From 8e6c8aa3b52e573a6db1f58b2ba9a9106a012963 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Apr 2019 22:45:09 +0200 Subject: isdn: gigaset: remove i4l support isdn4linux is getting removed, and the gigaset driver can still use the CAPI support, so this can all go away. Signed-off-by: Arnd Bergmann --- drivers/isdn/gigaset/Kconfig | 9 - drivers/isdn/gigaset/Makefile | 10 +- drivers/isdn/gigaset/i4l.c | 695 ------------------------------------------ 3 files changed, 7 insertions(+), 707 deletions(-) delete mode 100644 drivers/isdn/gigaset/i4l.c (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index fe41e9cfb672..c593105b3600 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig @@ -30,15 +30,6 @@ config GIGASET_CAPI Say N to build the old native ISDN4Linux variant. If unsure, say Y. -config GIGASET_I4L - bool - depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m') - default !GIGASET_CAPI - -config GIGASET_DUMMYLL - bool - default !GIGASET_CAPI&&!GIGASET_I4L - config GIGASET_BASE tristate "Gigaset base station support" depends on USB diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile index ac45a2739f56..9c010891dcd7 100644 --- a/drivers/isdn/gigaset/Makefile +++ b/drivers/isdn/gigaset/Makefile @@ -1,8 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o -gigaset-$(CONFIG_GIGASET_CAPI) += capi.o -gigaset-$(CONFIG_GIGASET_I4L) += i4l.o -gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o + +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 diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c deleted file mode 100644 index b5b389e95edd..000000000000 --- a/drivers/isdn/gigaset/i4l.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp , - * Tilman Schmidt . - * - * ===================================================================== - * 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 -#include - -#define SBUFSIZE 4096 /* sk_buff payload size */ -#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ -#define HW_HDR_LEN 2 /* Header size used to store ack info */ -#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */ - -/* == Handling of I4L IO =====================================================*/ - -/* writebuf_from_LL - * called by LL to transmit data on an open channel - * inserts the buffer data into the send queue and starts the transmission - * Note that this operation must not sleep! - * When the buffer is processed completely, gigaset_skb_sent() should be called. - * parameters: - * driverID driver ID as assigned by LL - * channel channel number - * ack if != 0 LL wants to be notified on completion via - * statcallb(ISDN_STAT_BSENT) - * skb skb containing data to send - * return value: - * number of accepted bytes - * 0 if temporarily unable to accept data (out of buffer space) - * <0 on error (eg. -EINVAL) - */ -static int writebuf_from_LL(int driverID, int channel, int ack, - struct sk_buff *skb) -{ - struct cardstate *cs = gigaset_get_cs_by_id(driverID); - struct bc_state *bcs; - unsigned char *ack_header; - unsigned len; - - if (!cs) { - pr_err("%s: invalid driver ID (%d)\n", __func__, driverID); - return -ENODEV; - } - if (channel < 0 || channel >= cs->channels) { - dev_err(cs->dev, "%s: invalid channel ID (%d)\n", - __func__, channel); - return -ENODEV; - } - bcs = &cs->bcs[channel]; - - /* can only handle linear sk_buffs */ - if (skb_linearize(skb) < 0) { - dev_err(cs->dev, "%s: skb_linearize failed\n", __func__); - return -ENOMEM; - } - len = skb->len; - - gig_dbg(DEBUG_LLDATA, - "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)", - driverID, channel, ack, len); - - if (!len) { - if (ack) - dev_notice(cs->dev, "%s: not ACKing empty packet\n", - __func__); - return 0; - } - if (len > MAX_BUF_SIZE) { - dev_err(cs->dev, "%s: packet too large (%d bytes)\n", - __func__, len); - return -EINVAL; - } - - /* set up acknowledgement header */ - if (skb_headroom(skb) < HW_HDR_LEN) { - /* should never happen */ - dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__); - return -ENOMEM; - } - skb_set_mac_header(skb, -HW_HDR_LEN); - skb->mac_len = HW_HDR_LEN; - ack_header = skb_mac_header(skb); - if (ack) { - ack_header[0] = len & 0xff; - ack_header[1] = len >> 8; - } else { - ack_header[0] = ack_header[1] = 0; - } - gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x", - len, ack, ack_header[0], ack_header[1]); - - /* pass to device-specific module */ - return cs->ops->send_skb(bcs, skb); -} - -/** - * gigaset_skb_sent() - acknowledge sending an skb - * @bcs: B channel descriptor structure. - * @skb: sent data. - * - * Called by hardware module {bas,ser,usb}_gigaset when the data in a - * skb has been successfully sent, for signalling completion to the LL. - */ -void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) -{ - isdn_if *iif = bcs->cs->iif; - unsigned char *ack_header = skb_mac_header(skb); - unsigned len; - isdn_ctrl response; - - ++bcs->trans_up; - - if (skb->len) - dev_warn(bcs->cs->dev, "%s: skb->len==%d\n", - __func__, skb->len); - - len = ack_header[0] + ((unsigned) ack_header[1] << 8); - if (len) { - gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)", - bcs->cs->myid, bcs->channel, len); - - response.driver = bcs->cs->myid; - response.command = ISDN_STAT_BSENT; - response.arg = bcs->channel; - response.parm.length = len; - iif->statcallb(&response); - } -} -EXPORT_SYMBOL_GPL(gigaset_skb_sent); - -/** - * gigaset_skb_rcvd() - pass received skb to LL - * @bcs: B channel descriptor structure. - * @skb: received data. - * - * Called by hardware module {bas,ser,usb}_gigaset when user data has - * been successfully received, for passing to the LL. - * Warning: skb must not be accessed anymore! - */ -void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) -{ - isdn_if *iif = bcs->cs->iif; - - iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb); - bcs->trans_down++; -} -EXPORT_SYMBOL_GPL(gigaset_skb_rcvd); - -/** - * gigaset_isdn_rcv_err() - signal receive error - * @bcs: B channel descriptor structure. - * - * Called by hardware module {bas,ser,usb}_gigaset when a receive error - * has occurred, for signalling to the LL. - */ -void gigaset_isdn_rcv_err(struct bc_state *bcs) -{ - isdn_if *iif = bcs->cs->iif; - isdn_ctrl response; - - /* if currently ignoring packets, just count down */ - if (bcs->ignore) { - bcs->ignore--; - return; - } - - /* update statistics */ - bcs->corrupted++; - - /* error -> LL */ - gig_dbg(DEBUG_CMD, "sending L1ERR"); - response.driver = bcs->cs->myid; - response.command = ISDN_STAT_L1ERR; - response.arg = bcs->channel; - response.parm.errcode = ISDN_STAT_L1ERR_RECV; - iif->statcallb(&response); -} -EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err); - -/* This function will be called by LL to send commands - * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL, - * so don't put too much effort into it. - */ -static int command_from_LL(isdn_ctrl *cntrl) -{ - struct cardstate *cs; - struct bc_state *bcs; - int retval = 0; - char **commands; - int ch; - int i; - size_t l; - - gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx", - cntrl->driver, cntrl->command, cntrl->arg); - - cs = gigaset_get_cs_by_id(cntrl->driver); - if (cs == NULL) { - pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver); - return -ENODEV; - } - ch = cntrl->arg & 0xff; - - switch (cntrl->command) { - case ISDN_CMD_IOCTL: - dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n"); - return -EINVAL; - - case ISDN_CMD_DIAL: - gig_dbg(DEBUG_CMD, - "ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)", - cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn, - cntrl->parm.setup.si1, cntrl->parm.setup.si2); - - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_DIAL: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - if (gigaset_get_channel(bcs) < 0) { - dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); - return -EBUSY; - } - switch (bcs->proto2) { - case L2_HDLC: - bcs->rx_bufsize = SBUFSIZE; - break; - default: /* assume transparent */ - bcs->rx_bufsize = TRANSBUFSIZE; - } - dev_kfree_skb(bcs->rx_skb); - gigaset_new_rx_skb(bcs); - - commands = kcalloc(AT_NUM, sizeof(*commands), GFP_ATOMIC); - if (!commands) { - gigaset_free_channel(bcs); - dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n"); - return -ENOMEM; - } - - l = 3 + strlen(cntrl->parm.setup.phone); - commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC); - if (!commands[AT_DIAL]) - goto oom; - if (cntrl->parm.setup.phone[0] == '*' && - cntrl->parm.setup.phone[1] == '*') { - /* internal call: translate ** prefix to CTP value */ - commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC); - if (!commands[AT_TYPE]) - goto oom; - snprintf(commands[AT_DIAL], l, - "D%s\r", cntrl->parm.setup.phone + 2); - } else { - commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC); - if (!commands[AT_TYPE]) - goto oom; - snprintf(commands[AT_DIAL], l, - "D%s\r", cntrl->parm.setup.phone); - } - - l = strlen(cntrl->parm.setup.eazmsn); - if (l) { - l += 8; - commands[AT_MSN] = kmalloc(l, GFP_ATOMIC); - if (!commands[AT_MSN]) - goto oom; - snprintf(commands[AT_MSN], l, "^SMSN=%s\r", - cntrl->parm.setup.eazmsn); - } - - switch (cntrl->parm.setup.si1) { - case 1: /* audio */ - /* BC = 9090A3: 3.1 kHz audio, A-law */ - commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC); - if (!commands[AT_BC]) - goto oom; - break; - case 7: /* data */ - default: /* hope the app knows what it is doing */ - /* BC = 8890: unrestricted digital information */ - commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC); - if (!commands[AT_BC]) - goto oom; - } - /* ToDo: other si1 values, inspect si2, set HLC/LLC */ - - commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC); - if (!commands[AT_PROTO]) - goto oom; - snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2); - - commands[AT_ISO] = kmalloc(9, GFP_ATOMIC); - if (!commands[AT_ISO]) - goto oom; - snprintf(commands[AT_ISO], 9, "^SISO=%u\r", - (unsigned) bcs->channel + 1); - - if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands, - bcs->at_state.seq_index, NULL)) { - for (i = 0; i < AT_NUM; ++i) - kfree(commands[i]); - kfree(commands); - gigaset_free_channel(bcs); - return -ENOMEM; - } - gigaset_schedule_event(cs); - break; - case ISDN_CMD_ACCEPTD: - gig_dbg(DEBUG_CMD, "ISDN_CMD_ACCEPTD"); - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - switch (bcs->proto2) { - case L2_HDLC: - bcs->rx_bufsize = SBUFSIZE; - break; - default: /* assume transparent */ - bcs->rx_bufsize = TRANSBUFSIZE; - } - dev_kfree_skb(bcs->rx_skb); - gigaset_new_rx_skb(bcs); - if (!gigaset_add_event(cs, &bcs->at_state, - EV_ACCEPT, NULL, 0, NULL)) - return -ENOMEM; - gigaset_schedule_event(cs); - - break; - case ISDN_CMD_HANGUP: - gig_dbg(DEBUG_CMD, "ISDN_CMD_HANGUP"); - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_HANGUP: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - if (!gigaset_add_event(cs, &bcs->at_state, - EV_HUP, NULL, 0, NULL)) - return -ENOMEM; - gigaset_schedule_event(cs); - - break; - case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ - dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n"); - break; - case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ - dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n", - cntrl->parm.num); - break; - case ISDN_CMD_SETL2: /* Set L2 to given protocol */ - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_SETL2: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - if (bcs->chstate & CHS_D_UP) { - dev_err(cs->dev, - "ISDN_CMD_SETL2: channel active (%d)\n", ch); - return -EINVAL; - } - switch (cntrl->arg >> 8) { - case ISDN_PROTO_L2_HDLC: - gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC"); - bcs->proto2 = L2_HDLC; - break; - case ISDN_PROTO_L2_TRANS: - gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE"); - bcs->proto2 = L2_VOICE; - break; - default: - dev_err(cs->dev, - "ISDN_CMD_SETL2: unsupported protocol (%lu)\n", - cntrl->arg >> 8); - return -EINVAL; - } - break; - case ISDN_CMD_SETL3: /* Set L3 to given protocol */ - gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL3"); - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_SETL3: invalid channel (%d)\n", ch); - return -EINVAL; - } - - if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) { - dev_err(cs->dev, - "ISDN_CMD_SETL3: unsupported protocol (%lu)\n", - cntrl->arg >> 8); - return -EINVAL; - } - - break; - - default: - gig_dbg(DEBUG_CMD, "unknown command %d from LL", - cntrl->command); - return -EINVAL; - } - - return retval; - -oom: - dev_err(bcs->cs->dev, "out of memory\n"); - for (i = 0; i < AT_NUM; ++i) - kfree(commands[i]); - kfree(commands); - gigaset_free_channel(bcs); - return -ENOMEM; -} - -static void gigaset_i4l_cmd(struct cardstate *cs, int cmd) -{ - isdn_if *iif = cs->iif; - isdn_ctrl command; - - command.driver = cs->myid; - command.command = cmd; - command.arg = 0; - iif->statcallb(&command); -} - -static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd) -{ - isdn_if *iif = bcs->cs->iif; - isdn_ctrl command; - - command.driver = bcs->cs->myid; - command.command = cmd; - command.arg = bcs->channel; - iif->statcallb(&command); -} - -/** - * gigaset_isdn_icall() - signal incoming call - * @at_state: connection state structure. - * - * Called by main module to notify the LL that an incoming call has been - * received. @at_state contains the parameters of the call. - * - * Return value: call disposition (ICALL_*) - */ -int gigaset_isdn_icall(struct at_state_t *at_state) -{ - struct cardstate *cs = at_state->cs; - struct bc_state *bcs = at_state->bcs; - isdn_if *iif = cs->iif; - isdn_ctrl response; - int retval; - - /* fill ICALL structure */ - response.parm.setup.si1 = 0; /* default: unknown */ - response.parm.setup.si2 = 0; - response.parm.setup.screen = 0; - response.parm.setup.plan = 0; - if (!at_state->str_var[STR_ZBC]) { - /* no BC (internal call): assume speech, A-law */ - response.parm.setup.si1 = 1; - } else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) { - /* unrestricted digital information */ - response.parm.setup.si1 = 7; - } else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) { - /* speech, A-law */ - response.parm.setup.si1 = 1; - } else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) { - /* 3,1 kHz audio, A-law */ - response.parm.setup.si1 = 1; - response.parm.setup.si2 = 2; - } else { - dev_warn(cs->dev, "RING ignored - unsupported BC %s\n", - at_state->str_var[STR_ZBC]); - return ICALL_IGNORE; - } - if (at_state->str_var[STR_NMBR]) { - strlcpy(response.parm.setup.phone, at_state->str_var[STR_NMBR], - sizeof response.parm.setup.phone); - } else - response.parm.setup.phone[0] = 0; - if (at_state->str_var[STR_ZCPN]) { - strlcpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN], - sizeof response.parm.setup.eazmsn); - } else - response.parm.setup.eazmsn[0] = 0; - - if (!bcs) { - dev_notice(cs->dev, "no channel for incoming call\n"); - response.command = ISDN_STAT_ICALLW; - response.arg = 0; - } else { - gig_dbg(DEBUG_CMD, "Sending ICALL"); - response.command = ISDN_STAT_ICALL; - response.arg = bcs->channel; - } - response.driver = cs->myid; - retval = iif->statcallb(&response); - gig_dbg(DEBUG_CMD, "Response: %d", retval); - switch (retval) { - case 0: /* no takers */ - return ICALL_IGNORE; - case 1: /* alerting */ - bcs->chstate |= CHS_NOTIFY_LL; - return ICALL_ACCEPT; - case 2: /* reject */ - return ICALL_REJECT; - case 3: /* incomplete */ - dev_warn(cs->dev, - "LL requested unsupported feature: Incomplete Number\n"); - return ICALL_IGNORE; - case 4: /* proceeding */ - /* Gigaset will send ALERTING anyway. - * There doesn't seem to be a way to avoid this. - */ - return ICALL_ACCEPT; - case 5: /* deflect */ - dev_warn(cs->dev, - "LL requested unsupported feature: Call Deflection\n"); - return ICALL_IGNORE; - default: - dev_err(cs->dev, "LL error %d on ICALL\n", retval); - return ICALL_IGNORE; - } -} - -/** - * gigaset_isdn_connD() - signal D channel connect - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the D channel connection has - * been established. - */ -void gigaset_isdn_connD(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending DCONN"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); -} - -/** - * gigaset_isdn_hupD() - signal D channel hangup - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the D channel connection has - * been shut down. - */ -void gigaset_isdn_hupD(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending DHUP"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP); -} - -/** - * gigaset_isdn_connB() - signal B channel connect - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the B channel connection has - * been established. - */ -void gigaset_isdn_connB(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending BCONN"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); -} - -/** - * gigaset_isdn_hupB() - signal B channel hangup - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the B channel connection has - * been shut down. - */ -void gigaset_isdn_hupB(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending BHUP"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP); -} - -/** - * gigaset_isdn_start() - signal device availability - * @cs: device descriptor structure. - * - * Called by main module to notify the LL that the device is available for - * use. - */ -void gigaset_isdn_start(struct cardstate *cs) -{ - gig_dbg(DEBUG_CMD, "sending RUN"); - gigaset_i4l_cmd(cs, ISDN_STAT_RUN); -} - -/** - * gigaset_isdn_stop() - signal device unavailability - * @cs: device descriptor structure. - * - * Called by main module to notify the LL that the device is no longer - * available for use. - */ -void gigaset_isdn_stop(struct cardstate *cs) -{ - gig_dbg(DEBUG_CMD, "sending STOP"); - gigaset_i4l_cmd(cs, ISDN_STAT_STOP); -} - -/** - * gigaset_isdn_regdev() - register to LL - * @cs: device descriptor structure. - * @isdnid: device name. - * - * Return value: 0 on success, error code < 0 on failure - */ -int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) -{ - isdn_if *iif; - - iif = kmalloc(sizeof *iif, GFP_KERNEL); - if (!iif) { - pr_err("out of memory\n"); - return -ENOMEM; - } - - if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) - >= sizeof iif->id) { - pr_err("ID too long: %s\n", isdnid); - kfree(iif); - return -EINVAL; - } - - iif->owner = THIS_MODULE; - iif->channels = cs->channels; - iif->maxbufsize = MAX_BUF_SIZE; - iif->features = ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_EURO; - iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */ - iif->command = command_from_LL; - iif->writebuf_skb = writebuf_from_LL; - iif->writecmd = NULL; /* Don't support isdnctrl */ - iif->readstat = NULL; /* Don't support isdnctrl */ - iif->rcvcallb_skb = NULL; /* Will be set by LL */ - iif->statcallb = NULL; /* Will be set by LL */ - - if (!register_isdn(iif)) { - pr_err("register_isdn failed\n"); - kfree(iif); - return -EINVAL; - } - - cs->iif = iif; - cs->myid = iif->channels; /* Set my device id */ - cs->hw_hdr_len = HW_HDR_LEN; - return 0; -} - -/** - * gigaset_isdn_unregdev() - unregister device from LL - * @cs: device descriptor structure. - */ -void gigaset_isdn_unregdev(struct cardstate *cs) -{ - gig_dbg(DEBUG_CMD, "sending UNLOAD"); - gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD); - kfree(cs->iif); - cs->iif = NULL; -} - -/** - * gigaset_isdn_regdrv() - register driver to LL - */ -void gigaset_isdn_regdrv(void) -{ - pr_info("ISDN4Linux interface\n"); - /* nothing to do */ -} - -/** - * gigaset_isdn_unregdrv() - unregister driver from LL - */ -void gigaset_isdn_unregdrv(void) -{ - /* nothing to do */ -} -- cgit v1.2.3 From 85993b8c9786fb24975dbcabebb1c75790d4fb6a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Apr 2019 22:47:35 +0200 Subject: isdn: remove hisax driver With the decline of ISDN, this seems to have become almost completely obsolete, and even in the past years before that, almost all remaining users appear to have used mISDN instead. Birger Harzenetter noted that he is still using i4l/hisax to take advantage of the 'divert' driver for call diversion, but otherwise uses mISDN on the same hardware. This is a rare edge case as far as I can tell, but we are still breaking an actively used work flow (see https://xkcd.com/1172/). We debated moving i4l/hisax to staging as an intermediate step, but as he is not likely to change the setup, and that would just delay breaking this use case. The alternatives here are to stay on stable kernels < 5.2, to create an external driver repository for isdn4linux, or to add divert functionality to mISDN. Cc: Birger Harzenetter Signed-off-by: Arnd Bergmann --- Documentation/isdn/HiSax.cert | 96 -- Documentation/isdn/README.HiSax | 659 ------- drivers/isdn/Makefile | 1 - drivers/isdn/hisax/Kconfig | 423 ----- drivers/isdn/hisax/Makefile | 60 - drivers/isdn/hisax/amd7930_fn.c | 794 --------- drivers/isdn/hisax/amd7930_fn.h | 37 - drivers/isdn/hisax/arcofi.c | 131 -- drivers/isdn/hisax/arcofi.h | 27 - drivers/isdn/hisax/asuscom.c | 423 ----- drivers/isdn/hisax/avm_a1.c | 307 ---- drivers/isdn/hisax/avm_a1p.c | 267 --- drivers/isdn/hisax/avm_pci.c | 904 ---------- drivers/isdn/hisax/avma1_cs.c | 162 -- drivers/isdn/hisax/bkm_a4t.c | 358 ---- drivers/isdn/hisax/bkm_a8.c | 433 ----- drivers/isdn/hisax/bkm_ax.h | 119 -- drivers/isdn/hisax/callc.c | 1792 ------------------- drivers/isdn/hisax/config.c | 1993 --------------------- drivers/isdn/hisax/diva.c | 1282 -------------- drivers/isdn/hisax/elsa.c | 1245 -------------- drivers/isdn/hisax/elsa_cs.c | 218 --- drivers/isdn/hisax/elsa_ser.c | 659 ------- drivers/isdn/hisax/enternow_pci.c | 420 ----- drivers/isdn/hisax/fsm.c | 161 -- drivers/isdn/hisax/fsm.h | 61 - drivers/isdn/hisax/gazel.c | 691 -------- drivers/isdn/hisax/hfc4s8s_l1.c | 1584 ----------------- drivers/isdn/hisax/hfc4s8s_l1.h | 89 - drivers/isdn/hisax/hfc_2bds0.c | 1078 ------------ drivers/isdn/hisax/hfc_2bds0.h | 128 -- drivers/isdn/hisax/hfc_2bs0.c | 591 ------- drivers/isdn/hisax/hfc_2bs0.h | 60 - drivers/isdn/hisax/hfc_pci.c | 1755 ------------------- drivers/isdn/hisax/hfc_pci.h | 235 --- drivers/isdn/hisax/hfc_sx.c | 1517 ---------------- drivers/isdn/hisax/hfc_sx.h | 196 --- drivers/isdn/hisax/hfc_usb.c | 1608 ----------------- drivers/isdn/hisax/hfc_usb.h | 208 --- drivers/isdn/hisax/hfcscard.c | 261 --- drivers/isdn/hisax/hisax.h | 1352 --------------- drivers/isdn/hisax/hisax_cfg.h | 66 - drivers/isdn/hisax/hisax_debug.h | 80 - drivers/isdn/hisax/hisax_fcpcipnp.c | 1024 ----------- drivers/isdn/hisax/hisax_fcpcipnp.h | 58 - drivers/isdn/hisax/hisax_if.h | 66 - drivers/isdn/hisax/hisax_isac.c | 895 ---------- drivers/isdn/hisax/hisax_isac.h | 46 - drivers/isdn/hisax/hscx.c | 277 --- drivers/isdn/hisax/hscx.h | 41 - drivers/isdn/hisax/hscx_irq.c | 294 ---- drivers/isdn/hisax/icc.c | 680 -------- drivers/isdn/hisax/icc.h | 72 - drivers/isdn/hisax/ipac.h | 29 - drivers/isdn/hisax/ipacx.c | 913 ---------- drivers/isdn/hisax/ipacx.h | 162 -- drivers/isdn/hisax/isac.c | 681 -------- drivers/isdn/hisax/isac.h | 70 - drivers/isdn/hisax/isar.c | 1910 --------------------- drivers/isdn/hisax/isar.h | 222 --- drivers/isdn/hisax/isdnl1.c | 930 ---------- drivers/isdn/hisax/isdnl1.h | 32 - drivers/isdn/hisax/isdnl2.c | 1839 -------------------- drivers/isdn/hisax/isdnl2.h | 25 - drivers/isdn/hisax/isdnl3.c | 594 ------- drivers/isdn/hisax/isdnl3.h | 42 - drivers/isdn/hisax/isurf.c | 305 ---- drivers/isdn/hisax/ix1_micro.c | 316 ---- drivers/isdn/hisax/jade.c | 305 ---- drivers/isdn/hisax/jade.h | 134 -- drivers/isdn/hisax/jade_irq.c | 238 --- drivers/isdn/hisax/l3_1tr6.c | 932 ---------- drivers/isdn/hisax/l3_1tr6.h | 164 -- drivers/isdn/hisax/l3dss1.c | 3227 ----------------------------------- drivers/isdn/hisax/l3dss1.h | 124 -- drivers/isdn/hisax/l3ni1.c | 3182 ---------------------------------- drivers/isdn/hisax/l3ni1.h | 136 -- drivers/isdn/hisax/lmgr.c | 50 - drivers/isdn/hisax/mic.c | 235 --- drivers/isdn/hisax/netjet.c | 985 ----------- drivers/isdn/hisax/netjet.h | 69 - drivers/isdn/hisax/niccy.c | 380 ----- drivers/isdn/hisax/nj_s.c | 294 ---- drivers/isdn/hisax/nj_u.c | 258 --- drivers/isdn/hisax/q931.c | 1513 ---------------- drivers/isdn/hisax/s0box.c | 260 --- drivers/isdn/hisax/saphir.c | 296 ---- drivers/isdn/hisax/sedlbauer.c | 873 ---------- drivers/isdn/hisax/sedlbauer_cs.c | 209 --- drivers/isdn/hisax/sportster.c | 267 --- drivers/isdn/hisax/st5481.h | 529 ------ drivers/isdn/hisax/st5481_b.c | 380 ----- drivers/isdn/hisax/st5481_d.c | 780 --------- drivers/isdn/hisax/st5481_init.c | 221 --- drivers/isdn/hisax/st5481_usb.c | 659 ------- drivers/isdn/hisax/tei.c | 465 ----- drivers/isdn/hisax/teleint.c | 334 ---- drivers/isdn/hisax/teles0.c | 364 ---- drivers/isdn/hisax/teles3.c | 498 ------ drivers/isdn/hisax/teles_cs.c | 201 --- drivers/isdn/hisax/telespci.c | 349 ---- drivers/isdn/hisax/w6692.c | 1085 ------------ drivers/isdn/hisax/w6692.h | 184 -- drivers/isdn/i4l/Kconfig | 2 - 104 files changed, 56236 deletions(-) delete mode 100644 Documentation/isdn/HiSax.cert delete mode 100644 Documentation/isdn/README.HiSax delete mode 100644 drivers/isdn/hisax/Kconfig delete mode 100644 drivers/isdn/hisax/Makefile delete mode 100644 drivers/isdn/hisax/amd7930_fn.c delete mode 100644 drivers/isdn/hisax/amd7930_fn.h delete mode 100644 drivers/isdn/hisax/arcofi.c delete mode 100644 drivers/isdn/hisax/arcofi.h delete mode 100644 drivers/isdn/hisax/asuscom.c delete mode 100644 drivers/isdn/hisax/avm_a1.c delete mode 100644 drivers/isdn/hisax/avm_a1p.c delete mode 100644 drivers/isdn/hisax/avm_pci.c delete mode 100644 drivers/isdn/hisax/avma1_cs.c delete mode 100644 drivers/isdn/hisax/bkm_a4t.c delete mode 100644 drivers/isdn/hisax/bkm_a8.c delete mode 100644 drivers/isdn/hisax/bkm_ax.h delete mode 100644 drivers/isdn/hisax/callc.c delete mode 100644 drivers/isdn/hisax/config.c delete mode 100644 drivers/isdn/hisax/diva.c delete mode 100644 drivers/isdn/hisax/elsa.c delete mode 100644 drivers/isdn/hisax/elsa_cs.c delete mode 100644 drivers/isdn/hisax/elsa_ser.c delete mode 100644 drivers/isdn/hisax/enternow_pci.c delete mode 100644 drivers/isdn/hisax/fsm.c delete mode 100644 drivers/isdn/hisax/fsm.h delete mode 100644 drivers/isdn/hisax/gazel.c delete mode 100644 drivers/isdn/hisax/hfc4s8s_l1.c delete mode 100644 drivers/isdn/hisax/hfc4s8s_l1.h delete mode 100644 drivers/isdn/hisax/hfc_2bds0.c delete mode 100644 drivers/isdn/hisax/hfc_2bds0.h delete mode 100644 drivers/isdn/hisax/hfc_2bs0.c delete mode 100644 drivers/isdn/hisax/hfc_2bs0.h delete mode 100644 drivers/isdn/hisax/hfc_pci.c delete mode 100644 drivers/isdn/hisax/hfc_pci.h delete mode 100644 drivers/isdn/hisax/hfc_sx.c delete mode 100644 drivers/isdn/hisax/hfc_sx.h delete mode 100644 drivers/isdn/hisax/hfc_usb.c delete mode 100644 drivers/isdn/hisax/hfc_usb.h delete mode 100644 drivers/isdn/hisax/hfcscard.c delete mode 100644 drivers/isdn/hisax/hisax.h delete mode 100644 drivers/isdn/hisax/hisax_cfg.h delete mode 100644 drivers/isdn/hisax/hisax_debug.h delete mode 100644 drivers/isdn/hisax/hisax_fcpcipnp.c delete mode 100644 drivers/isdn/hisax/hisax_fcpcipnp.h delete mode 100644 drivers/isdn/hisax/hisax_if.h delete mode 100644 drivers/isdn/hisax/hisax_isac.c delete mode 100644 drivers/isdn/hisax/hisax_isac.h delete mode 100644 drivers/isdn/hisax/hscx.c delete mode 100644 drivers/isdn/hisax/hscx.h delete mode 100644 drivers/isdn/hisax/hscx_irq.c delete mode 100644 drivers/isdn/hisax/icc.c delete mode 100644 drivers/isdn/hisax/icc.h delete mode 100644 drivers/isdn/hisax/ipac.h delete mode 100644 drivers/isdn/hisax/ipacx.c delete mode 100644 drivers/isdn/hisax/ipacx.h delete mode 100644 drivers/isdn/hisax/isac.c delete mode 100644 drivers/isdn/hisax/isac.h delete mode 100644 drivers/isdn/hisax/isar.c delete mode 100644 drivers/isdn/hisax/isar.h delete mode 100644 drivers/isdn/hisax/isdnl1.c delete mode 100644 drivers/isdn/hisax/isdnl1.h delete mode 100644 drivers/isdn/hisax/isdnl2.c delete mode 100644 drivers/isdn/hisax/isdnl2.h delete mode 100644 drivers/isdn/hisax/isdnl3.c delete mode 100644 drivers/isdn/hisax/isdnl3.h delete mode 100644 drivers/isdn/hisax/isurf.c delete mode 100644 drivers/isdn/hisax/ix1_micro.c delete mode 100644 drivers/isdn/hisax/jade.c delete mode 100644 drivers/isdn/hisax/jade.h delete mode 100644 drivers/isdn/hisax/jade_irq.c delete mode 100644 drivers/isdn/hisax/l3_1tr6.c delete mode 100644 drivers/isdn/hisax/l3_1tr6.h delete mode 100644 drivers/isdn/hisax/l3dss1.c delete mode 100644 drivers/isdn/hisax/l3dss1.h delete mode 100644 drivers/isdn/hisax/l3ni1.c delete mode 100644 drivers/isdn/hisax/l3ni1.h delete mode 100644 drivers/isdn/hisax/lmgr.c delete mode 100644 drivers/isdn/hisax/mic.c delete mode 100644 drivers/isdn/hisax/netjet.c delete mode 100644 drivers/isdn/hisax/netjet.h delete mode 100644 drivers/isdn/hisax/niccy.c delete mode 100644 drivers/isdn/hisax/nj_s.c delete mode 100644 drivers/isdn/hisax/nj_u.c delete mode 100644 drivers/isdn/hisax/q931.c delete mode 100644 drivers/isdn/hisax/s0box.c delete mode 100644 drivers/isdn/hisax/saphir.c delete mode 100644 drivers/isdn/hisax/sedlbauer.c delete mode 100644 drivers/isdn/hisax/sedlbauer_cs.c delete mode 100644 drivers/isdn/hisax/sportster.c delete mode 100644 drivers/isdn/hisax/st5481.h delete mode 100644 drivers/isdn/hisax/st5481_b.c delete mode 100644 drivers/isdn/hisax/st5481_d.c delete mode 100644 drivers/isdn/hisax/st5481_init.c delete mode 100644 drivers/isdn/hisax/st5481_usb.c delete mode 100644 drivers/isdn/hisax/tei.c delete mode 100644 drivers/isdn/hisax/teleint.c delete mode 100644 drivers/isdn/hisax/teles0.c delete mode 100644 drivers/isdn/hisax/teles3.c delete mode 100644 drivers/isdn/hisax/teles_cs.c delete mode 100644 drivers/isdn/hisax/telespci.c delete mode 100644 drivers/isdn/hisax/w6692.c delete mode 100644 drivers/isdn/hisax/w6692.h (limited to 'drivers/isdn') diff --git a/Documentation/isdn/HiSax.cert b/Documentation/isdn/HiSax.cert deleted file mode 100644 index f2a6fcb8efee..000000000000 --- a/Documentation/isdn/HiSax.cert +++ /dev/null @@ -1,96 +0,0 @@ ------BEGIN PGP SIGNED MESSAGE----- - -First: - - HiSax 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. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -However, if you wish to modify the HiSax sources, please note the following: - -HiSax has passed the ITU approval test suite with ELSA Quickstep ISDN cards -and Eicon Technology Diva 2.01 PCI card. -The certification is only valid for the combination of the tested software -version and the tested hardware. Any changes to the HiSax source code may -therefore affect the certification. - -Additional ITU approval tests have been carried out for all generic cards -using Colognechip single chip solutions HFC-S PCI A for PCI cards as well -as HFC-S USB based USB ISDN ta adapters. -These tests included all layers 1-3 and as well all functional tests for -the layer 1. Because all hardware based on these chips are complete ISDN -solutions in one chip all cards and USB-TAs using these chips are to be -regarded as approved for those tests. Some additional electrical tests -of the layer 1 which are independent of the driver and related to a -special hardware used will be regarded as approved if at least one -solution has been tested including those electrical tests. So if cards -or tas have been completely approved for any other os, the approval -for those electrical tests is valid for linux, too. -Please send any questions regarding this drivers or approval abouts to -werner@isdn-development.de -Additional information and the type approval documents will be found -shortly on the Colognechip website www.colognechip.com - -If you change the main files of the HiSax ISDN stack, the certification will -become invalid. Because in most countries it is illegal to connect -unapproved ISDN equipment to the public network, I have to guarantee that -changes in HiSax do not affect the certification. - -In order to make a valid certification apparent to the user, I have built in -some validation checks that are made during the make process. The HiSax main -files are protected by md5 checksums and the md5sum file is pgp signed by -myself: - -KeyID 1024/FF992F6D 1997/01/16 Karsten Keil -Key fingerprint = 92 6B F7 58 EE 86 28 C8 C4 1A E6 DC 39 89 F2 AA - -Only if the checksums are OK, and the signature of the file -"drivers/isdn/hisax/md5sums.asc" match, is the certification valid; a -message confirming this is then displayed during the hisax init process. - -The affected files are: - -drivers/isdn/hisax/isac.c -drivers/isdn/hisax/isdnl1.c -drivers/isdn/hisax/isdnl2.c -drivers/isdn/hisax/isdnl3.c -drivers/isdn/hisax/tei.c -drivers/isdn/hisax/callc.c -drivers/isdn/hisax/l3dss1.c -drivers/isdn/hisax/l3_1tr6.c -drivers/isdn/hisax/cert.c -drivers/isdn/hisax/elsa.c -drivers/isdn/hisax/diva.c -drivers/isdn/hisax/hfc_pci.c - -Please send any changes, bugfixes and patches to me rather than implementing -them directly into the HiSax sources. - -This does not reduce your rights granted by the GNU General Public License. -If you wish to change the sources, go ahead; but note that then the -certification is invalid even if you use one of the approved cards. - -Here are the certification registration numbers for ELSA Quickstep cards: -German D133361J CETECOM ICT Services GmbH 0682 -European D133362J CETECOM ICT Services GmbH 0682 - - -Karsten Keil -keil@isdn4linux.de - ------BEGIN PGP SIGNATURE----- -Version: 2.6.3i -Charset: noconv - -iQCVAwUBOFAwqTpxHvX/mS9tAQFI2QP9GLDK2iy/KBhwReE3F7LeO+tVhffTVZ3a -20q5/z/WcIg/pnH0uTkl2UgDXBFXYl45zJyDGNpAposIFmT+Edd14o7Vj1w/BBdn -Y+5rBmJf+gyBu61da5d6bv0lpymwRa/um+ri+ilYnZ/XPfg5JKhdjGSBCJuJAElM -d2jFbTrsMYw= -=LNf9 ------END PGP SIGNATURE----- diff --git a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax deleted file mode 100644 index b1a573cf4472..000000000000 --- a/Documentation/isdn/README.HiSax +++ /dev/null @@ -1,659 +0,0 @@ -HiSax is a Linux hardware-level driver for passive ISDN cards with Siemens -chipset (ISAC_S 2085/2086/2186, HSCX SAB 82525). It is based on the Teles -driver from Jan den Ouden. -It is meant to be used with isdn4linux, an ISDN link-level module for Linux -written by Fritz Elfert. - - 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. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - -Supported cards ---------------- - -Teles 8.0/16.0/16.3 and compatible ones -Teles 16.3c -Teles S0/PCMCIA -Teles PCI -Teles S0Box -Creatix S0Box -Creatix PnP S0 -Compaq ISDN S0 ISA card -AVM A1 (Fritz, Teledat 150) -AVM Fritz PCMCIA -AVM Fritz PnP -AVM Fritz PCI -ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8 -ELSA Quickstep 1000 -ELSA Quickstep 1000PCI -ELSA Quickstep 3000 (same settings as QS1000) -ELSA Quickstep 3000PCI -ELSA PCMCIA -ITK ix1-micro Rev.2 -Eicon Diva 2.0 ISA and PCI (S0 and U interface, no PRO version) -Eicon Diva 2.01 ISA and PCI -Eicon Diva 2.02 PCI -Eicon Diva Piccola -ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D) -Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter) -PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink) -HFC-2BS0 based cards (TeleInt SA1) -Sedlbauer Speed Card (Speed Win, Teledat 100, PCI, Fax+) -Sedlbauer Speed Star/Speed Star2 (PCMCIA) -Sedlbauer ISDN-Controller PC/104 -USR Sportster internal TA (compatible Stollmann tina-pp V3) -USR internal TA PCI -ith Kommunikationstechnik GmbH MIC 16 ISA card -Traverse Technologie NETjet PCI S0 card and NETspider U card -Ovislink ISDN sc100-p card (NETjet driver) -Dr. Neuhaus Niccy PnP/PCI -Siemens I-Surf 1.0 -Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom) -ACER P10 -HST Saphir -Berkom Telekom A4T -Scitel Quadro -Gazel ISDN cards -HFC-PCI based cards -Winbond W6692 based cards -HFC-S+, HFC-SP/PCMCIA cards -formula-n enternow -Gerdes Power ISDN - -Note: PCF, PCF-Pro: up to now, only the ISDN part is supported - PCC-8: not tested yet - Eicon.Diehl Diva U interface not tested - -If you know other passive cards with the Siemens chipset, please let me know. -You can combine any card, if there is no conflict between the resources -(io, mem, irq). - - -Configuring the driver ----------------------- - -The HiSax driver can either be built directly into the kernel or as a module. -It can be configured using the command line feature while loading the kernel -with LILO or LOADLIN or, if built as a module, using insmod/modprobe with -parameters. -There is also some config needed before you compile the kernel and/or -modules. It is included in the normal "make [menu]config" target at the -kernel. Don't forget it, especially to select the right D-channel protocol. - -Please note: In older versions of the HiSax driver, all PnP cards -needed to be configured with isapnp and worked only with the HiSax -driver used as a module. - -In the current version, HiSax will automatically use the in-kernel -ISAPnP support, provided you selected it during kernel configuration -(CONFIG_ISAPNP), if you don't give the io=, irq= command line parameters. - -The affected card types are: 4,7,12,14,19,27-30 - -a) when built as a module -------------------------- - -insmod/modprobe hisax.o \ - io=iobase irq=IRQ mem=membase type=card_type \ - protocol=D_channel_protocol id=idstring - -or, if several cards are installed: - -insmod/modprobe hisax.o \ - io=iobase1,iobase2,... irq=IRQ1,IRQ2,... mem=membase1,membase2,... \ - type=card_type1,card_type2,... \ - protocol=D_channel_protocol1,D_channel_protocol2,... \ - id=idstring1%idstring2 ... - -where "iobaseN" represents the I/O base address of the Nth card, "membaseN" -the memory base address of the Nth card, etc. - -The reason for the delimiter "%" being used in the idstrings is that "," -won't work with the current modules package. - -The parameters may be specified in any order. For example, the "io" -parameter may precede the "irq" parameter, or vice versa. If several -cards are installed, the ordering within the comma separated parameter -lists must of course be consistent. - -Only parameters applicable to the card type need to be specified. For -example, the Teles 16.3 card is not memory-mapped, so the "mem" -parameter may be omitted for this card. Sometimes it may be necessary -to specify a dummy parameter, however. This is the case when there is -a card of a different type later in the list that needs a parameter -which the preceding card does not. For instance, if a Teles 16.0 card -is listed after a Teles 16.3 card, a dummy memory base parameter of 0 -must be specified for the 16.3. Instead of a dummy value, the parameter -can also be skipped by simply omitting the value. For example: -mem=,0xd0000. See example 6 below. - -The parameter for the D-Channel protocol may be omitted if you selected the -correct one during kernel config. Valid values are "1" for German 1TR6, -"2" for EDSS1 (Euro ISDN), "3" for leased lines (no D-Channel) and "4" -for US NI1. -With US NI1 you have to include your SPID into the MSN setting in the form -: for example (your phonenumber is 1234 your SPID 5678): -AT&E1234:5678 on ttyI interfaces -isdnctrl eaz ippp0 1234:5678 on network devices - -The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying -the I/O addresses of the ISAC and HSCX chips, respectively. - -Card types: - - Type Required parameters (in addition to type and protocol) - - 1 Teles 16.0 irq, mem, io - 2 Teles 8.0 irq, mem - 3 Teles 16.3 (non PnP) irq, io - 4 Creatix/Teles PnP irq, io0 (ISAC), io1 (HSCX) - 5 AVM A1 (Fritz) irq, io - 6 ELSA PCC/PCF cards io or nothing for autodetect (the iobase is - required only if you have more than one ELSA - card in your PC) - 7 ELSA Quickstep 1000 irq, io (from isapnp setup) - 8 Teles 16.3 PCMCIA irq, io - 9 ITK ix1-micro Rev.2 irq, io - 10 ELSA PCMCIA irq, io (set with card manager) - 11 Eicon.Diehl Diva ISA PnP irq, io - 11 Eicon.Diehl Diva PCI no parameter - 12 ASUS COM ISDNLink irq, io (from isapnp setup) - 13 HFC-2BS0 based cards irq, io - 14 Teles 16.3c PnP irq, io - 15 Sedlbauer Speed Card irq, io - 15 Sedlbauer PC/104 irq, io - 15 Sedlbauer Speed PCI no parameter - 16 USR Sportster internal irq, io - 17 MIC card irq, io - 18 ELSA Quickstep 1000PCI no parameter - 19 Compaq ISDN S0 ISA card irq, io0, io1, io (from isapnp setup io=IO2) - 20 NETjet PCI card no parameter - 21 Teles PCI no parameter - 22 Sedlbauer Speed Star (PCMCIA) irq, io (set with card manager) - 24 Dr. Neuhaus Niccy PnP irq, io0, io1 (from isapnp setup) - 24 Dr. Neuhaus Niccy PCI no parameter - 25 Teles S0Box irq, io (of the used lpt port) - 26 AVM A1 PCMCIA (Fritz!) irq, io (set with card manager) - 27 AVM PnP (Fritz!PnP) irq, io (from isapnp setup) - 27 AVM PCI (Fritz!PCI) no parameter - 28 Sedlbauer Speed Fax+ irq, io (from isapnp setup) - 29 Siemens I-Surf 1.0 irq, io, memory (from isapnp setup) - 30 ACER P10 irq, io (from isapnp setup) - 31 HST Saphir irq, io - 32 Telekom A4T none - 33 Scitel Quadro subcontroller (4*S0, subctrl 1...4) - 34 Gazel ISDN cards (ISA) irq,io - 34 Gazel ISDN cards (PCI) none - 35 HFC 2BDS0 PCI none - 36 W6692 based PCI cards none - 37 HFC 2BDS0 S+, SP irq,io - 38 NETspider U PCI card none - 39 HFC 2BDS0 SP/PCMCIA irq,io (set with cardmgr) - 40 hotplug interface - 41 Formula-n enter:now PCI none - -At the moment IRQ sharing is only possible with PCI cards. Please make sure -that your IRQ is free and enabled for ISA use. - - -Examples for module loading - -1. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 10 - modprobe hisax type=3 protocol=2 io=0x280 irq=10 - -2. Teles 16.0, 1TR6 ISDN, I/O base d80 hex, IRQ 5, Memory d0000 hex - modprobe hisax protocol=1 type=1 io=0xd80 mem=0xd0000 irq=5 - -3. Fritzcard, Euro ISDN, I/O base 340 hex, IRQ 10 and ELSA PCF, Euro ISDN - modprobe hisax type=5,6 protocol=2,2 io=0x340 irq=10 id=Fritz%Elsa - -4. Any ELSA PCC/PCF card, Euro ISDN - modprobe hisax type=6 protocol=2 - -5. Teles 16.3 PnP, Euro ISDN, with isapnp configured - isapnp config: (INT 0 (IRQ 10 (MODE +E))) - (IO 0 (BASE 0x0580)) - (IO 1 (BASE 0x0180)) - modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180 - - In the current version of HiSax, you can instead simply use - - modprobe hisax type=4 protocol=2 - - if you configured your kernel for ISAPnP. Don't run isapnp in - this case! - -6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and - Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex - modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000 - - Please note the dummy 0 memory address for the Teles 16.3, used as a - placeholder as described above, in the last example. - -7. Teles PCMCIA, Euro ISDN, I/O base 180 hex, IRQ 15 (default values) - modprobe hisax type=8 protocol=2 io=0x180 irq=15 - - -b) using LILO/LOADLIN, with the driver compiled directly into the kernel ------------------------------------------------------------------------- - -hisax=typ1,dp1,pa_1,pb_1,pc_1[,typ2,dp2,pa_2 ... \ - typn,dpn,pa_n,pb_n,pc_n][,idstring1[,idstring2,...,idstringn]] - -where - typ1 = type of 1st card (default depends on kernel settings) - dp1 = D-Channel protocol of 1st card. 1=1TR6, 2=EDSS1, 3=leased - pa_1 = 1st parameter (depending on the type of the card) - pb_1 = 2nd parameter ( " " " " " " " ) - pc_1 = 3rd parameter ( " " " " " " " ) - - typ2,dp2,pa_2,pb_2,pc_2 = Parameters of the second card (defaults: none) - typn,dpn,pa_n,pb_n,pc_n = Parameters of the n'th card (up to 16 cards are - supported) - - idstring = Driver ID for accessing the particular card with utility - programs and for identification when using a line monitor - (default: "HiSax") - - Note: the ID string must start with an alphabetical character! - -Card types: - -type - 1 Teles 16.0 pa=irq pb=membase pc=iobase - 2 Teles 8.0 pa=irq pb=membase - 3 Teles 16.3 pa=irq pb=iobase - 4 Creatix/Teles PNP ONLY WORKS AS A MODULE ! - 5 AVM A1 (Fritz) pa=irq pb=iobase - 6 ELSA PCC/PCF cards pa=iobase or nothing for autodetect - 7 ELSA Quickstep 1000 ONLY WORKS AS A MODULE ! - 8 Teles S0 PCMCIA pa=irq pb=iobase - 9 ITK ix1-micro Rev.2 pa=irq pb=iobase - 10 ELSA PCMCIA pa=irq, pb=io (set with card manager) - 11 Eicon.Diehl Diva ISAPnP ONLY WORKS AS A MODULE ! - 11 Eicon.Diehl Diva PCI no parameter - 12 ASUS COM ISDNLink ONLY WORKS AS A MODULE ! - 13 HFC-2BS0 based cards pa=irq pb=io - 14 Teles 16.3c PnP ONLY WORKS AS A MODULE ! - 15 Sedlbauer Speed Card pa=irq pb=io (Speed Win only as module !) - 15 Sedlbauer PC/104 pa=irq pb=io - 15 Sedlbauer Speed PCI no parameter - 16 USR Sportster internal pa=irq pb=io - 17 MIC card pa=irq pb=io - 18 ELSA Quickstep 1000PCI no parameter - 19 Compaq ISDN S0 ISA card ONLY WORKS AS A MODULE ! - 20 NETjet PCI card no parameter - 21 Teles PCI no parameter - 22 Sedlbauer Speed Star (PCMCIA) pa=irq, pb=io (set with card manager) - 24 Dr. Neuhaus Niccy PnP ONLY WORKS AS A MODULE ! - 24 Dr. Neuhaus Niccy PCI no parameter - 25 Teles S0Box pa=irq, pb=io (of the used lpt port) - 26 AVM A1 PCMCIA (Fritz!) pa=irq, pb=io (set with card manager) - 27 AVM PnP (Fritz!PnP) ONLY WORKS AS A MODULE ! - 27 AVM PCI (Fritz!PCI) no parameter - 28 Sedlbauer Speed Fax+ ONLY WORKS AS A MODULE ! - 29 Siemens I-Surf 1.0 ONLY WORKS AS A MODULE ! - 30 ACER P10 ONLY WORKS AS A MODULE ! - 31 HST Saphir pa=irq, pb=io - 32 Telekom A4T no parameter - 33 Scitel Quadro subcontroller (4*S0, subctrl 1...4) - 34 Gazel ISDN cards (ISA) pa=irq, pb=io - 34 Gazel ISDN cards (PCI) no parameter - 35 HFC 2BDS0 PCI no parameter - 36 W6692 based PCI cards none - 37 HFC 2BDS0 S+,SP/PCMCIA ONLY WORKS AS A MODULE ! - 38 NETspider U PCI card none - 39 HFC 2BDS0 SP/PCMCIA ONLY WORKS AS A MODULE ! - 40 hotplug interface ONLY WORKS AS A MODULE ! - 41 Formula-n enter:now PCI none - -Running the driver ------------------- - -When you insmod isdn.o and hisax.o (or with the in-kernel version, during -boot time), a few lines should appear in your syslog. Look for something like: - -Apr 13 21:01:59 kke01 kernel: HiSax: Driver for Siemens chip set ISDN cards -Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.9 -Apr 13 21:01:59 kke01 kernel: HiSax: Revisions 1.14/1.9/1.10/1.25/1.8 -Apr 13 21:01:59 kke01 kernel: HiSax: Total 1 card defined -Apr 13 21:01:59 kke01 kernel: HiSax: Card 1 Protocol EDSS1 Id=HiSax1 (0) -Apr 13 21:01:59 kke01 kernel: HiSax: Elsa driver Rev. 1.13 -... -Apr 13 21:01:59 kke01 kernel: Elsa: PCF-Pro found at 0x360 Rev.:C IRQ 10 -Apr 13 21:01:59 kke01 kernel: Elsa: timer OK; resetting card -Apr 13 21:01:59 kke01 kernel: Elsa: HSCX version A: V2.1 B: V2.1 -Apr 13 21:01:59 kke01 kernel: Elsa: ISAC 2086/2186 V1.1 -... -Apr 13 21:01:59 kke01 kernel: HiSax: DSS1 Rev. 1.14 -Apr 13 21:01:59 kke01 kernel: HiSax: 2 channels added - -This means that the card is ready for use. -Cabling problems or line-downs are not detected, and only some ELSA cards can -detect the S0 power. - -Remember that, according to the new strategy for accessing low-level drivers -from within isdn4linux, you should also define a driver ID while doing -insmod: Simply append hisax_id= to the insmod command line. This -string MUST NOT start with a digit or a small 'x'! - -At this point you can run a 'cat /dev/isdnctrl0' and view debugging messages. - -At the moment, debugging messages are enabled with the hisaxctrl tool: - - hisaxctrl DebugCmd - - default is HiSax, if you didn't specify one. - -DebugCmd is 1 for generic debugging - 11 for layer 1 development debugging - 13 for layer 3 development debugging - -where is the integer sum of the following debugging -options you wish enabled: - -With DebugCmd set to 1: - - 0x0001 Link-level <--> hardware-level communication - 0x0002 Top state machine - 0x0004 D-Channel Frames for isdnlog - 0x0008 D-Channel Q.921 - 0x0010 B-Channel X.75 - 0x0020 D-Channel l2 - 0x0040 B-Channel l2 - 0x0080 D-Channel link state debugging - 0x0100 B-Channel link state debugging - 0x0200 TEI debug - 0x0400 LOCK debug in callc.c - 0x0800 More paranoid debug in callc.c (not for normal use) - 0x1000 D-Channel l1 state debugging - 0x2000 B-Channel l1 state debugging - -With DebugCmd set to 11: - - 0x0001 Warnings (default: on) - 0x0002 IRQ status - 0x0004 ISAC - 0x0008 ISAC FIFO - 0x0010 HSCX - 0x0020 HSCX FIFO (attention: full B-Channel output!) - 0x0040 D-Channel LAPD frame types - 0x0080 IPAC debug - 0x0100 HFC receive debug - 0x0200 ISAC monitor debug - 0x0400 D-Channel frames for isdnlog (set with 1 0x4 too) - 0x0800 D-Channel message verbose - -With DebugCmd set to 13: - - 1 Warnings (default: on) - 2 l3 protocol descriptor errors - 4 l3 state machine - 8 charge info debugging (1TR6) - -For example, 'hisaxctrl HiSax 1 0x3ff' enables full generic debugging. - -Because of some obscure problems with some switch equipment, the delay -between the CONNECT message and sending the first data on the B-channel is now -configurable with - -hisaxctrl 2 - in ms Value between 50 and 800 ms is recommended. - -Downloading Firmware --------------------- -At the moment, the Sedlbauer speed fax+ is the only card, which -needs to download firmware. -The firmware is downloaded with the hisaxctrl tool: - - hisaxctrl 9 - - default is HiSax, if you didn't specify one, - -where is the filename of the firmware file. - -For example, 'hisaxctrl HiSax 9 ISAR.BIN' downloads the firmware for -ISAR based cards (like the Sedlbauer speed fax+). - -Warning -------- -HiSax is a work in progress and may crash your machine. -For certification look at HiSax.cert file. - -Limitations ------------ -At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines. -For leased lines see appendix. - -Bugs ----- -If you find any, please let me know. - - -Thanks ------- -Special thanks to: - - Emil Stephan for the name HiSax which is a mix of HSCX and ISAC. - - Fritz Elfert, Jan den Ouden, Michael Hipp, Michael Wein, - Andreas Kool, Pekka Sarnila, Sim Yskes, Johan Myrre'en, - Klaus-Peter Nischke (ITK AG), Christof Petig, Werner Fehn (ELSA GmbH), - Volker Schmidt - Edgar Toernig and Marcus Niemann for the Sedlbauer driver - Stephan von Krawczynski - Juergen Quade for the Leased Line part - Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE), for ELSA PCMCIA support - Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff - Ton van Rosmalen for Teles PCI - Petr Novak for Winbond W6692 support - Werner Cornelius for HFC-PCI, HFC-S(+/P) and supplementary services support - and more people who are hunting bugs. (If I forgot somebody, please - send me a mail). - - Firma ELSA GmbH - Firma Eicon.Diehl GmbH - Firma Dynalink NL - Firma ASUSCOM NETWORK INC. Taiwan - Firma S.u.S.E - Firma ith Kommunikationstechnik GmbH - Firma Traverse Technologie Australia - Firma Medusa GmbH (www.medusa.de). - Firma Quant-X Austria for sponsoring a DEC Alpha board+CPU - Firma Cologne Chip Designs GmbH - - My girl friend and partner in life Ute for her patience with me. - - -Enjoy, - -Karsten Keil -keil@isdn4linux.de - - -Appendix: Teles PCMCIA driver ------------------------------ - -See - http://www.linux.no/teles_cs.txt -for instructions. - -Appendix: Linux and ISDN-leased lines -------------------------------------- - -Original from Juergen Quade, new version KKe. - -Attention NEW VERSION, the old leased line syntax won't work !!! - -You can use HiSax to connect your Linux-Box via an ISDN leased line -to e.g. the Internet: - -1. Build a kernel which includes the HiSax driver either as a module - or as part of the kernel. - cd /usr/src/linux - make menuconfig - - make clean; make zImage; make modules; make modules_install -2. Install the new kernel - cp /usr/src/linux/arch/x86/boot/zImage /etc/kernel/linux.isdn - vi /etc/lilo.conf - - lilo -3. in case the hisax driver is a "fixed" part of the kernel, configure - the driver with lilo: - vi /etc/lilo.conf - - lilo - Your lilo.conf _might_ look like the following: - - # LILO configuration-file - # global section - # teles 16.0 on IRQ=5, MEM=0xd8000, PORT=0xd80 - append="hisax=1,3,5,0xd8000,0xd80,HiSax" - # teles 16.3 (non pnp) on IRQ=15, PORT=0xd80 - # append="hisax=3,3,5,0xd8000,0xd80,HiSax" - boot=/dev/sda - compact # faster, but won't work on all systems. - linear - read-only - prompt - timeout=100 - vga = normal # force sane state - # Linux bootable partition config begins - image = /etc/kernel/linux.isdn - root = /dev/sda1 - label = linux.isdn - # - image = /etc/kernel/linux-2.0.30 - root = /dev/sda1 - label = linux.secure - - In the line starting with "append" you have to adapt the parameters - according to your card (see above in this file) - -3. boot the new linux.isdn kernel -4. start the ISDN subsystem: - a) load - if necessary - the modules (depends, whether you compiled - the ISDN driver as module or not) - According to the type of card you have to specify the necessary - driver parameter (irq, io, mem, type, protocol). - For the leased line the protocol is "3". See the table above for - the parameters, which you have to specify depending on your card. - b) configure i4l - /sbin/isdnctrl addif isdn0 - # EAZ 1 -- B1 channel 2 --B2 channel - /sbin/isdnctrl eaz isdn0 1 - /sbin/isdnctrl secure isdn0 on - /sbin/isdnctrl huptimeout isdn0 0 - /sbin/isdnctrl l2_prot isdn0 hdlc - # Attention you must not set an outgoing number !!! This won't work !!! - # The incoming number is LEASED0 for the first card, LEASED1 for the - # second and so on. - /sbin/isdnctrl addphone isdn0 in LEASED0 - # Here is no need to bind the channel. - c) in case the remote partner is a CISCO: - /sbin/isdnctrl encap isdn0 cisco-h - d) configure the interface - /sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP} - e) set the routes - /sbin/route add -host ${REMOTE_IP} isdn0 - /sbin/route add default gw ${REMOTE_IP} - f) switch the card into leased mode for each used B-channel - /sbin/hisaxctrl HiSax 5 1 - -Remarks: -a) Use state of the art isdn4k-utils - -Here an example script: -#!/bin/sh -# Start/Stop ISDN leased line connection - -I4L_AS_MODULE=yes -I4L_REMOTE_IS_CISCO=no -I4L_MODULE_PARAMS="type=16 io=0x268 irq=7 " -I4L_DEBUG=no -I4L_LEASED_128K=yes -LOCAL_IP=192.168.1.1 -REMOTE_IP=192.168.2.1 - -case "$1" in - start) - echo "Starting ISDN ..." - if [ ${I4L_AS_MODULE} = "yes" ]; then - echo "loading modules..." - /sbin/modprobe hisax ${I4L_MODULE_PARAMS} - fi - # configure interface - /sbin/isdnctrl addif isdn0 - /sbin/isdnctrl secure isdn0 on - if [ ${I4L_DEBUG} = "yes" ]; then - /sbin/isdnctrl verbose 7 - /sbin/hisaxctrl HiSax 1 0xffff - /sbin/hisaxctrl HiSax 11 0xff - cat /dev/isdnctrl >/tmp/lea.log & - fi - if [ ${I4L_REMOTE_IS_CISCO} = "yes" ]; then - /sbin/isdnctrl encap isdn0 cisco-h - fi - /sbin/isdnctrl huptimeout isdn0 0 - # B-CHANNEL 1 - /sbin/isdnctrl eaz isdn0 1 - /sbin/isdnctrl l2_prot isdn0 hdlc - # 1. card - /sbin/isdnctrl addphone isdn0 in LEASED0 - if [ ${I4L_LEASED_128K} = "yes" ]; then - /sbin/isdnctrl addslave isdn0 isdn0s - /sbin/isdnctrl secure isdn0s on - /sbin/isdnctrl huptimeout isdn0s 0 - # B-CHANNEL 2 - /sbin/isdnctrl eaz isdn0s 2 - /sbin/isdnctrl l2_prot isdn0s hdlc - # 1. card - /sbin/isdnctrl addphone isdn0s in LEASED0 - if [ ${I4L_REMOTE_IS_CISCO} = "yes" ]; then - /sbin/isdnctrl encap isdn0s cisco-h - fi - fi - /sbin/isdnctrl dialmode isdn0 manual - # configure tcp/ip - /sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP} - /sbin/route add -host ${REMOTE_IP} isdn0 - /sbin/route add default gw ${REMOTE_IP} - # switch to leased mode - # B-CHANNEL 1 - /sbin/hisaxctrl HiSax 5 1 - if [ ${I4L_LEASED_128K} = "yes" ]; then - # B-CHANNEL 2 - sleep 10; /* Wait for master */ - /sbin/hisaxctrl HiSax 5 2 - fi - ;; - stop) - /sbin/ifconfig isdn0 down - /sbin/isdnctrl delif isdn0 - if [ ${I4L_DEBUG} = "yes" ]; then - killall cat - fi - if [ ${I4L_AS_MODULE} = "yes" ]; then - /sbin/rmmod hisax - /sbin/rmmod isdn - /sbin/rmmod ppp - /sbin/rmmod slhc - fi - ;; - *) - echo "Usage: $0 {start|stop}" - exit 1 -esac -exit 0 diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index e7d3d8f2ad5a..7487f0bbe855 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_MISDN) += mISDN/ obj-$(CONFIG_ISDN) += hardware/ obj-$(CONFIG_ISDN_DIVERSION) += divert/ -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/ obj-$(CONFIG_HYSDN) += hysdn/ obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/ diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig deleted file mode 100644 index 43d98ccf5ff6..000000000000 --- a/drivers/isdn/hisax/Kconfig +++ /dev/null @@ -1,423 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -menu "Passive cards" - -config ISDN_DRV_HISAX - tristate "HiSax SiemensChipSet driver support" - select CRC_CCITT - ---help--- - This is a driver supporting the Siemens chipset on various - ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles - S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many - compatibles). - - HiSax is just the name of this driver, not the name of any hardware. - - If you have a card with such a chipset, you should say Y here and - also to the configuration option of the driver for your particular - card, below. - -if ISDN_DRV_HISAX - -comment "D-channel protocol features" - -config HISAX_EURO - bool "HiSax Support for EURO/DSS1" - help - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - The call control protocol E-DSS1 is used in most European countries. - If unsure, say Y. - -config DE_AOC - bool "Support for german chargeinfo" - depends on HISAX_EURO - help - If you want that the HiSax hardware driver sends messages to the - upper level of the isdn code on each AOCD (Advice Of Charge, During - the call -- transmission of the fee information during a call) and - on each AOCE (Advice Of Charge, at the End of the call -- - transmission of fee information at the end of the call), say Y here. - This works only in Germany. - -config HISAX_NO_SENDCOMPLETE - bool "Disable sending complete" - depends on HISAX_EURO - help - If you have trouble with some ugly exchanges or you live in - Australia select this option. - -config HISAX_NO_LLC - bool "Disable sending low layer compatibility" - depends on HISAX_EURO - help - If you have trouble with some ugly exchanges try to select this - option. - -config HISAX_NO_KEYPAD - bool "Disable keypad protocol option" - depends on HISAX_EURO - help - If you like to send special dial strings including * or # without - using the keypad protocol, select this option. - -config HISAX_1TR6 - bool "HiSax Support for german 1TR6" - help - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - 1TR6 is an old call control protocol which was used in Germany - before E-DSS1 was established. Nowadays, all new lines in Germany - use E-DSS1. - -config HISAX_NI1 - bool "HiSax Support for US NI1" - help - Enable this if you like to use ISDN in US on a NI1 basic rate - interface. - -config HISAX_MAX_CARDS - int "Maximum number of cards supported by HiSax" - default "8" - help - This option allows you to specify the maximum number of cards which - the HiSax driver will be able to handle. - -comment "HiSax supported cards" - -config HISAX_16_0 - bool "Teles 16.0/8.0" - depends on ISA - help - This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 - and many compatibles. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port/shmem settings. - -config HISAX_16_3 - bool "Teles 16.3 or PNP or PCMCIA" - help - This enables HiSax support for the Teles ISDN-cards S0-16.3 the - Teles/Creatix PnP and the Teles PCMCIA. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_TELESPCI - bool "Teles PCI" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the Teles PCI. - See on how to configure it. - -config HISAX_S0BOX - bool "Teles S0Box" - help - This enables HiSax support for the Teles/Creatix parallel port - S0BOX. See on how to - configure it. - -config HISAX_AVM_A1 - bool "AVM A1 (Fritz)" - depends on ISA - help - This enables HiSax support for the AVM A1 (aka "Fritz"). - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_FRITZPCI - bool "AVM PnP/PCI (Fritz!PnP/PCI)" - depends on BROKEN || !PPC64 - help - This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". - See on how to configure it. - -config HISAX_AVM_A1_PCMCIA - bool "AVM A1 PCMCIA (Fritz)" - help - This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). - See on how to configure it. - -config HISAX_ELSA - bool "Elsa cards" - help - This enables HiSax support for the Elsa Mircolink ISA cards, for the - Elsa Quickstep series cards and Elsa PCMCIA. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_IX1MICROR2 - bool "ITK ix1-micro Revision 2" - depends on ISA - help - This enables HiSax support for the ITK ix1-micro Revision 2 card. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_DIEHLDIVA - bool "Eicon.Diehl Diva cards" - help - This enables HiSax support for the Eicon.Diehl Diva none PRO - versions passive ISDN cards. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_ASUSCOM - bool "ASUSCOM ISA cards" - depends on ISA - help - This enables HiSax support for the AsusCom and their OEM versions - passive ISDN ISA cards. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_TELEINT - bool "TELEINT cards" - depends on ISA - help - This enables HiSax support for the TELEINT SA1 semiactiv ISDN card. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_HFCS - bool "HFC-S based cards" - depends on ISA - help - This enables HiSax support for the HFC-S 2BDS0 based cards, like - teles 16.3c. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_SEDLBAUER - bool "Sedlbauer cards" - help - This enables HiSax support for the Sedlbauer passive ISDN cards. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_SPORTSTER - bool "USR Sportster internal TA" - depends on ISA - help - This enables HiSax support for the USR Sportster internal TA card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_MIC - bool "MIC card" - depends on ISA - help - This enables HiSax support for the ITH MIC card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NETJET - bool "NETjet card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) - depends on VIRT_TO_BUS - help - This enables HiSax support for the NetJet from Traverse - Technologies. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NETJET_U - bool "NETspider U card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) - depends on VIRT_TO_BUS - help - This enables HiSax support for the Netspider U interface ISDN card - from Traverse Technologies. - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NICCY - bool "Niccy PnP/PCI card" - help - This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_ISURF - bool "Siemens I-Surf card" - depends on ISA - help - This enables HiSax support for the Siemens I-Talk/I-Surf card with - ISAR chip. - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HSTSAPHIR - bool "HST Saphir card" - depends on ISA - help - This enables HiSax support for the HST Saphir card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_BKM_A4T - bool "Telekom A4T card" - depends on PCI - help - This enables HiSax support for the Telekom A4T card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_SCT_QUADRO - bool "Scitel Quadro card" - depends on PCI - help - This enables HiSax support for the Scitel Quadro card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_GAZEL - bool "Gazel cards" - help - This enables HiSax support for the Gazel cards. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HFC_PCI - bool "HFC PCI-Bus cards" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the HFC-S PCI 2BDS0 based cards. - - For more information see under - . - -config HISAX_W6692 - bool "Winbond W6692 based cards" - depends on PCI - help - This enables HiSax support for Winbond W6692 based PCI ISDN cards. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HFC_SX - bool "HFC-S+, HFC-SP, HFC-PCMCIA cards" - help - This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA - cards. This code is not finished yet. - -config HISAX_ENTERNOW_PCI - bool "Formula-n enter:now PCI card" - depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the Formula-n enter:now PCI - ISDN card. - -config HISAX_DEBUG - bool "HiSax debugging" - help - This enables debugging code in the new-style HiSax drivers, i.e. - the ST5481 USB driver currently. - If in doubt, say yes. - -comment "HiSax PCMCIA card service modules" - -config HISAX_SEDLBAUER_CS - tristate "Sedlbauer PCMCIA cards" - depends on PCMCIA && HISAX_SEDLBAUER - help - This enables the PCMCIA client driver for the Sedlbauer Speed Star - and Speed Star II cards. - -config HISAX_ELSA_CS - tristate "ELSA PCMCIA MicroLink cards" - depends on PCMCIA && HISAX_ELSA - help - This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink - card. - -config HISAX_AVM_A1_CS - tristate "AVM A1 PCMCIA cards" - depends on PCMCIA && ISDN_DRV_HISAX - help - This enables the PCMCIA client driver for the AVM A1 / Fritz!Card - PCMCIA cards. - -config HISAX_TELES_CS - tristate "TELES PCMCIA cards" - depends on PCMCIA && HISAX_16_3 - help - This enables the PCMCIA client driver for the Teles PCMCIA cards. - -comment "HiSax sub driver modules" - -config HISAX_ST5481 - tristate "ST5481 USB ISDN modem" - depends on USB - select ISDN_HDLC - select CRC_CCITT - select BITREVERSE - help - This enables the driver for ST5481 based USB ISDN adapters, - e.g. the BeWan Gazel 128 USB - -config HISAX_HFCUSB - tristate "HFC USB based ISDN modems" - depends on USB - help - This enables the driver for HFC USB based ISDN modems. - -config HISAX_HFC4S8S - tristate "HFC-4S/8S based ISDN cards" - help - This enables the driver for HFC-4S/8S based ISDN cards. - -config HISAX_FRITZ_PCIPNP - tristate "AVM Fritz!Card PCI/PCIv2/PnP support" - depends on PCI - help - This enables the driver for the AVM Fritz!Card PCI, - Fritz!Card PCI v2 and Fritz!Card PnP. - (the latter also needs you to select "ISA Plug and Play support" - from the menu "Plug and Play configuration") - -endif - -endmenu - diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile deleted file mode 100644 index 3eca9d23f1c2..000000000000 --- a/drivers/isdn/hisax/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the hisax ISDN device driver - -# The target object and module list name. - -# Define maximum number of cards - -ccflags-y := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) - -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o -obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o -obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o -obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o -obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o -obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o -obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o -obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o -obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o - -# Multipart objects. - -hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ - st5481_b.o - -hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o -hisax-$(CONFIG_HISAX_EURO) += l3dss1.o -hisax-$(CONFIG_HISAX_NI1) += l3ni1.o -hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o - -hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o -hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o -hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o -hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \ - isar.o -hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o -hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o -hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o -hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o -hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o -hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o -hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o -hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_W6692) += w6692.o -hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o - diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c deleted file mode 100644 index 6c336366128c..000000000000 --- a/drivers/isdn/hisax/amd7930_fn.c +++ /dev/null @@ -1,794 +0,0 @@ -/* gerdes_amd7930.c,v 0.99 2001/10/02 - * - * gerdes_amd7930.c Amd 79C30A and 79C32A specific routines - * (based on HiSax driver by Karsten Keil) - * - * Author Christoph Ersfeld - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - * - * - * Notes: - * Version 0.99 is the first release of this driver and there are - * certainly a few bugs. - * - * Please don't report any malfunction to me without sending - * (compressed) debug-logs. - * It would be nearly impossible to retrace it. - * - * Log D-channel-processing as follows: - * - * 1. Load hisax with card-specific parameters, this example ist for - * Formula-n enter:now ISDN PCI and compatible - * (f.e. Gerdes Power ISDN PCI) - * - * modprobe hisax type=41 protocol=2 id=gerdes - * - * if you chose an other value for id, you need to modify the - * code below, too. - * - * 2. set debug-level - * - * hisaxctrl gerdes 1 0x3ff - * hisaxctrl gerdes 11 0x4f - * cat /dev/isdnctrl >> ~/log & - * - * Please take also a look into /var/log/messages if there is - * anything importand concerning HISAX. - * - * - * Credits: - * Programming the driver for Formula-n enter:now ISDN PCI and - * necessary this driver for the used Amd 7930 D-channel-controller - * was spnsored by Formula-n Europe AG. - * Thanks to Karsten Keil and Petr Novak, who gave me support in - * Hisax-specific questions. - * I want so say special thanks to Carl-Friedrich Braun, who had to - * answer a lot of questions about generally ISDN and about handling - * of the Amd-Chip. - * - */ - - -#include "hisax.h" -#include "isdnl1.h" -#include "isac.h" -#include "amd7930_fn.h" -#include -#include -#include - -static void Amd7930_new_ph(struct IsdnCardState *cs); - -static WORD initAMD[] = { - 0x0100, - - 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2 - 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on) - 0x0087, 1, 0xFF, // DMR2 - 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on) - 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition ) - 0x0084, 2, 0x80, 0x00, // DRLR - 0x00C0, 1, 0x47, // PPCR1 - 0x00C8, 1, 0x01, // PPCR2 - - 0x0102, - 0x0107, - 0x01A1, 1, - 0x0121, 1, - 0x0189, 2, - - 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4 - 0x0063, 2, 0x08, 0x08, // GX - 0x0064, 2, 0x08, 0x08, // GR - 0x0065, 2, 0x99, 0x00, // GER - 0x0066, 2, 0x7C, 0x8B, // STG - 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2 - 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2 - 0x0069, 1, 0x4F, // MMR1 - 0x006A, 1, 0x00, // MMR2 - 0x006C, 1, 0x40, // MMR3 - 0x0021, 1, 0x02, // INIT - 0x00A3, 1, 0x40, // LMR1 - - 0xFFFF -}; - - -static void /* macro wWordAMD */ -WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val) -{ - wByteAMD(cs, 0x00, reg); - wByteAMD(cs, 0x01, LOBYTE(val)); - wByteAMD(cs, 0x01, HIBYTE(val)); -} - -static WORD /* macro rWordAMD */ -ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg) -{ - WORD res; - /* direct access register */ - if (reg < 8) { - res = rByteAMD(cs, reg); - res += 256 * rByteAMD(cs, reg); - } - /* indirect access register */ - else { - wByteAMD(cs, 0x00, reg); - res = rByteAMD(cs, 0x01); - res += 256 * rByteAMD(cs, 0x01); - } - return (res); -} - - -static void -Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command); - - cs->dc.amd7930.lmr1 = command; - wByteAMD(cs, 0xA3, command); -} - - - -static BYTE i430States[] = { -// to reset F3 F4 F5 F6 F7 F8 AR from - 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init - 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset - 0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3 - 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4 - 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5 - 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6 - 0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7 - 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8 - 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR - - -/* Row init - reset F3 F4 F5 F6 F7 F8 AR */ -static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; - - - - -static void -Amd7930_get_state(struct IsdnCardState *cs) { - BYTE lsr = rByteAMD(cs, 0xA1); - cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; - Amd7930_new_ph(cs); -} - - - -static void -Amd7930_new_ph(struct IsdnCardState *cs) -{ - u_char index = stateHelper[cs->dc.amd7930.old_state] * 8 + stateHelper[cs->dc.amd7930.ph_state] - 1; - u_char message = i430States[index]; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d", - cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index); - - cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state; - - /* abort transmit if nessesary */ - if ((message & 0xf0) && (cs->tx_skb)) { - wByteAMD(cs, 0x21, 0xC2); - wByteAMD(cs, 0x21, 0x02); - } - - switch (message & 0x0f) { - - case (1): - l1_msg(cs, HW_RESET | INDICATION, NULL); - Amd7930_get_state(cs); - break; - case (2): /* init, Card starts in F3 */ - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (4): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST"); - break; - case (5): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (7): /* init, Card starts in F7 */ - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - /* fall through */ - case (9): - Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set"); - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (10): - Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared"); - cs->dc.amd7930.old_state = 3; - break; - case (11): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - default: - break; - } -} - - - -static void -Amd7930_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: bh, D_L1STATECHANGE"); - Amd7930_new_ph(cs); - } - - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: bh, D_RCVBUFREADY"); - DChannel_proc_rcv(cs); - } - - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: bh, D_XMTBUFREADY"); - DChannel_proc_xmt(cs); - } -} - -static void -Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag) -{ - - BYTE stat, der; - BYTE *ptr; - struct sk_buff *skb; - - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "Amd7930: empty_Dfifo"); - - - ptr = cs->rcvbuf + cs->rcvidx; - - /* AMD interrupts off */ - AmdIrqOff(cs); - - /* read D-Channel-Fifo*/ - stat = rByteAMD(cs, 0x07); // DSR2 - - /* while Data in Fifo ... */ - while ((stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1)) { - *ptr = rByteAMD(cs, 0x04); // DCRB - ptr++; - stat = rByteAMD(cs, 0x07); // DSR2 - cs->rcvidx = ptr - cs->rcvbuf; - - /* Paket ready? */ - if (stat & 1) { - - der = rWordAMD(cs, 0x03); - - /* no errors, packet ok */ - if (!der && !flag) { - rWordAMD(cs, 0x89); // clear DRCR - - if ((cs->rcvidx) > 0) { - if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n"); - else { - /* Debugging */ - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx); - QuickHex(t, cs->rcvbuf, cs->rcvidx); - debugl1(cs, "%s", cs->dlog); - } - /* moves received data in sk-buffer */ - skb_put_data(skb, cs->rcvbuf, - cs->rcvidx); - skb_queue_tail(&cs->rq, skb); - } - } - - } - /* throw damaged packets away, reset receive-buffer, indicate RX */ - ptr = cs->rcvbuf; - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - } - /* Packet to long, overflow */ - if (cs->rcvidx >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun"); - cs->rcvidx = 0; - return; - } - /* AMD interrupts on */ - AmdIrqOn(cs); -} - - -static void -Amd7930_fill_Dfifo(struct IsdnCardState *cs) -{ - - WORD dtcrr, dtcrw, len, count; - BYTE txstat, dmr3; - BYTE *ptr, *deb_ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "Amd7930: fill_Dfifo"); - - if ((!cs->tx_skb) || (cs->tx_skb->len <= 0)) - return; - - dtcrw = 0; - if (!cs->dc.amd7930.tx_xmtlen) - /* new Frame */ - len = dtcrw = cs->tx_skb->len; - /* continue frame */ - else len = cs->dc.amd7930.tx_xmtlen; - - - /* AMD interrupts off */ - AmdIrqOff(cs); - - deb_ptr = ptr = cs->tx_skb->data; - - /* while free place in tx-fifo available and data in sk-buffer */ - txstat = 0x10; - while ((txstat & 0x10) && (cs->tx_cnt < len)) { - wByteAMD(cs, 0x04, *ptr); - ptr++; - cs->tx_cnt++; - txstat = rByteAMD(cs, 0x07); - } - count = ptr - cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - - - dtcrr = rWordAMD(cs, 0x85); // DTCR - dmr3 = rByteAMD(cs, 0x8E); - - if (cs->debug & L1_DEB_ISAC) { - debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw)); - } - - /* writeing of dtcrw starts transmit */ - if (!cs->dc.amd7930.tx_xmtlen) { - wWordAMD(cs, 0x85, dtcrw); - cs->dc.amd7930.tx_xmtlen = dtcrw; - } - - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); - add_timer(&cs->dbusytimer); - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count); - QuickHex(t, deb_ptr, count); - debugl1(cs, "%s", cs->dlog); - } - /* AMD interrupts on */ - AmdIrqOn(cs); -} - - -void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags) -{ - BYTE dsr1, dsr2, lsr; - WORD der; - - while (irflags) - { - - dsr1 = rByteAMD(cs, 0x02); - der = rWordAMD(cs, 0x03); - dsr2 = rByteAMD(cs, 0x07); - lsr = rByteAMD(cs, 0xA1); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der); - - /* D error -> read DER and DSR2 bit 2 */ - if (der || (dsr2 & 4)) { - - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der); - - /* RX, TX abort if collision detected */ - if (der & 2) { - wByteAMD(cs, 0x21, 0xC2); - wByteAMD(cs, 0x21, 0x02); - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - /* restart frame */ - if (cs->tx_skb) { - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - Amd7930_fill_Dfifo(cs); - } else { - printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n"); - debugl1(cs, "Amd7930: interrupt: D-Collision, no skb"); - } - } - /* remove damaged data from fifo */ - Amd7930_empty_Dfifo(cs, 1); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - /* restart TX-Frame */ - if (cs->tx_skb) { - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - Amd7930_fill_Dfifo(cs); - } - } - - /* D TX FIFO empty -> fill */ - if (irflags & 1) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data"); - - /* AMD interrupts off */ - AmdIrqOff(cs); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) - Amd7930_fill_Dfifo(cs); - } - /* AMD interrupts on */ - AmdIrqOn(cs); - } - - - /* D RX FIFO full or tiny packet in Fifo -> empty */ - if ((irflags & 2) || (dsr1 & 2)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: empty D-FIFO"); - Amd7930_empty_Dfifo(cs, 0); - } - - - /* D-Frame transmit complete */ - if (dsr1 & 64) { - if (cs->debug & L1_DEB_ISAC) { - debugl1(cs, "Amd7930: interrupt: transmit packet ready"); - } - /* AMD interrupts off */ - AmdIrqOff(cs); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - - if (cs->tx_skb) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb"); - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - cs->tx_skb = NULL; - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued"); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - Amd7930_fill_Dfifo(cs); - } - else - schedule_event(cs, D_XMTBUFREADY); - /* AMD interrupts on */ - AmdIrqOn(cs); - } - - /* LIU status interrupt -> read LSR, check statechanges */ - if (lsr & 0x38) { - /* AMD interrupts off */ - AmdIrqOff(cs); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2)); - - cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; - - schedule_event(cs, D_L1STATECHANGE); - /* AMD interrupts on */ - AmdIrqOn(cs); - } - - /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */ - irflags = rByteAMD(cs, 0x00); - } - -} - -static void -Amd7930_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr); - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0); -#endif - Amd7930_fill_Dfifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0); -#endif - Amd7930_fill_Dfifo(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if (cs->dc.amd7930.ph_state == 8) { - /* b-channels off, PH-AR cleared - * change to F3 */ - Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5 - spin_unlock_irqrestore(&cs->lock, flags); - } else { - Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST"); - cs->dc.amd7930.ph_state = 2; - spin_unlock_irqrestore(&cs->lock, flags); - Amd7930_new_ph(cs); - } - break; - case (HW_ENABLE | REQUEST): - cs->dc.amd7930.ph_state = 9; - Amd7930_new_ph(cs); - break; - case (HW_INFO3 | REQUEST): - // automatic - break; - case (HW_TESTLOOP | REQUEST): - /* not implemented yet */ - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Amd7930: l1hw: unknown %04x", pr); - break; - } -} - -static void -setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs) -{ - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: setstack called"); - - st->l1.l1hw = Amd7930_l1hw; -} - - -static void -DC_Close_Amd7930(struct IsdnCardState *cs) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: DC_Close called"); -} - - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - u_long flags; - struct PStack *stptr; - WORD dtcr, der; - BYTE dsr1, dsr2; - - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer expired!"); - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - spin_lock_irqsave(&cs->lock, flags); - /* D Transmit Byte Count Register: - * Counts down packet's number of Bytes, 0 if packet ready */ - dtcr = rWordAMD(cs, 0x85); - dsr1 = rByteAMD(cs, 0x02); - dsr2 = rByteAMD(cs, 0x07); - der = rWordAMD(cs, 0x03); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt); - - if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - spin_unlock_irqrestore(&cs->lock, flags); - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - cs->dc.amd7930.tx_xmtlen = 0; - } else { - printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n"); - debugl1(cs, "Amd7930: D-Channel Busy no skb"); - - } - /* Transmitter reset, abort transmit */ - wByteAMD(cs, 0x21, 0x82); - wByteAMD(cs, 0x21, 0x02); - spin_unlock_irqrestore(&cs->lock, flags); - cs->irq_func(cs->irq, cs); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset"); - } - } -} - - - -void Amd7930_init(struct IsdnCardState *cs) -{ - WORD *ptr; - BYTE cmd, cnt; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: initamd called"); - - cs->dc.amd7930.tx_xmtlen = 0; - cs->dc.amd7930.old_state = 0; - cs->dc.amd7930.lmr1 = 0x40; - cs->dc.amd7930.ph_command = Amd7930_ph_command; - cs->setstack_d = setstack_Amd7930; - cs->DC_Close = DC_Close_Amd7930; - - /* AMD Initialisation */ - for (ptr = initAMD; *ptr != 0xFFFF; ) { - cmd = LOBYTE(*ptr); - - /* read */ - if (*ptr++ >= 0x100) { - if (cmd < 8) - /* reset register */ - rByteAMD(cs, cmd); - else { - wByteAMD(cs, 0x00, cmd); - for (cnt = *ptr++; cnt > 0; cnt--) - rByteAMD(cs, 0x01); - } - } - /* write */ - else if (cmd < 8) - wByteAMD(cs, cmd, LOBYTE(*ptr++)); - - else { - wByteAMD(cs, 0x00, cmd); - for (cnt = *ptr++; cnt > 0; cnt--) - wByteAMD(cs, 0x01, LOBYTE(*ptr++)); - } - } -} - -void setup_Amd7930(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, Amd7930_bh); - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); -} diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h deleted file mode 100644 index 1f4d80c5e5a6..000000000000 --- a/drivers/isdn/hisax/amd7930_fn.h +++ /dev/null @@ -1,37 +0,0 @@ -/* drivers/isdn/hisax/amd7930_fn.h - * - * gerdes_amd7930.h Header-file included by - * gerdes_amd7930.c - * - * Author Christoph Ersfeld - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - */ - - - - -#define BYTE unsigned char -#define WORD unsigned int -#define rByteAMD(cs, reg) cs->readisac(cs, reg) -#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val) -#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg) -#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val) -#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256)) -#define LOBYTE(w) ((unsigned char)(w & 0x00ff)) - -#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0) -#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1) - -#define AMD_CR 0x00 -#define AMD_DR 0x01 - - -#define DBUSY_TIMER_VALUE 80 - -extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char); -extern void Amd7930_init(struct IsdnCardState *); -extern void setup_Amd7930(struct IsdnCardState *); diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c deleted file mode 100644 index 2f784f96d439..000000000000 --- a/drivers/isdn/hisax/arcofi.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $ - * - * Ansteuerung ARCOFI 2165 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isdnl1.h" -#include "isac.h" -#include "arcofi.h" - -#define ARCOFI_TIMER_VALUE 20 - -static void -add_arcofi_timer(struct IsdnCardState *cs) { - if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } - cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ) / 1000); - add_timer(&cs->dc.isac.arcofitimer); -} - -static void -send_arcofi(struct IsdnCardState *cs) { - add_arcofi_timer(cs); - cs->dc.isac.mon_txp = 0; - cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len; - memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc); - switch (cs->dc.isac.arcofi_bc) { - case 0: break; - case 1: cs->dc.isac.mon_tx[1] |= 0x40; - break; - default: break; - } - cs->dc.isac.mocr &= 0x0f; - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - (void) cs->readisac(cs, ISAC_MOSR); - cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); - cs->dc.isac.mocr |= 0x10; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); -} - -int -arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { - if (cs->debug & L1_DEB_MONITOR) { - debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event); - } - if (event == ARCOFI_TIMEOUT) { - cs->dc.isac.arcofi_state = ARCOFI_NOP; - test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags); - wake_up(&cs->dc.isac.arcofi_wait); - return (1); - } - switch (cs->dc.isac.arcofi_state) { - case ARCOFI_NOP: - if (event == ARCOFI_START) { - cs->dc.isac.arcofi_list = data; - cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; - send_arcofi(cs); - } - break; - case ARCOFI_TRANSMIT: - if (event == ARCOFI_TX_END) { - if (cs->dc.isac.arcofi_list->receive) { - add_arcofi_timer(cs); - cs->dc.isac.arcofi_state = ARCOFI_RECEIVE; - } else { - if (cs->dc.isac.arcofi_list->next) { - cs->dc.isac.arcofi_list = - cs->dc.isac.arcofi_list->next; - send_arcofi(cs); - } else { - if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } - cs->dc.isac.arcofi_state = ARCOFI_NOP; - wake_up(&cs->dc.isac.arcofi_wait); - } - } - } - break; - case ARCOFI_RECEIVE: - if (event == ARCOFI_RX_END) { - if (cs->dc.isac.arcofi_list->next) { - cs->dc.isac.arcofi_list = - cs->dc.isac.arcofi_list->next; - cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; - send_arcofi(cs); - } else { - if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } - cs->dc.isac.arcofi_state = ARCOFI_NOP; - wake_up(&cs->dc.isac.arcofi_wait); - } - } - break; - default: - debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state); - return (2); - } - return (0); -} - -static void -arcofi_timer(struct timer_list *t) { - struct IsdnCardState *cs = from_timer(cs, t, dc.isac.arcofitimer); - arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL); -} - -void -clear_arcofi(struct IsdnCardState *cs) { - if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } -} - -void -init_arcofi(struct IsdnCardState *cs) { - timer_setup(&cs->dc.isac.arcofitimer, arcofi_timer, 0); - init_waitqueue_head(&cs->dc.isac.arcofi_wait); - test_and_set_bit(HW_ARCOFI, &cs->HW_Flags); -} diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h deleted file mode 100644 index b9c77529fabf..000000000000 --- a/drivers/isdn/hisax/arcofi.h +++ /dev/null @@ -1,27 +0,0 @@ -/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $ - * - * Ansteuerung ARCOFI 2165 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define ARCOFI_USE 1 - -/* states */ -#define ARCOFI_NOP 0 -#define ARCOFI_TRANSMIT 1 -#define ARCOFI_RECEIVE 2 -/* events */ -#define ARCOFI_START 1 -#define ARCOFI_TX_END 2 -#define ARCOFI_RX_END 3 -#define ARCOFI_TIMEOUT 4 - -extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data); -extern void init_arcofi(struct IsdnCardState *cs); -extern void clear_arcofi(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c deleted file mode 100644 index 74c871495e81..000000000000 --- a/drivers/isdn/hisax/asuscom.c +++ /dev/null @@ -1,423 +0,0 @@ -/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information - * - */ - -#include -#include -#include "hisax.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *Asuscom_revision = "$Revision: 1.14.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ASUS_ISAC 0 -#define ASUS_HSCX 1 -#define ASUS_ADR 2 -#define ASUS_CTRL_U7 3 -#define ASUS_CTRL_POTS 5 - -#define ASUS_IPAC_ALE 0 -#define ASUS_IPAC_DATA 1 - -#define ASUS_ISACHSCX 1 -#define ASUS_IPAC 2 - -/* CARD_ADR (Write) */ -#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.asus.adr, - cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.asus.adr, - cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \ - cs->hw.asus.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \ - cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \ - cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \ - cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -asuscom_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -asuscom_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val, icnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "ASUS IRQ LOOP\n"); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_asuscom(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - if (cs->hw.asus.cfg_reg) - release_region(cs->hw.asus.cfg_reg, bytecnt); -} - -static void -reset_asuscom(struct IsdnCardState *cs) -{ - if (cs->subtyp == ASUS_IPAC) - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20); - else - byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ - mdelay(10); - if (cs->subtyp == ASUS_IPAC) - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); - else - byteout(cs->hw.asus.adr, 0); /* Reset Off */ - mdelay(10); - if (cs->subtyp == ASUS_IPAC) { - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12); - } -} - -static int -Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_asuscom(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_asuscom(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - cs->debug |= L1_DEB_IPAC; - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id asus_ids[] = { - { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), - ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), - (unsigned long) "Asus1688 PnP" }, - { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), - ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), - (unsigned long) "Asus1690 PnP" }, - { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), - ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), - (unsigned long) "Isurf2 PnP" }, - { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), - ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), - (unsigned long) "Iscas TE320" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &asus_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_asuscom(struct IsdnCard *card) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - u_char val; - char tmp[64]; - - strcpy(tmp, Asuscom_revision); - printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_ASUSCOM) - return (0); -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "AsusPnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "AsusPnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - bytecnt = 8; - cs->hw.asus.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) { - printk(KERN_WARNING - "HiSax: ISDNLink config port %x-%x already in use\n", - cs->hw.asus.cfg_reg, - cs->hw.asus.cfg_reg + bytecnt); - return (0); - } - printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n", - cs->hw.asus.cfg_reg, cs->irq); - setup_isac(cs); - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Asus_card_msg; - val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, - cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); - if ((val == 1) || (val == 2)) { - cs->subtyp = ASUS_IPAC; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &asuscom_interrupt_ipac; - printk(KERN_INFO "Asus: IPAC version %x\n", val); - } else { - cs->subtyp = ASUS_ISACHSCX; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; - cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; - cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->irq_func = &asuscom_interrupt; - ISACVersion(cs, "ISDNLink:"); - if (HscxVersion(cs, "ISDNLink:")) { - printk(KERN_WARNING - "ISDNLink: wrong HSCX versions check IO address\n"); - release_io_asuscom(cs); - return (0); - } - } - return (1); -} diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c deleted file mode 100644 index 7dd74087ad72..000000000000 --- a/drivers/isdn/hisax/avm_a1.c +++ /dev/null @@ -1,307 +0,0 @@ -/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $ - * - * low level stuff for AVM A1 (Fritz) isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *avm_revision = "$Revision: 2.15.2.4 $"; - -#define AVM_A1_STAT_ISAC 0x01 -#define AVM_A1_STAT_HSCX 0x02 -#define AVM_A1_STAT_TIMER 0x04 - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int adr, u_char off) -{ - return (bytein(adr + off)); -} - -static inline void -writereg(unsigned int adr, u_char off, u_char data) -{ - byteout(adr + off, data); -} - - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.avm.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.avm.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.avm.isacfifo, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.avm.isacfifo, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.avm.hscx[hscx], offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.avm.hscx[hscx], offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -avm_a1_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) { - if (!(sval & AVM_A1_STAT_TIMER)) { - byteout(cs->hw.avm.cfg_reg, 0x1E); - sval = bytein(cs->hw.avm.cfg_reg); - } else if (cs->debug & L1_DEB_INTSTAT) - debugl1(cs, "avm IntStatus %x", sval); - if (!(sval & AVM_A1_STAT_HSCX)) { - val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA); - if (val) - hscx_int_main(cs, val); - } - if (!(sval & AVM_A1_STAT_ISAC)) { - val = readreg(cs->hw.avm.isac, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); - } - } - writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.avm.isac, ISAC_MASK, 0x0); - writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static inline void -release_ioregs(struct IsdnCardState *cs, int mask) -{ - release_region(cs->hw.avm.cfg_reg, 8); - if (mask & 1) - release_region(cs->hw.avm.isac + 32, 32); - if (mask & 2) - release_region(cs->hw.avm.isacfifo, 1); - if (mask & 4) - release_region(cs->hw.avm.hscx[0] + 32, 32); - if (mask & 8) - release_region(cs->hw.avm.hscxfifo[0], 1); - if (mask & 0x10) - release_region(cs->hw.avm.hscx[1] + 32, 32); - if (mask & 0x20) - release_region(cs->hw.avm.hscxfifo[1], 1); -} - -static int -AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - return (0); - case CARD_RELEASE: - release_ioregs(cs, 0x3f); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 1); - byteout(cs->hw.avm.cfg_reg, 0x16); - byteout(cs->hw.avm.cfg_reg, 0x1E); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_avm_a1(struct IsdnCard *card) -{ - u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, avm_revision); - printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_A1) - return (0); - - cs->hw.avm.cfg_reg = card->para[1] + 0x1800; - cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20; - cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20; - cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20; - cs->hw.avm.isacfifo = card->para[1] + 0x1000; - cs->hw.avm.hscxfifo[0] = card->para[1]; - cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800; - cs->irq = card->para[0]; - if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) { - printk(KERN_WARNING - "HiSax: AVM A1 config port %x-%x already in use\n", - cs->hw.avm.cfg_reg, - cs->hw.avm.cfg_reg + 8); - return (0); - } - if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) { - printk(KERN_WARNING - "HiSax: AVM A1 isac ports %x-%x already in use\n", - cs->hw.avm.isac + 32, - cs->hw.avm.isac + 64); - release_ioregs(cs, 0); - return (0); - } - if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) { - printk(KERN_WARNING - "HiSax: AVM A1 isac fifo port %x already in use\n", - cs->hw.avm.isacfifo); - release_ioregs(cs, 1); - return (0); - } - if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx A ports %x-%x already in use\n", - cs->hw.avm.hscx[0] + 32, - cs->hw.avm.hscx[0] + 64); - release_ioregs(cs, 3); - return (0); - } - if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx A fifo port %x already in use\n", - cs->hw.avm.hscxfifo[0]); - release_ioregs(cs, 7); - return (0); - } - if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx B ports %x-%x already in use\n", - cs->hw.avm.hscx[1] + 32, - cs->hw.avm.hscx[1] + 64); - release_ioregs(cs, 0xf); - return (0); - } - if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx B fifo port %x already in use\n", - cs->hw.avm.hscxfifo[1]); - release_ioregs(cs, 0x1f); - return (0); - } - byteout(cs->hw.avm.cfg_reg, 0x0); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg, 0x1); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg, 0x0); - HZDELAY(HZ / 5 + 1); - val = cs->irq; - if (val == 9) - val = 2; - byteout(cs->hw.avm.cfg_reg + 1, val); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg, 0x0); - HZDELAY(HZ / 5 + 1); - - val = bytein(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg, val); - val = bytein(cs->hw.avm.cfg_reg + 3); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg + 3, val); - val = bytein(cs->hw.avm.cfg_reg + 2); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg + 2, val); - val = bytein(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg, val); - - printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n", - cs->irq, - cs->hw.avm.cfg_reg); - printk(KERN_INFO - "HiSax: isac:0x%X/0x%X\n", - cs->hw.avm.isac + 32, cs->hw.avm.isacfifo); - printk(KERN_INFO - "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n", - cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0], - cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]); - - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - setup_isac(cs); - cs->cardmsg = &AVM_card_msg; - cs->irq_func = &avm_a1_interrupt; - ISACVersion(cs, "AVM A1:"); - if (HscxVersion(cs, "AVM A1:")) { - printk(KERN_WARNING - "AVM A1: wrong HSCX versions check IO address\n"); - release_ioregs(cs, 0x3f); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c deleted file mode 100644 index bc52d54ff5e1..000000000000 --- a/drivers/isdn/hisax/avm_a1p.c +++ /dev/null @@ -1,267 +0,0 @@ -/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $ - * - * low level stuff for the following AVM cards: - * A1 PCMCIA - * FRITZ!Card PCMCIA - * FRITZ!Card PCMCIA 2.0 - * - * Author Carsten Paeth - * Copyright by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -/* register offsets */ -#define ADDRREG_OFFSET 0x02 -#define DATAREG_OFFSET 0x03 -#define ASL0_OFFSET 0x04 -#define ASL1_OFFSET 0x05 -#define MODREG_OFFSET 0x06 -#define VERREG_OFFSET 0x07 - -/* address offsets */ -#define ISAC_FIFO_OFFSET 0x00 -#define ISAC_REG_OFFSET 0x20 -#define HSCX_CH_DIFF 0x40 -#define HSCX_FIFO_OFFSET 0x80 -#define HSCX_REG_OFFSET 0xa0 - -/* read bits ASL0 */ -#define ASL0_R_TIMER 0x10 /* active low */ -#define ASL0_R_ISAC 0x20 /* active low */ -#define ASL0_R_HSCX 0x40 /* active low */ -#define ASL0_R_TESTBIT 0x80 -#define ASL0_R_IRQPENDING (ASL0_R_ISAC | ASL0_R_HSCX | ASL0_R_TIMER) - -/* write bits ASL0 */ -#define ASL0_W_RESET 0x01 -#define ASL0_W_TDISABLE 0x02 -#define ASL0_W_TRESET 0x04 -#define ASL0_W_IRQENABLE 0x08 -#define ASL0_W_TESTBIT 0x80 - -/* write bits ASL1 */ -#define ASL1_W_LED0 0x10 -#define ASL1_W_LED1 0x20 -#define ASL1_W_ENABLE_S0 0xC0 - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static const char *avm_revision = "$Revision: 2.9.2.5 $"; - -static inline u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - u_char ret; - - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset); - ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET); - return ret; -} - -static inline void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset); - byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value); -} - -static inline void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET); - insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -static inline void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET); - outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -static inline u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - u_char ret; - - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset); - ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET); - return ret; -} - -static inline void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset); - byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value); -} - -static inline void -ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF); - insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -static inline void -WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF); - outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -avm_a1p_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - while ((sval = (~bytein(cs->hw.avm.cfg_reg + ASL0_OFFSET) & ASL0_R_IRQPENDING))) { - if (cs->debug & L1_DEB_INTSTAT) - debugl1(cs, "avm IntStatus %x", sval); - if (sval & ASL0_R_HSCX) { - val = ReadHSCX(cs, 1, HSCX_ISTA); - if (val) - hscx_int_main(cs, val); - } - if (sval & ASL0_R_ISAC) { - val = ReadISAC(cs, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); - } - } - WriteHSCX(cs, 0, HSCX_MASK, 0xff); - WriteHSCX(cs, 1, HSCX_MASK, 0xff); - WriteISAC(cs, ISAC_MASK, 0xff); - WriteISAC(cs, ISAC_MASK, 0x00); - WriteHSCX(cs, 0, HSCX_MASK, 0x00); - WriteHSCX(cs, 1, HSCX_MASK, 0x00); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static int -AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - - case CARD_RELEASE: - /* free_irq is done in HiSax_closecard(). */ - /* free_irq(cs->irq, cs); */ - return 0; - - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET | ASL0_W_IRQENABLE); - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - inithscxisac(cs, 1); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - - case CARD_TEST: - /* we really don't need it for the PCMCIA Version */ - return 0; - - default: - /* all card drivers ignore others, so we do the same */ - return 0; - } - return 0; -} - -int setup_avm_a1_pcmcia(struct IsdnCard *card) -{ - u_char model, vers; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - - strcpy(tmp, avm_revision); - printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n", - HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_A1_PCMCIA) - return (0); - - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - - - byteout(cs->hw.avm.cfg_reg + ASL1_OFFSET, ASL1_W_ENABLE_S0); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET); - - model = bytein(cs->hw.avm.cfg_reg + MODREG_OFFSET); - vers = bytein(cs->hw.avm.cfg_reg + VERREG_OFFSET); - - printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n", - cs->hw.avm.cfg_reg, cs->irq, model, vers); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &AVM_card_msg; - cs->irq_flags = IRQF_SHARED; - cs->irq_func = &avm_a1p_interrupt; - - ISACVersion(cs, "AVM A1 PCMCIA:"); - if (HscxVersion(cs, "AVM A1 PCMCIA:")) { - printk(KERN_WARNING - "AVM A1 PCMCIA: wrong HSCX versions check IO address\n"); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c deleted file mode 100644 index b161456c942e..000000000000 --- a/drivers/isdn/hisax/avm_pci.c +++ /dev/null @@ -1,904 +0,0 @@ -/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $ - * - * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to AVM, Berlin for information - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include -#include -#include -#include - -static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; - -#define AVM_FRITZ_PCI 1 -#define AVM_FRITZ_PNP 2 - -#define HDLC_FIFO 0x0 -#define HDLC_STATUS 0x4 - -#define AVM_HDLC_1 0x00 -#define AVM_HDLC_2 0x01 -#define AVM_ISAC_FIFO 0x02 -#define AVM_ISAC_REG_LOW 0x04 -#define AVM_ISAC_REG_HIGH 0x06 - -#define AVM_STATUS0_IRQ_ISAC 0x01 -#define AVM_STATUS0_IRQ_HDLC 0x02 -#define AVM_STATUS0_IRQ_TIMER 0x04 -#define AVM_STATUS0_IRQ_MASK 0x07 - -#define AVM_STATUS0_RESET 0x01 -#define AVM_STATUS0_DIS_TIMER 0x02 -#define AVM_STATUS0_RES_TIMER 0x04 -#define AVM_STATUS0_ENA_IRQ 0x08 -#define AVM_STATUS0_TESTBIT 0x10 - -#define AVM_STATUS1_INT_SEL 0x0f -#define AVM_STATUS1_ENA_IOM 0x80 - -#define HDLC_MODE_ITF_FLG 0x01 -#define HDLC_MODE_TRANS 0x02 -#define HDLC_MODE_CCR_7 0x04 -#define HDLC_MODE_CCR_16 0x08 -#define HDLC_MODE_TESTLOOP 0x80 - -#define HDLC_INT_XPR 0x80 -#define HDLC_INT_XDU 0x40 -#define HDLC_INT_RPR 0x20 -#define HDLC_INT_MASK 0xE0 - -#define HDLC_STAT_RME 0x01 -#define HDLC_STAT_RDO 0x10 -#define HDLC_STAT_CRCVFRRAB 0x0E -#define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK 0x3f00 - -#define HDLC_CMD_XRS 0x80 -#define HDLC_CMD_XME 0x01 -#define HDLC_CMD_RRS 0x20 -#define HDLC_CMD_XML_MASK 0x3f00 - - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - register u_char val; - - outb(idx, cs->hw.avm.cfg_reg + 4); - val = inb(cs->hw.avm.isac + (offset & 0xf)); - return (val); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - - outb(idx, cs->hw.avm.cfg_reg + 4); - outb(value, cs->hw.avm.isac + (offset & 0xf)); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); - insb(cs->hw.avm.isac, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); - outsb(cs->hw.avm.isac, data, size); -} - -static inline u_int -ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset) -{ - register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - register u_int val; - - outl(idx, cs->hw.avm.cfg_reg + 4); - val = inl(cs->hw.avm.isac + offset); - return (val); -} - -static inline void -WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value) -{ - register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - - outl(idx, cs->hw.avm.cfg_reg + 4); - outl(value, cs->hw.avm.isac + offset); -} - -static inline u_char -ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset) -{ - register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - register u_char val; - - outb(idx, cs->hw.avm.cfg_reg + 4); - val = inb(cs->hw.avm.isac + offset); - return (val); -} - -static inline void -WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value) -{ - register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - - outb(idx, cs->hw.avm.cfg_reg + 4); - outb(value, cs->hw.avm.isac + offset); -} - -static u_char -ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset) -{ - return (0xff & ReadHDLCPCI(cs, chan, offset)); -} - -static void -WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value) -{ - WriteHDLCPCI(cs, chan, offset, value); -} - -static inline -struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -static void -write_ctrl(struct BCState *bcs, int which) { - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl); - if (bcs->cs->subtyp == AVM_FRITZ_PCI) { - WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl); - } else { - if (which & 4) - WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2, - bcs->hw.hdlc.ctrl.sr.mode); - if (which & 2) - WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1, - bcs->hw.hdlc.ctrl.sr.xml); - if (which & 1) - WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS, - bcs->hw.hdlc.ctrl.sr.cmd); - } -} - -static void -modehdlc(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int hdlc = bcs->channel; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d", - 'A' + hdlc, bcs->mode, mode, hdlc, bc); - bcs->hw.hdlc.ctrl.ctrl = 0; - switch (mode) { - case (-1): /* used for init */ - bcs->mode = 1; - bcs->channel = bc; - bc = 0; - /* fall through */ - case (L1_MODE_NULL): - if (bcs->mode == L1_MODE_NULL) - return; - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; - write_ctrl(bcs, 5); - bcs->mode = L1_MODE_NULL; - bcs->channel = bc; - break; - case (L1_MODE_TRANS): - bcs->mode = mode; - bcs->channel = bc; - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; - write_ctrl(bcs, 5); - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd = 0; - schedule_event(bcs, B_XMTBUFREADY); - break; - case (L1_MODE_HDLC): - bcs->mode = mode; - bcs->channel = bc; - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG; - write_ctrl(bcs, 5); - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd = 0; - schedule_event(bcs, B_XMTBUFREADY); - break; - } -} - -static inline void -hdlc_empty_fifo(struct BCState *bcs, int count) -{ - register u_int *ptr; - u_char *p; - u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1; - int cnt = 0; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hdlc_empty_fifo %d", count); - if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hdlc_empty_fifo: incoming packet too large"); - return; - } - p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; - ptr = (u_int *)p; - bcs->hw.hdlc.rcvidx += count; - if (cs->subtyp == AVM_FRITZ_PCI) { - outl(idx, cs->hw.avm.cfg_reg + 4); - while (cnt < count) { -#ifdef __powerpc__ - *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE)); -#else - *ptr++ = inl(cs->hw.avm.isac); -#endif /* __powerpc__ */ - cnt += 4; - } - } else { - outb(idx, cs->hw.avm.cfg_reg + 4); - while (cnt < count) { - *p++ = inb(cs->hw.avm.isac); - cnt++; - } - } - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - if (cs->subtyp == AVM_FRITZ_PNP) - p = (u_char *) ptr; - t += sprintf(t, "hdlc_empty_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); - QuickHex(t, p, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static inline void -hdlc_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int count, cnt = 0; - int fifo_size = 32; - u_char *p; - u_int *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hdlc_fill_fifo"); - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (bcs->tx_skb->len > fifo_size) { - count = fifo_size; - } else { - count = bcs->tx_skb->len; - if (bcs->mode != L1_MODE_TRANS) - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME; - } - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len); - p = bcs->tx_skb->data; - ptr = (u_int *)p; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hdlc.count += count; - bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count); - write_ctrl(bcs, 3); /* sets the correct index too */ - if (cs->subtyp == AVM_FRITZ_PCI) { - while (cnt < count) { -#ifdef __powerpc__ - out_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE), *ptr++); -#else - outl(*ptr++, cs->hw.avm.isac); -#endif /* __powerpc__ */ - cnt += 4; - } - } else { - while (cnt < count) { - outb(*p++, cs->hw.avm.isac); - cnt++; - } - } - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - if (cs->subtyp == AVM_FRITZ_PNP) - p = (u_char *) ptr; - t += sprintf(t, "hdlc_fill_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); - QuickHex(t, p, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -HDLC_irq(struct BCState *bcs, u_int stat) { - int len; - struct sk_buff *skb; - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); - if (stat & HDLC_INT_RPR) { - if (stat & HDLC_STAT_RDO) { - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "RDO"); - else - debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); - bcs->hw.hdlc.ctrl.sr.xml = 0; - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.rcvidx = 0; - } else { - if (!(len = (stat & HDLC_STAT_RML_MASK) >> 8)) - len = 32; - hdlc_empty_fifo(bcs, len); - if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { - if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) || - (bcs->mode == L1_MODE_TRANS)) { - if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx))) - printk(KERN_WARNING "HDLC: receive out of memory\n"); - else { - skb_put_data(skb, - bcs->hw.hdlc.rcvbuf, - bcs->hw.hdlc.rcvidx); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hdlc.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } else { - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "invalid frame"); - else - debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat); - bcs->hw.hdlc.rcvidx = 0; - } - } - } - } - if (stat & HDLC_INT_XDU) { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hdlc.count); - bcs->tx_cnt += bcs->hw.hdlc.count; - bcs->hw.hdlc.count = 0; - if (bcs->cs->debug & L1_DEB_WARN) - debugl1(bcs->cs, "ch%d XDU", bcs->channel); - } else if (bcs->cs->debug & L1_DEB_WARN) - debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel); - bcs->hw.hdlc.ctrl.sr.xml = 0; - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS; - write_ctrl(bcs, 1); - hdlc_fill_fifo(bcs); - } else if (stat & HDLC_INT_XPR) { - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - hdlc_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hdlc.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hdlc.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hdlc.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hdlc_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static inline void -HDLC_irq_main(struct IsdnCardState *cs) -{ - u_int stat; - struct BCState *bcs; - - if (cs->subtyp == AVM_FRITZ_PCI) { - stat = ReadHDLCPCI(cs, 0, HDLC_STATUS); - } else { - stat = ReadHDLCPnP(cs, 0, HDLC_STATUS); - if (stat & HDLC_INT_RPR) - stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS + 1)) << 8; - } - if (stat & HDLC_INT_MASK) { - if (!(bcs = Sel_BCS(cs, 0))) { - if (cs->debug) - debugl1(cs, "hdlc spurious channel 0 IRQ"); - } else - HDLC_irq(bcs, stat); - } - if (cs->subtyp == AVM_FRITZ_PCI) { - stat = ReadHDLCPCI(cs, 1, HDLC_STATUS); - } else { - stat = ReadHDLCPnP(cs, 1, HDLC_STATUS); - if (stat & HDLC_INT_RPR) - stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS + 1)) << 8; - } - if (stat & HDLC_INT_MASK) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hdlc spurious channel 1 IRQ"); - } else - HDLC_irq(bcs, stat); - } -} - -static void -hdlc_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hdlc.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hdlc.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - modehdlc(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - modehdlc(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_hdlcstate(struct BCState *bcs) -{ - modehdlc(bcs, 0, 0); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hdlc.rcvbuf); - bcs->hw.hdlc.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hdlc.rcvbuf\n"); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hdlc.rcvbuf); - bcs->hw.hdlc.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hdlc.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_hdlc(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hdlcstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hdlc_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -#if 0 -void __init -clear_pending_hdlc_ints(struct IsdnCardState *cs) -{ - u_int val; - - if (cs->subtyp == AVM_FRITZ_PCI) { - val = ReadHDLCPCI(cs, 0, HDLC_STATUS); - debugl1(cs, "HDLC 1 STA %x", val); - val = ReadHDLCPCI(cs, 1, HDLC_STATUS); - debugl1(cs, "HDLC 2 STA %x", val); - } else { - val = ReadHDLCPnP(cs, 0, HDLC_STATUS); - debugl1(cs, "HDLC 1 STA %x", val); - val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1); - debugl1(cs, "HDLC 1 RML %x", val); - val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2); - debugl1(cs, "HDLC 1 MODE %x", val); - val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3); - debugl1(cs, "HDLC 1 VIN %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS); - debugl1(cs, "HDLC 2 STA %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1); - debugl1(cs, "HDLC 2 RML %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2); - debugl1(cs, "HDLC 2 MODE %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3); - debugl1(cs, "HDLC 2 VIN %x", val); - } -} -#endif /* 0 */ - -static void -inithdlc(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_hdlc; - cs->bcs[1].BC_SetStack = setstack_hdlc; - cs->bcs[0].BC_Close = close_hdlcstate; - cs->bcs[1].BC_Close = close_hdlcstate; - modehdlc(cs->bcs, -1, 0); - modehdlc(cs->bcs + 1, -1, 1); -} - -static irqreturn_t -avm_pcipnp_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_long flags; - u_char val; - u_char sval; - - spin_lock_irqsave(&cs->lock, flags); - sval = inb(cs->hw.avm.cfg_reg + 2); - if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { - /* possible a shared IRQ reqest */ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (!(sval & AVM_STATUS0_IRQ_ISAC)) { - val = ReadISAC(cs, ISAC_ISTA); - isac_interrupt(cs, val); - } - if (!(sval & AVM_STATUS0_IRQ_HDLC)) { - HDLC_irq_main(cs); - } - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -reset_avmpcipnp(struct IsdnCardState *cs) -{ - printk(KERN_INFO "AVM PCI/PnP: reset\n"); - outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); - mdelay(10); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); - outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); - mdelay(10); - printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); -} - -static int -AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_avmpcipnp(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - outb(0, cs->hw.avm.cfg_reg + 2); - release_region(cs->hw.avm.cfg_reg, 32); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_avmpcipnp(cs); - clear_pending_isac_ints(cs); - initisac(cs); - inithdlc(cs); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER, - cs->hw.avm.cfg_reg + 2); - WriteISAC(cs, ISAC_MASK, 0); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | - AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); - /* RESET Receiver and Transmitter */ - WriteISAC(cs, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int avm_setup_rest(struct IsdnCardState *cs) -{ - u_int val, ver; - - cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; - if (!request_region(cs->hw.avm.cfg_reg, 32, - (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { - printk(KERN_WARNING - "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", - cs->hw.avm.cfg_reg, - cs->hw.avm.cfg_reg + 31); - return (0); - } - switch (cs->subtyp) { - case AVM_FRITZ_PCI: - val = inl(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM PCI: stat %#x\n", val); - printk(KERN_INFO "AVM PCI: Class %X Rev %d\n", - val & 0xff, (val >> 8) & 0xff); - cs->BC_Read_Reg = &ReadHDLC_s; - cs->BC_Write_Reg = &WriteHDLC_s; - break; - case AVM_FRITZ_PNP: - val = inb(cs->hw.avm.cfg_reg); - ver = inb(cs->hw.avm.cfg_reg + 1); - printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver); - cs->BC_Read_Reg = &ReadHDLCPnP; - cs->BC_Write_Reg = &WriteHDLCPnP; - break; - default: - printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp); - return (0); - } - printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n", - (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP", - cs->irq, cs->hw.avm.cfg_reg); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Send_Data = &hdlc_fill_fifo; - cs->cardmsg = &AVM_card_msg; - cs->irq_func = &avm_pcipnp_interrupt; - cs->writeisac(cs, ISAC_MASK, 0xFF); - ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); - return (1); -} - -#ifndef __ISAPNP__ - -static int avm_pnp_setup(struct IsdnCardState *cs) -{ - return (1); /* no-op: success */ -} - -#else - -static struct pnp_card *pnp_avm_c = NULL; - -static int avm_pnp_setup(struct IsdnCardState *cs) -{ - struct pnp_dev *pnp_avm_d = NULL; - - if (!isapnp_present()) - return (1); /* no-op: success */ - - if ((pnp_avm_c = pnp_find_card( - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; - - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (cs->irq == -1) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return (0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return (0); - } - cs->subtyp = AVM_FRITZ_PNP; - - return (2); /* goto 'ready' label */ - } - } - - return (1); -} - -#endif /* __ISAPNP__ */ - -#ifndef CONFIG_PCI - -static int avm_pci_setup(struct IsdnCardState *cs) -{ - return (1); /* no-op: success */ -} - -#else - -static struct pci_dev *dev_avm = NULL; - -static int avm_pci_setup(struct IsdnCardState *cs) -{ - if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - - if (pci_enable_device(dev_avm)) - return (0); - - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return (0); - } - - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return (0); - } - - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); - return (0); - } - - cs->irq_flags |= IRQF_SHARED; - - return (1); -} - -#endif /* CONFIG_PCI */ - -int setup_avm_pcipnp(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - int rc; - - strcpy(tmp, avm_pci_rev); - printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); - - if (cs->typ != ISDN_CTYPE_FRITZPCI) - return (0); - - if (card->para[1]) { - /* old manual method */ - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } - - rc = avm_pnp_setup(cs); - if (rc < 1) - return (0); - if (rc == 2) - goto ready; - - rc = avm_pci_setup(cs); - if (rc < 1) - return (0); - -ready: - return avm_setup_rest(cs); -} diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c deleted file mode 100644 index baad94ec1f4a..000000000000 --- a/drivers/isdn/hisax/avma1_cs.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * PCMCIA client driver for AVM A1 / Fritz!PCMCIA - * - * Author Carsten Paeth - * Copyright 1998-2001 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int isdnprot = 2; - -module_param(isdnprot, int, 0); - -/*====================================================================*/ - -static int avma1cs_config(struct pcmcia_device *link); -static void avma1cs_release(struct pcmcia_device *link); -static void avma1cs_detach(struct pcmcia_device *p_dev); - -static int avma1cs_probe(struct pcmcia_device *p_dev) -{ - dev_dbg(&p_dev->dev, "avma1cs_attach()\n"); - - /* General socket configuration */ - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - p_dev->config_index = 1; - p_dev->config_regs = PRESENT_OPTION; - - return avma1cs_config(p_dev); -} /* avma1cs_attach */ - -static void avma1cs_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); - avma1cs_release(link); - kfree(link->priv); -} /* avma1cs_detach */ - -static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->io_lines = 5; - - return pcmcia_request_io(p_dev); -} - - -static int avma1cs_config(struct pcmcia_device *link) -{ - int i = -1; - char devname[128]; - IsdnCard_t icard; - int busy = 0; - - dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link); - - devname[0] = 0; - if (link->prod_id[1]) - strlcpy(devname, link->prod_id[1], sizeof(devname)); - - if (pcmcia_loop_config(link, avma1cs_configcheck, NULL)) - return -ENODEV; - - do { - /* - * allocate an interrupt line - */ - if (!link->irq) { - /* undo */ - pcmcia_disable_device(link); - break; - } - - /* - * configure the PCMCIA socket - */ - i = pcmcia_enable_device(link); - if (i != 0) { - pcmcia_disable_device(link); - break; - } - - } while (0); - - /* If any step failed, release any partially configured state */ - if (i != 0) { - avma1cs_release(link); - return -ENODEV; - } - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = isdnprot; - icard.typ = ISDN_CTYPE_A1_PCMCIA; - - i = hisax_init_pcmcia(link, &busy, &icard); - if (i < 0) { - printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 " - "PCMCIA %d at i/o %#x\n", i, - (unsigned int) link->resource[0]->start); - avma1cs_release(link); - return -ENODEV; - } - link->priv = (void *) (unsigned long) i; - - return 0; -} /* avma1cs_config */ - -static void avma1cs_release(struct pcmcia_device *link) -{ - unsigned long minor = (unsigned long) link->priv; - - dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link); - - /* now unregister function with hisax */ - HiSax_closecard(minor); - - pcmcia_disable_device(link); -} /* avma1cs_release */ - -static const struct pcmcia_device_id avma1cs_ids[] = { - PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), - PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids); - -static struct pcmcia_driver avma1cs_driver = { - .owner = THIS_MODULE, - .name = "avma1_cs", - .probe = avma1cs_probe, - .remove = avma1cs_detach, - .id_table = avma1cs_ids, -}; -module_pcmcia_driver(avma1cs_driver); diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c deleted file mode 100644 index c360164bde1b..000000000000 --- a/drivers/isdn/hisax/bkm_a4t.c +++ /dev/null @@ -1,358 +0,0 @@ -/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $ - * - * low level stuff for T-Berkom A4T - * - * Author Roland Klabunde - * Copyright by Roland Klabunde - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "jade.h" -#include "isdnl1.h" -#include -#include "bkm_ax.h" - -static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $"; - - -static inline u_char -readreg(unsigned int ale, unsigned long adr, u_char off) -{ - register u_int ret; - unsigned int *po = (unsigned int *) adr; /* Postoffice */ - - *po = (GCS_2 | PO_WRITE | off); - __WAITI20__(po); - *po = (ale | PO_READ); - __WAITI20__(po); - ret = *po; - return ((unsigned char) ret); -} - - -static inline void -readfifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size) -{ - int i; - for (i = 0; i < size; i++) - *data++ = readreg(ale, adr, off); -} - - -static inline void -writereg(unsigned int ale, unsigned long adr, u_char off, u_char data) -{ - unsigned int *po = (unsigned int *) adr; /* Postoffice */ - *po = (GCS_2 | PO_WRITE | off); - __WAITI20__(po); - *po = (ale | PO_WRITE | data); - __WAITI20__(po); -} - - -static inline void -writefifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size) -{ - int i; - - for (i = 0; i < size; i++) - writereg(ale, adr, off, *data++); -} - - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); -} - -static u_char -ReadJADE(struct IsdnCardState *cs, int jade, u_char offset) -{ - return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)))); -} - -static void -WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value) -{ - writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value); -} - -/* - * fast interrupt JADE stuff goes here - */ - -#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80))) -#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data) - -#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) -#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) - -#include "jade_irq.c" - -static irqreturn_t -bkm_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val = 0; - u_long flags; - I20_REGISTER_FILE *pI20_Regs; - - spin_lock_irqsave(&cs->lock, flags); - pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - - /* ISDN interrupt pending? */ - if (pI20_Regs->i20IntStatus & intISDN) { - /* Reset the ISDN interrupt */ - pI20_Regs->i20IntStatus = intISDN; - /* Disable ISDN interrupt */ - pI20_Regs->i20IntCtrl &= ~intISDN; - /* Channel A first */ - val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80); - if (val) { - jade_int_main(cs, val, 0); - } - /* Channel B */ - val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0); - if (val) { - jade_int_main(cs, val, 1); - } - /* D-Channel */ - val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA); - if (val) { - isac_interrupt(cs, val); - } - /* Reenable ISDN interrupt */ - pI20_Regs->i20IntCtrl |= intISDN; - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } else { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } -} - -static void -release_io_bkm(struct IsdnCardState *cs) -{ - if (cs->hw.ax.base) { - iounmap((void *) cs->hw.ax.base); - cs->hw.ax.base = 0; - } -} - -static void -enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) -{ - if (cs->typ == ISDN_CTYPE_BKM_A4T) { - I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - if (bEnable) - pI20_Regs->i20IntCtrl |= (intISDN | intPCI); - else - /* CAUTION: This disables the video capture driver too */ - pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI); - } -} - -static void -reset_bkm(struct IsdnCardState *cs) -{ - if (cs->typ == ISDN_CTYPE_BKM_A4T) { - I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - /* Issue the I20 soft reset */ - pI20_Regs->i20SysControl = 0xFF; /* all in */ - mdelay(10); - /* Remove the soft reset */ - pI20_Regs->i20SysControl = sysRESET | 0xFF; - mdelay(10); - /* Set our configuration */ - pI20_Regs->i20SysControl = sysRESET | sysCFG; - /* Issue ISDN reset */ - pI20_Regs->i20GuestControl = guestWAIT_CFG | - g_A4T_JADE_RES | - g_A4T_ISAR_RES | - g_A4T_ISAC_RES | - g_A4T_JADE_BOOTR | - g_A4T_ISAR_BOOTR; - mdelay(10); - - /* Remove RESET state from ISDN */ - pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | - g_A4T_JADE_RES | - g_A4T_ISAR_RES); - mdelay(10); - } -} - -static int -BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - /* Disable ints */ - spin_lock_irqsave(&cs->lock, flags); - enable_bkm_int(cs, 0); - reset_bkm(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - /* Sanity */ - spin_lock_irqsave(&cs->lock, flags); - enable_bkm_int(cs, 0); - reset_bkm(cs); - spin_unlock_irqrestore(&cs->lock, flags); - release_io_bkm(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - clear_pending_isac_ints(cs); - clear_pending_jade_ints(cs); - initisac(cs); - initjade(cs); - /* Enable ints */ - enable_bkm_int(cs, 1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs, - u_int *found, u_int *pci_memaddr) -{ - u16 sub_sys; - u16 sub_vendor; - - sub_vendor = dev_a4t->subsystem_vendor; - sub_sys = dev_a4t->subsystem_device; - if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) { - if (pci_enable_device(dev_a4t)) - return (0); /* end loop & function */ - *found = 1; - *pci_memaddr = pci_resource_start(dev_a4t, 0); - cs->irq = dev_a4t->irq; - return (1); /* end loop */ - } - - return (-1); /* continue looping */ -} - -static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs, - u_int pci_memaddr) -{ - I20_REGISTER_FILE *pI20_Regs; - - if (!cs->irq) { /* IRQ range check ?? */ - printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n"); - return (0); - } - cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096); - /* Check suspecious address */ - pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { - printk(KERN_WARNING "HiSax: Telekom A4T address " - "%lx-%lx suspicious\n", - cs->hw.ax.base, cs->hw.ax.base + 4096); - iounmap((void *) cs->hw.ax.base); - cs->hw.ax.base = 0; - return (0); - } - cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; - cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; - cs->hw.ax.isac_ale = GCS_1; - cs->hw.ax.jade_ale = GCS_3; - - printk(KERN_INFO "HiSax: Telekom A4T: Card configured at " - "0x%lX IRQ %d\n", - cs->hw.ax.base, cs->irq); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadJADE; - cs->BC_Write_Reg = &WriteJADE; - cs->BC_Send_Data = &jade_fill_fifo; - cs->cardmsg = &BKM_card_msg; - cs->irq_func = &bkm_interrupt; - cs->irq_flags |= IRQF_SHARED; - ISACVersion(cs, "Telekom A4T:"); - /* Jade version */ - JadeVersion(cs, "Telekom A4T:"); - - return (1); -} - -static struct pci_dev *dev_a4t = NULL; - -int setup_bkm_a4t(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_int pci_memaddr = 0, found = 0; - int ret; - - strcpy(tmp, bkm_a4t_revision); - printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ == ISDN_CTYPE_BKM_A4T) { - cs->subtyp = BKM_A4T; - } else - return (0); - - while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, - PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { - ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr); - if (!ret) - return (0); - if (ret > 0) - break; - } - if (!found) { - printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n"); - return (0); - } - if (!pci_memaddr) { - printk(KERN_WARNING "HiSax: Telekom A4T: " - "No Memory base address\n"); - return (0); - } - - return a4t_cs_init(card, cs, pci_memaddr); -} diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c deleted file mode 100644 index dd663ea57ec6..000000000000 --- a/drivers/isdn/hisax/bkm_a8.c +++ /dev/null @@ -1,433 +0,0 @@ -/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $ - * - * low level stuff for Scitel Quadro (4*S0, passive) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include -#include "hisax.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isdnl1.h" -#include -#include "bkm_ax.h" - -#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ - -static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $"; - -static const char *sct_quadro_subtypes[] = -{ - "", - "#1", - "#2", - "#3", - "#4" -}; - - -#define wordout(addr, val) outw(val, addr) -#define wordin(addr) inw(addr) - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - wordout(ale, off); - ret = wordin(adr) & 0xFF; - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - int i; - wordout(ale, off); - for (i = 0; i < size; i++) - data[i] = wordin(adr) & 0xFF; -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - wordout(ale, off); - wordout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - int i; - wordout(ale, off); - for (i = 0; i < size; i++) - wordout(adr, data[i]); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); -} - - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); -} - -/* Set the specific ipac to active */ -static void -set_ipac_active(struct IsdnCardState *cs, u_int active) -{ - /* set irq mask */ - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, - active ? 0xc0 : 0xff); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \ - cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \ - cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data) -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \ - cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \ - cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -bkm_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val, icnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - if (!(ista & 0x3f)) { /* not this IPAC */ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) { - hscx_int_main(cs, val); - } - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "HiSax: Scitel Quadro (%s) IRQ LOOP\n", - sct_quadro_subtypes[cs->subtyp]); - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_sct_quadro(struct IsdnCardState *cs) -{ - release_region(cs->hw.ax.base & 0xffffffc0, 128); - if (cs->subtyp == SCT_1) - release_region(cs->hw.ax.plx_adr, 64); -} - -static void -enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) -{ - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - if (bEnable) - wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); - else - wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); - } -} - -static void -reset_bkm(struct IsdnCardState *cs) -{ - if (cs->subtyp == SCT_1) { - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - mdelay(10); - /* Remove the soft reset */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - mdelay(10); - } -} - -static int -BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - /* Disable ints */ - set_ipac_active(cs, 0); - enable_bkm_int(cs, 0); - reset_bkm(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - /* Sanity */ - spin_lock_irqsave(&cs->lock, flags); - set_ipac_active(cs, 0); - enable_bkm_int(cs, 0); - spin_unlock_irqrestore(&cs->lock, flags); - release_io_sct_quadro(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs, 1); - inithscxisac(cs, 3); - /* Enable ints */ - enable_bkm_int(cs, 1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int sct_alloc_io(u_int adr, u_int len) -{ - if (!request_region(adr, len, "scitel")) { - printk(KERN_WARNING - "HiSax: Scitel port %#x-%#x already in use\n", - adr, adr + len); - return (1); - } - return (0); -} - -static struct pci_dev *dev_a8 = NULL; -static u16 sub_vendor_id = 0; -static u16 sub_sys_id = 0; -static u_char pci_bus = 0; -static u_char pci_device_fn = 0; -static u_char pci_irq = 0; - -int setup_sct_quadro(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_int found = 0; - u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; - - strcpy(tmp, sct_quadro_revision); - printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - cs->subtyp = SCT_1; /* Preset */ - } else - return (0); - - /* Identify subtype by para[0] */ - if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) - cs->subtyp = card->para[0]; - else { - printk(KERN_WARNING "HiSax: Scitel Quadro: Invalid " - "subcontroller in configuration, default to 1\n"); - return (0); - } - if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) || - (sub_vendor_id != PCI_VENDOR_ID_BERKOM))) - return (0); - if (cs->subtyp == SCT_1) { - while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX, - PCI_DEVICE_ID_PLX_9050, dev_a8))) { - - sub_vendor_id = dev_a8->subsystem_vendor; - sub_sys_id = dev_a8->subsystem_device; - if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) && - (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) { - if (pci_enable_device(dev_a8)) - return (0); - pci_ioaddr1 = pci_resource_start(dev_a8, 1); - pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; - found = 1; - break; - } - } - if (!found) { - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): " - "Card not found\n", - sct_quadro_subtypes[cs->subtyp]); - return (0); - } -#ifdef ATTEMPT_PCI_REMAPPING -/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) { - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): " - "PLX rev 1, remapping required!\n", - sct_quadro_subtypes[cs->subtyp]); - /* Restart PCI negotiation */ - pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int)-1); - /* Move up by 0x80 byte */ - pci_ioaddr1 += 0x80; - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1); - dev_a8->resource[1].start = pci_ioaddr1; - } -#endif /* End HACK */ - } - if (!pci_irq) { /* IRQ range check ?? */ - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): No IRQ\n", - sct_quadro_subtypes[cs->subtyp]); - return (0); - } - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5); - if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) { - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): " - "No IO base address(es)\n", - sct_quadro_subtypes[cs->subtyp]); - return (0); - } - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK; - /* Take over */ - cs->irq = pci_irq; - cs->irq_flags |= IRQF_SHARED; - /* pci_ioaddr1 is unique to all subdevices */ - /* pci_ioaddr2 is for the fourth subdevice only */ - /* pci_ioaddr3 is for the third subdevice only */ - /* pci_ioaddr4 is for the second subdevice only */ - /* pci_ioaddr5 is for the first subdevice only */ - cs->hw.ax.plx_adr = pci_ioaddr1; - /* Enter all ipac_base addresses */ - switch (cs->subtyp) { - case 1: - cs->hw.ax.base = pci_ioaddr5 + 0x00; - if (sct_alloc_io(pci_ioaddr1, 128)) - return (0); - if (sct_alloc_io(pci_ioaddr5, 64)) - return (0); - /* disable all IPAC */ - writereg(pci_ioaddr5, pci_ioaddr5 + 4, - IPAC_MASK, 0xFF); - writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, - IPAC_MASK, 0xFF); - writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, - IPAC_MASK, 0xFF); - writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, - IPAC_MASK, 0xFF); - break; - case 2: - cs->hw.ax.base = pci_ioaddr4 + 0x08; - if (sct_alloc_io(pci_ioaddr4, 64)) - return (0); - break; - case 3: - cs->hw.ax.base = pci_ioaddr3 + 0x10; - if (sct_alloc_io(pci_ioaddr3, 64)) - return (0); - break; - case 4: - cs->hw.ax.base = pci_ioaddr2 + 0x20; - if (sct_alloc_io(pci_ioaddr2, 64)) - return (0); - break; - } - /* For isac and hscx data path */ - cs->hw.ax.data_adr = cs->hw.ax.base + 4; - - printk(KERN_INFO "HiSax: Scitel Quadro (%s) configured at " - "0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n", - sct_quadro_subtypes[cs->subtyp], - cs->hw.ax.plx_adr, - cs->hw.ax.base, - cs->hw.ax.data_adr, - cs->irq); - - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &BKM_card_msg; - cs->irq_func = &bkm_interrupt_ipac; - - printk(KERN_INFO "HiSax: Scitel Quadro (%s): IPAC Version %d\n", - sct_quadro_subtypes[cs->subtyp], - readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); - return (1); -} diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h deleted file mode 100644 index 27ff8a88679b..000000000000 --- a/drivers/isdn/hisax/bkm_ax.h +++ /dev/null @@ -1,119 +0,0 @@ -/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $ - * - * low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __BKM_AX_H__ -#define __BKM_AX_H__ - -/* Supported boards (subtypes) */ -#define SCT_1 1 -#define SCT_2 2 -#define SCT_3 3 -#define SCT_4 4 -#define BKM_A4T 5 - -#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */ -#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */ -#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */ -#define PLX_ADDR_ALE 0x20 /* Addr ALE */ -#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */ - -#define PLX_SUBVEN 0x2C /* Offset SubVendor */ -#define PLX_SUBSYS 0x2E /* Offset SubSystem */ - - -/* Application specific registers I20 (Siemens SZB6120H) */ -typedef struct { - /* Video front end horizontal configuration register */ - volatile u_int i20VFEHorzCfg; /* Offset 00 */ - /* Video front end vertical configuration register */ - volatile u_int i20VFEVertCfg; /* Offset 04 */ - /* Video front end scaler and pixel format register */ - volatile u_int i20VFEScaler; /* Offset 08 */ - /* Video display top register */ - volatile u_int i20VDispTop; /* Offset 0C */ - /* Video display bottom register */ - volatile u_int i20VDispBottom; /* Offset 10 */ - /* Video stride, status and frame grab register */ - volatile u_int i20VidFrameGrab;/* Offset 14 */ - /* Video display configuration register */ - volatile u_int i20VDispCfg; /* Offset 18 */ - /* Video masking map top */ - volatile u_int i20VMaskTop; /* Offset 1C */ - /* Video masking map bottom */ - volatile u_int i20VMaskBottom; /* Offset 20 */ - /* Overlay control register */ - volatile u_int i20OvlyControl; /* Offset 24 */ - /* System, PCI and general purpose pins control register */ - volatile u_int i20SysControl; /* Offset 28 */ -#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */ - /* GPIO 4...0: Output fixed for our cfg! */ -#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */ - /* General purpose pins and guest bus control register */ - volatile u_int i20GuestControl;/* Offset 2C */ -#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */ -#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */ -#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */ -#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */ -#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */ -#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */ -#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */ -#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */ -#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */ - -#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */ -#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */ -#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */ -#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */ -#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */ -#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */ -#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */ -#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */ - - volatile u_int i20CodeSource; /* Offset 30 */ - volatile u_int i20CodeXferCtrl;/* Offset 34 */ - volatile u_int i20CodeMemPtr; /* Offset 38 */ - - volatile u_int i20IntStatus; /* Offset 3C */ - volatile u_int i20IntCtrl; /* Offset 40 */ -#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */ -#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */ -#define intCOD 0x10000000 /* CodRepIrqEn (High) */ -#define intPCI 0x01000000 /* PCI IntA enable (High) */ - - volatile u_int i20I2CCtrl; /* Offset 44 */ -} I20_REGISTER_FILE, *PI20_REGISTER_FILE; - -/* - * Postoffice structure for A4T - * - */ -#define PO_OFFSET 0x00000200 /* Postoffice offset from base */ - -#define GCS_0 0x00000000 /* Guest bus chip selects */ -#define GCS_1 0x00100000 -#define GCS_2 0x00200000 -#define GCS_3 0x00300000 - -#define PO_READ 0x00000000 /* R/W from/to guest bus */ -#define PO_WRITE 0x00800000 - -#define PO_PEND 0x02000000 - -#define POSTOFFICE(postoffice) *(volatile unsigned int *)(postoffice) - -/* Wait unlimited (don't worry) */ -#define __WAITI20__(postoffice) \ - do { \ - while ((POSTOFFICE(postoffice) & PO_PEND)) ; \ - } while (0) - -#endif /* __BKM_AX_H__ */ diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c deleted file mode 100644 index 9ee06328784c..000000000000 --- a/drivers/isdn/hisax/callc.c +++ /dev/null @@ -1,1792 +0,0 @@ -/* $Id: callc.c,v 2.59.2.4 2004/02/11 13:21:32 keil Exp $ - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * based on the teles driver from Jan den Ouden - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include -#include -#include -#include "hisax.h" -#include - -const char *lli_revision = "$Revision: 2.59.2.4 $"; - -extern struct IsdnCard cards[]; - -static int init_b_st(struct Channel *chanp, int incoming); -static void release_b_st(struct Channel *chanp); - -static struct Fsm callcfsm; -static int chancount; - -/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ -#define ALERT_REJECT 0 - -/* Value to delay the sending of the first B-channel packet after CONNECT - * here is no value given by ITU, but experience shows that 300 ms will - * work on many networks, if you or your other side is behind local exchanges - * a greater value may be recommented. If the delay is to short the first paket - * will be lost and autodetect on many comercial routers goes wrong ! - * You can adjust this value on runtime with - * hisaxctrl 2 - * value is in milliseconds - */ -#define DEFAULT_B_DELAY 300 - -/* Flags for remembering action done in lli */ - -#define FLG_START_B 0 - -/* - * Find card with given driverId - */ -static inline struct IsdnCardState * -hisax_findcard(int driverid) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].cs) - if (cards[i].cs->myid == driverid) - return (cards[i].cs); - return (struct IsdnCardState *) 0; -} - -static __printf(3, 4) void - link_debug(struct Channel *chanp, int direction, char *fmt, ...) -{ - va_list args; - char tmp[16]; - - va_start(args, fmt); - sprintf(tmp, "Ch%d %s ", chanp->chan, - direction ? "LL->HL" : "HL->LL"); - VHiSax_putstatus(chanp->cs, tmp, fmt, args); - va_end(args); -} - -enum { - ST_NULL, /* 0 inactive */ - ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */ - ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */ - ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */ - ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */ - ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ - ST_ACTIVE, /* 6 active, b channel prot. established */ - ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */ - ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */ - ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */ - ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */ - ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */ - ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */ -}; - - -#define STATE_COUNT (ST_IN_PROCEED_SEND + 1) - -static char *strState[] = -{ - "ST_NULL", - "ST_OUT_DIAL", - "ST_IN_WAIT_LL", - "ST_IN_ALERT_SENT", - "ST_IN_WAIT_CONN_ACK", - "ST_WAIT_BCONN", - "ST_ACTIVE", - "ST_WAIT_BRELEASE", - "ST_WAIT_BREL_DISC", - "ST_WAIT_DCOMMAND", - "ST_WAIT_DRELEASE", - "ST_WAIT_D_REL_CNF", - "ST_IN_PROCEED_SEND", -}; - -enum { - EV_DIAL, /* 0 */ - EV_SETUP_CNF, /* 1 */ - EV_ACCEPTB, /* 2 */ - EV_DISCONNECT_IND, /* 3 */ - EV_RELEASE, /* 4 */ - EV_LEASED, /* 5 */ - EV_LEASED_REL, /* 6 */ - EV_SETUP_IND, /* 7 */ - EV_ACCEPTD, /* 8 */ - EV_SETUP_CMPL_IND, /* 9 */ - EV_BC_EST, /* 10 */ - EV_WRITEBUF, /* 11 */ - EV_HANGUP, /* 12 */ - EV_BC_REL, /* 13 */ - EV_CINF, /* 14 */ - EV_SUSPEND, /* 15 */ - EV_RESUME, /* 16 */ - EV_NOSETUP_RSP, /* 17 */ - EV_SETUP_ERR, /* 18 */ - EV_CONNECT_ERR, /* 19 */ - EV_PROCEED, /* 20 */ - EV_ALERT, /* 21 */ - EV_REDIR, /* 22 */ -}; - -#define EVENT_COUNT (EV_REDIR + 1) - -static char *strEvent[] = -{ - "EV_DIAL", - "EV_SETUP_CNF", - "EV_ACCEPTB", - "EV_DISCONNECT_IND", - "EV_RELEASE", - "EV_LEASED", - "EV_LEASED_REL", - "EV_SETUP_IND", - "EV_ACCEPTD", - "EV_SETUP_CMPL_IND", - "EV_BC_EST", - "EV_WRITEBUF", - "EV_HANGUP", - "EV_BC_REL", - "EV_CINF", - "EV_SUSPEND", - "EV_RESUME", - "EV_NOSETUP_RSP", - "EV_SETUP_ERR", - "EV_CONNECT_ERR", - "EV_PROCEED", - "EV_ALERT", - "EV_REDIR", -}; - - -static inline void -HL_LL(struct Channel *chanp, int command) -{ - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = command; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); -} - -static inline void -lli_deliver_cause(struct Channel *chanp) -{ - isdn_ctrl ic; - - if (!chanp->proc) - return; - if (chanp->proc->para.cause == NO_CAUSE) - return; - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - if (chanp->cs->protocol == ISDN_PTYPE_EURO) - sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f, - chanp->proc->para.cause & 0x7f); - else - sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f, - chanp->proc->para.cause & 0x7f); - chanp->cs->iif.statcallb(&ic); -} - -static inline void -lli_close(struct FsmInst *fi) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); -} - -static void -lli_leased_in(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - int ret; - - if (!chanp->leased) - return; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_IN_WAIT_LL); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_ICALL_LEASED"); - ic.driver = chanp->cs->myid; - ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); - ic.arg = chanp->chan; - ic.parm.setup.si1 = 7; - ic.parm.setup.si2 = 0; - ic.parm.setup.plan = 0; - ic.parm.setup.screen = 0; - sprintf(ic.parm.setup.eazmsn, "%d", chanp->chan + 1); - sprintf(ic.parm.setup.phone, "LEASED%d", chanp->cs->myid); - ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 1, "statcallb ret=%d", ret); - if (!ret) { - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_NULL); - } -} - - -/* - * Dial out - */ -static void -lli_init_bchan_out(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_BCONN); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DCONN"); - HL_LL(chanp, ISDN_STAT_DCONN); - init_b_st(chanp, 0); - chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -lli_prep_dialout(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmDelTimer(&chanp->drel_timer, 60); - FsmDelTimer(&chanp->dial_timer, 73); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - if (chanp->leased) { - lli_init_bchan_out(fi, event, arg); - } else { - FsmChangeState(fi, ST_OUT_DIAL); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp); - } -} - -static void -lli_resume(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmDelTimer(&chanp->drel_timer, 60); - FsmDelTimer(&chanp->dial_timer, 73); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - if (chanp->leased) { - lli_init_bchan_out(fi, event, arg); - } else { - FsmChangeState(fi, ST_OUT_DIAL); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp); - } -} - -static void -lli_go_active(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - - FsmChangeState(fi, ST_ACTIVE); - chanp->data_open = !0; - if (chanp->bcs->conmsg) - strcpy(ic.parm.num, chanp->bcs->conmsg); - else - ic.parm.num[0] = 0; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BCONN %s", ic.parm.num); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BCONN; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan); -} - - -/* - * RESUME - */ - -/* incoming call */ - -static void -lli_deliver_call(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - int ret; - - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - /* - * Report incoming calls only once to linklevel, use CallFlags - * which is set to 3 with each broadcast message in isdnl1.c - * and resetted if a interface answered the STAT_ICALL. - */ - if (1) { /* for only one TEI */ - FsmChangeState(fi, ST_IN_WAIT_LL); - if (chanp->debug & 1) - link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW"); - ic.driver = chanp->cs->myid; - ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); - - ic.arg = chanp->chan; - /* - * No need to return "unknown" for calls without OAD, - * cause that's handled in linklevel now (replaced by '0') - */ - memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); - ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 1, "statcallb ret=%d", ret); - - switch (ret) { - case 1: /* OK, someone likes this call */ - FsmDelTimer(&chanp->drel_timer, 61); - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); - break; - case 5: /* direct redirect */ - case 4: /* Proceeding desired */ - FsmDelTimer(&chanp->drel_timer, 61); - FsmChangeState(fi, ST_IN_PROCEED_SEND); - chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); - if (ret == 5) { - memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); - chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); - } - break; - case 2: /* Rejecting Call */ - break; - case 3: /* incomplete number */ - FsmDelTimer(&chanp->drel_timer, 61); - chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); - break; - case 0: /* OK, nobody likes this call */ - default: /* statcallb problems */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_NULL); - break; - } - } else { - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - } -} - -static void -lli_send_dconnect(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); -} - -static void -lli_send_alert(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); -} - -static void -lli_send_redir(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); -} - -static void -lli_init_bchan_in(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_BCONN); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DCONN"); - HL_LL(chanp, ISDN_STAT_DCONN); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = !0; - init_b_st(chanp, !0); - chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -lli_setup_rsp(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_init_bchan_in(fi, event, arg); - } else { - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); -#ifdef WANT_ALERT - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); -#endif - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); - } -} - -/* Call suspend */ - -static void -lli_suspend(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc); -} - -/* Call clearing */ - -static void -lli_leased_hup(struct FsmInst *fi, struct Channel *chanp) -{ - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L0010"); - chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); -} - -static void -lli_disconnect_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (chanp->proc) - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, - chanp->proc); - } -} - -static void -lli_disconnect_reject(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (chanp->proc) - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, - chanp->proc); - } -} - -static void -lli_dhup_close(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - lli_deliver_cause(chanp); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); - } -} - -static void -lli_reject_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - return; - } -#ifndef ALERT_REJECT - if (chanp->proc) - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); - lli_dhup_close(fi, event, arg); -#else - FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); -#endif -} - -static void -lli_disconn_bchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_WAIT_BRELEASE); - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); -} - -static void -lli_start_disc(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - lli_disconnect_req(fi, event, arg); - } -} - -static void -lli_rel_b_disc(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_start_disc(fi, event, arg); -} - -static void -lli_bhup_disc(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_disc(fi, event, arg); -} - -static void -lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_DCOMMAND); - chanp->data_open = 0; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - release_b_st(chanp); -} - -static void -lli_release_bchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_WAIT_BREL_DISC); - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); -} - - -static void -lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_dhup_close(fi, event, arg); -} - -static void -lli_bhup_dhup(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_dhup(fi, event, arg); -} - -static void -lli_abort(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); - lli_bhup_dhup(fi, event, arg); -} - -static void -lli_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - FsmChangeState(fi, ST_WAIT_D_REL_CNF); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, - chanp->proc); - } -} - -static void -lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_release_req(fi, event, arg); -} - -static void -lli_bhup_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_release_req(fi, event, arg); -} - - -/* processing charge info */ -static void -lli_charge_info(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CINF; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo); - chanp->cs->iif.statcallb(&ic); -} - -/* error procedures */ - -static void -lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); -} - -static void -lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); -} - -static void -lli_error(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_WAIT_DRELEASE); -} - -static void -lli_failure_l(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - FsmChangeState(fi, ST_NULL); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f); - chanp->cs->iif.statcallb(&ic); - HL_LL(chanp, ISDN_STAT_DHUP); - chanp->Flags = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); -} - -static void -lli_rel_b_fail(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_failure_l(fi, event, arg); -} - -static void -lli_bhup_fail(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_fail(fi, event, arg); -} - -static void -lli_failure_a(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); - lli_bhup_fail(fi, event, arg); -} - -/* *INDENT-OFF* */ -static struct FsmNode fnlist[] __initdata = -{ - {ST_NULL, EV_DIAL, lli_prep_dialout}, - {ST_NULL, EV_RESUME, lli_resume}, - {ST_NULL, EV_SETUP_IND, lli_deliver_call}, - {ST_NULL, EV_LEASED, lli_leased_in}, - {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out}, - {ST_OUT_DIAL, EV_HANGUP, lli_disconnect_req}, - {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req}, - {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close}, - {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp}, - {ST_OUT_DIAL, EV_SETUP_ERR, lli_error}, - {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l}, - {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp}, - {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, - {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, - {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, - {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call}, - {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error}, - {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, - {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, - {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, - {ST_IN_ALERT_SENT, EV_DISCONNECT_IND, lli_release_req}, - {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close}, - {ST_IN_ALERT_SENT, EV_REDIR, lli_send_redir}, - {ST_IN_PROCEED_SEND, EV_REDIR, lli_send_redir}, - {ST_IN_PROCEED_SEND, EV_ALERT, lli_send_alert}, - {ST_IN_PROCEED_SEND, EV_ACCEPTD, lli_send_dconnect}, - {ST_IN_PROCEED_SEND, EV_HANGUP, lli_disconnect_reject}, - {ST_IN_PROCEED_SEND, EV_DISCONNECT_IND, lli_dhup_close}, - {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close}, - {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in}, - {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_disconnect_req}, - {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_release_req}, - {ST_IN_WAIT_CONN_ACK, EV_RELEASE, lli_dhup_close}, - {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_error}, - {ST_WAIT_BCONN, EV_BC_EST, lli_go_active}, - {ST_WAIT_BCONN, EV_BC_REL, lli_rel_b_disc}, - {ST_WAIT_BCONN, EV_HANGUP, lli_rel_b_disc}, - {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_rel_b_release_req}, - {ST_WAIT_BCONN, EV_RELEASE, lli_rel_b_dhup}, - {ST_WAIT_BCONN, EV_LEASED_REL, lli_rel_b_fail}, - {ST_WAIT_BCONN, EV_CINF, lli_charge_info}, - {ST_ACTIVE, EV_CINF, lli_charge_info}, - {ST_ACTIVE, EV_BC_REL, lli_bhup_rel_b}, - {ST_ACTIVE, EV_SUSPEND, lli_suspend}, - {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan}, - {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan}, - {ST_ACTIVE, EV_RELEASE, lli_abort}, - {ST_ACTIVE, EV_LEASED_REL, lli_failure_a}, - {ST_WAIT_BRELEASE, EV_BC_REL, lli_bhup_disc}, - {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_bhup_release_req}, - {ST_WAIT_BRELEASE, EV_RELEASE, lli_bhup_dhup}, - {ST_WAIT_BRELEASE, EV_LEASED_REL, lli_bhup_fail}, - {ST_WAIT_BREL_DISC, EV_BC_REL, lli_bhup_release_req}, - {ST_WAIT_BREL_DISC, EV_RELEASE, lli_bhup_dhup}, - {ST_WAIT_DCOMMAND, EV_HANGUP, lli_start_disc}, - {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_release_req}, - {ST_WAIT_DCOMMAND, EV_RELEASE, lli_dhup_close}, - {ST_WAIT_DCOMMAND, EV_LEASED_REL, lli_failure_l}, - {ST_WAIT_DRELEASE, EV_RELEASE, lli_dhup_close}, - {ST_WAIT_DRELEASE, EV_DIAL, lli_dchan_not_ready}, - /* ETS 300-104 16.1 */ - {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close}, - {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready}, -}; -/* *INDENT-ON* */ - -int __init -CallcNew(void) -{ - callcfsm.state_count = STATE_COUNT; - callcfsm.event_count = EVENT_COUNT; - callcfsm.strEvent = strEvent; - callcfsm.strState = strState; - return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist)); -} - -void -CallcFree(void) -{ - FsmFree(&callcfsm); -} - -static void -release_b_st(struct Channel *chanp) -{ - struct PStack *st = chanp->b_st; - - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) { - chanp->bcs->BC_Close(chanp->bcs); - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - releasestack_isdnl2(st); - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_HDLC_56K): - case (ISDN_PROTO_L2_TRANS): - case (ISDN_PROTO_L2_MODEM): - case (ISDN_PROTO_L2_FAX): - releasestack_transl2(st); - break; - } - } -} - -static struct Channel -*selectfreechannel(struct PStack *st, int bch) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct Channel *chanp = st->lli.userdata; - int i; - - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) - i = 1; - else - i = 0; - - if (!bch) { - i = 2; /* virtual channel */ - chanp += 2; - } - - while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) { - if (chanp->fi.state == ST_NULL) - return (chanp); - chanp++; - i++; - } - - if (bch) /* number of channels is limited */ { - i = 2; /* virtual channel */ - chanp = st->lli.userdata; - chanp += i; - while (i < (2 + MAX_WAITING_CALLS)) { - if (chanp->fi.state == ST_NULL) - return (chanp); - chanp++; - i++; - } - } - return (NULL); -} - -static void stat_redir_result(struct IsdnCardState *cs, int chan, ulong result) -{ isdn_ctrl ic; - - ic.driver = cs->myid; - ic.command = ISDN_STAT_REDIR; - ic.arg = chan; - ic.parm.num[0] = result; - cs->iif.statcallb(&ic); -} /* stat_redir_result */ - -static void -dchan_l3l4(struct PStack *st, int pr, void *arg) -{ - struct l3_process *pc = arg; - struct IsdnCardState *cs = st->l1.hardware; - struct Channel *chanp; - - if (!pc) - return; - - if (pr == (CC_SETUP | INDICATION)) { - if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) { - pc->para.cause = 0x11; /* User busy */ - pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc); - } else { - chanp->proc = pc; - pc->chan = chanp; - FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - } - return; - } - if (!(chanp = pc->chan)) - return; - - switch (pr) { - case (CC_MORE_INFO | INDICATION): - FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - break; - case (CC_DISCONNECT | INDICATION): - FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); - break; - case (CC_RELEASE | CONFIRM): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_SUSPEND | CONFIRM): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_RESUME | CONFIRM): - FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); - break; - case (CC_RESUME_ERR): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_RELEASE | INDICATION): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_SETUP_COMPL | INDICATION): - FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); - break; - case (CC_SETUP | CONFIRM): - FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); - break; - case (CC_CHARGE | INDICATION): - FsmEvent(&chanp->fi, EV_CINF, NULL); - break; - case (CC_NOSETUP_RSP): - FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL); - break; - case (CC_SETUP_ERR): - FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL); - break; - case (CC_CONNECT_ERR): - FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL); - break; - case (CC_RELEASE_ERR): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_PROCEED_SEND | INDICATION): - case (CC_PROCEEDING | INDICATION): - case (CC_ALERTING | INDICATION): - case (CC_PROGRESS | INDICATION): - case (CC_NOTIFY | INDICATION): - break; - case (CC_REDIR | INDICATION): - stat_redir_result(cs, chanp->chan, pc->redir_result); - break; - default: - if (chanp->debug & 0x800) { - HiSax_putstatus(chanp->cs, "Ch", - "%d L3->L4 unknown primitiv %#x", - chanp->chan, pr); - } - } -} - -static void -dummy_pstack(struct PStack *st, int pr, void *arg) { - printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg); -} - -static int -init_PStack(struct PStack **stp) { - *stp = kmalloc(sizeof(struct PStack), GFP_KERNEL); - if (!*stp) - return -ENOMEM; - (*stp)->next = NULL; - (*stp)->l1.l1l2 = dummy_pstack; - (*stp)->l1.l1hw = dummy_pstack; - (*stp)->l1.l1tei = dummy_pstack; - (*stp)->l2.l2tei = dummy_pstack; - (*stp)->l2.l2l1 = dummy_pstack; - (*stp)->l2.l2l3 = dummy_pstack; - (*stp)->l3.l3l2 = dummy_pstack; - (*stp)->l3.l3ml3 = dummy_pstack; - (*stp)->l3.l3l4 = dummy_pstack; - (*stp)->lli.l4l3 = dummy_pstack; - (*stp)->ma.layer = dummy_pstack; - return 0; -} - -static int -init_d_st(struct Channel *chanp) -{ - struct PStack *st; - struct IsdnCardState *cs = chanp->cs; - char tmp[16]; - int err; - - err = init_PStack(&chanp->d_st); - if (err) - return err; - st = chanp->d_st; - st->next = NULL; - HiSax_addlist(cs, st); - setstack_HiSax(st, cs); - st->l2.sap = 0; - st->l2.tei = -1; - st->l2.flag = 0; - test_and_set_bit(FLG_MOD128, &st->l2.flag); - test_and_set_bit(FLG_LAPD, &st->l2.flag); - test_and_set_bit(FLG_ORIG, &st->l2.flag); - st->l2.maxlen = MAX_DFRAME_LEN; - st->l2.window = 1; - st->l2.T200 = 1000; /* 1000 milliseconds */ - st->l2.N200 = 3; /* try 3 times */ - st->l2.T203 = 10000; /* 10000 milliseconds */ - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) - sprintf(tmp, "DCh%d Q.921 ", chanp->chan); - else - sprintf(tmp, "DCh Q.921 "); - setstack_isdnl2(st, tmp); - setstack_l3dc(st, chanp); - st->lli.userdata = chanp; - st->l3.l3l4 = dchan_l3l4; - - return 0; -} - -static __printf(2, 3) void - callc_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct Channel *chanp = fi->userdata; - char tmp[16]; - - va_start(args, fmt); - sprintf(tmp, "Ch%d callc ", chanp->chan); - VHiSax_putstatus(chanp->cs, tmp, fmt, args); - va_end(args); -} - -static int -init_chan(int chan, struct IsdnCardState *csta) -{ - struct Channel *chanp = csta->channel + chan; - int err; - - chanp->cs = csta; - chanp->bcs = csta->bcs + chan; - chanp->chan = chan; - chanp->incoming = 0; - chanp->debug = 0; - chanp->Flags = 0; - chanp->leased = 0; - err = init_PStack(&chanp->b_st); - if (err) - return err; - chanp->b_st->l1.delay = DEFAULT_B_DELAY; - chanp->fi.fsm = &callcfsm; - chanp->fi.state = ST_NULL; - chanp->fi.debug = 0; - chanp->fi.userdata = chanp; - chanp->fi.printdebug = callc_debug; - FsmInitTimer(&chanp->fi, &chanp->dial_timer); - FsmInitTimer(&chanp->fi, &chanp->drel_timer); - if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { - err = init_d_st(chanp); - if (err) - return err; - } else { - chanp->d_st = csta->channel->d_st; - } - chanp->data_open = 0; - return 0; -} - -int -CallcNewChan(struct IsdnCardState *csta) { - int i, err; - - chancount += 2; - err = init_chan(0, csta); - if (err) - return err; - err = init_chan(1, csta); - if (err) - return err; - printk(KERN_INFO "HiSax: 2 channels added\n"); - - for (i = 0; i < MAX_WAITING_CALLS; i++) { - err = init_chan(i + 2, csta); - if (err) - return err; - } - printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); - if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { - printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); - csta->channel->d_st->lli.l4l3(csta->channel->d_st, - DL_ESTABLISH | REQUEST, NULL); - } - return (0); -} - -static void -release_d_st(struct Channel *chanp) -{ - struct PStack *st = chanp->d_st; - - if (!st) - return; - releasestack_isdnl2(st); - releasestack_isdnl3(st); - HiSax_rmlist(st->l1.hardware, st); - kfree(st); - chanp->d_st = NULL; -} - -void -CallcFreeChan(struct IsdnCardState *csta) -{ - int i; - - for (i = 0; i < 2; i++) { - FsmDelTimer(&csta->channel[i].drel_timer, 74); - FsmDelTimer(&csta->channel[i].dial_timer, 75); - if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) - release_d_st(csta->channel + i); - if (csta->channel[i].b_st) { - release_b_st(csta->channel + i); - kfree(csta->channel[i].b_st); - csta->channel[i].b_st = NULL; - } else - printk(KERN_WARNING "CallcFreeChan b_st ch%d already freed\n", i); - if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { - release_d_st(csta->channel + i); - } else - csta->channel[i].d_st = NULL; - } -} - -static void -lldata_handler(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - - switch (pr) { - case (DL_DATA | INDICATION): - if (chanp->data_open) { - if (chanp->debug & 0x800) - link_debug(chanp, 0, "lldata: %d", skb->len); - chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - } else { - link_debug(chanp, 0, "lldata: channel not open"); - dev_kfree_skb(skb); - } - break; - case (DL_ESTABLISH | INDICATION): - case (DL_ESTABLISH | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - default: - printk(KERN_WARNING "lldata_handler unknown primitive %#x\n", - pr); - break; - } -} - -static void -lltrans_handler(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | INDICATION): - if (chanp->data_open) { - if (chanp->debug & 0x800) - link_debug(chanp, 0, "lltrans: %d", skb->len); - chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - } else { - link_debug(chanp, 0, "lltrans: channel not open"); - dev_kfree_skb(skb); - } - break; - case (PH_ACTIVATE | INDICATION): - case (PH_ACTIVATE | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (PH_DEACTIVATE | INDICATION): - case (PH_DEACTIVATE | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - default: - printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n", - pr); - break; - } -} - -void -lli_writewakeup(struct PStack *st, int len) -{ - struct Channel *chanp = st->lli.userdata; - isdn_ctrl ic; - - if (chanp->debug & 0x800) - link_debug(chanp, 0, "llwakeup: %d", len); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BSENT; - ic.arg = chanp->chan; - ic.parm.length = len; - chanp->cs->iif.statcallb(&ic); -} - -static int -init_b_st(struct Channel *chanp, int incoming) -{ - struct PStack *st = chanp->b_st; - struct IsdnCardState *cs = chanp->cs; - char tmp[16]; - - st->l1.hardware = cs; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - case (ISDN_PROTO_L2_HDLC): - st->l1.mode = L1_MODE_HDLC; - break; - case (ISDN_PROTO_L2_HDLC_56K): - st->l1.mode = L1_MODE_HDLC_56K; - break; - case (ISDN_PROTO_L2_TRANS): - st->l1.mode = L1_MODE_TRANS; - break; - case (ISDN_PROTO_L2_MODEM): - st->l1.mode = L1_MODE_V32; - break; - case (ISDN_PROTO_L2_FAX): - st->l1.mode = L1_MODE_FAX; - break; - } - chanp->bcs->conmsg = NULL; - if (chanp->bcs->BC_SetStack(st, chanp->bcs)) - return (-1); - st->l2.flag = 0; - test_and_set_bit(FLG_LAPB, &st->l2.flag); - st->l2.maxlen = MAX_DATA_SIZE; - if (!incoming) - test_and_set_bit(FLG_ORIG, &st->l2.flag); - st->l2.T200 = 1000; /* 1000 milliseconds */ - st->l2.window = 7; - st->l2.N200 = 4; /* try 4 times */ - st->l2.T203 = 5000; /* 5000 milliseconds */ - st->l3.debug = 0; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - sprintf(tmp, "Ch%d X.75", chanp->chan); - setstack_isdnl2(st, tmp); - setstack_l3bc(st, chanp); - st->l2.l2l3 = lldata_handler; - st->lli.userdata = chanp; - test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag); - test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag); - st->l2.l2m.debug = chanp->debug & 16; - st->l2.debug = chanp->debug & 64; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_HDLC_56K): - case (ISDN_PROTO_L2_TRANS): - case (ISDN_PROTO_L2_MODEM): - case (ISDN_PROTO_L2_FAX): - st->l1.l1l2 = lltrans_handler; - st->lli.userdata = chanp; - test_and_set_bit(FLG_LLI_L1WAKEUP, &st->lli.flag); - test_and_clear_bit(FLG_LLI_L2WAKEUP, &st->lli.flag); - setstack_transl2(st); - setstack_l3bc(st, chanp); - break; - } - test_and_set_bit(FLG_START_B, &chanp->Flags); - return (0); -} - -static void -leased_l4l3(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - - switch (pr) { - case (DL_DATA | REQUEST): - link_debug(chanp, 0, "leased line d-channel DATA"); - dev_kfree_skb(skb); - break; - case (DL_ESTABLISH | REQUEST): - st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); - break; - case (DL_RELEASE | REQUEST): - break; - default: - printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n", - pr); - break; - } -} - -static void -leased_l1l2(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - int i, event = EV_LEASED_REL; - - switch (pr) { - case (PH_DATA | INDICATION): - link_debug(chanp, 0, "leased line d-channel DATA"); - dev_kfree_skb(skb); - break; - case (PH_ACTIVATE | INDICATION): - case (PH_ACTIVATE | CONFIRM): - event = EV_LEASED; - /* fall through */ - case (PH_DEACTIVATE | INDICATION): - case (PH_DEACTIVATE | CONFIRM): - if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) - i = 1; - else - i = 0; - while (i < 2) { - FsmEvent(&chanp->fi, event, NULL); - chanp++; - i++; - } - break; - default: - printk(KERN_WARNING - "transd_l1l2 unknown primitive %#x\n", pr); - break; - } -} - -static void -distr_debug(struct IsdnCardState *csta, int debugflags) -{ - int i; - struct Channel *chanp = csta->channel; - - for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) { - chanp[i].debug = debugflags; - chanp[i].fi.debug = debugflags & 2; - chanp[i].d_st->l2.l2m.debug = debugflags & 8; - chanp[i].b_st->l2.l2m.debug = debugflags & 0x10; - chanp[i].d_st->l2.debug = debugflags & 0x20; - chanp[i].b_st->l2.debug = debugflags & 0x40; - chanp[i].d_st->l3.l3m.debug = debugflags & 0x80; - chanp[i].b_st->l3.l3m.debug = debugflags & 0x100; - chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200; - chanp[i].b_st->ma.debug = debugflags & 0x200; - chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000; - chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000; - } - if (debugflags & 4) - csta->debug |= DEB_DLOG_HEX; - else - csta->debug &= ~DEB_DLOG_HEX; -} - -static char tmpbuf[256]; - -static void -capi_debug(struct Channel *chanp, capi_msg *cm) -{ - char *t = tmpbuf; - - t += QuickHex(t, (u_char *)cm, (cm->Length > 50) ? 50 : cm->Length); - t--; - *t = 0; - HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf); -} - -static void -lli_got_fac_req(struct Channel *chanp, capi_msg *cm) { - if ((cm->para[0] != 3) || (cm->para[1] != 0)) - return; - if (cm->para[2] < 3) - return; - if (cm->para[4] != 0) - return; - switch (cm->para[3]) { - case 4: /* Suspend */ - strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] + 1); - FsmEvent(&chanp->fi, EV_SUSPEND, cm); - break; - case 5: /* Resume */ - strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] + 1); - if (chanp->fi.state == ST_NULL) { - FsmEvent(&chanp->fi, EV_RESUME, cm); - } else { - FsmDelTimer(&chanp->dial_timer, 72); - FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73); - } - break; - } -} - -static void -lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) { - if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) || - (cs->typ == ISDN_CTYPE_ELSA_PCI)) { - if (cs->hw.elsa.MFlag) { - cs->cardmsg(cs, CARD_AUX_IND, cm->para); - } - } -} - - -/***************************************************************/ -/* Limit the available number of channels for the current card */ -/***************************************************************/ -static int -set_channel_limit(struct IsdnCardState *cs, int chanmax) -{ - isdn_ctrl ic; - int i, ii; - - if ((chanmax < 0) || (chanmax > 2)) - return (-EINVAL); - cs->chanlimit = 0; - for (ii = 0; ii < 2; ii++) { - ic.driver = cs->myid; - ic.command = ISDN_STAT_DISCH; - ic.arg = ii; - if (ii >= chanmax) - ic.parm.num[0] = 0; /* disabled */ - else - ic.parm.num[0] = 1; /* enabled */ - i = cs->iif.statcallb(&ic); - if (i) return (-EINVAL); - if (ii < chanmax) - cs->chanlimit++; - } - return (0); -} /* set_channel_limit */ - -int -HiSax_command(isdn_ctrl *ic) -{ - struct IsdnCardState *csta = hisax_findcard(ic->driver); - struct PStack *st; - struct Channel *chanp; - int i; - u_int num; - - if (!csta) { - printk(KERN_ERR - "HiSax: if_command %d called with invalid driverId %d!\n", - ic->command, ic->driver); - return -ENODEV; - } - switch (ic->command) { - case (ISDN_CMD_SETEAZ): - chanp = csta->channel + ic->arg; - break; - case (ISDN_CMD_SETL2): - chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) - link_debug(chanp, 1, "SETL2 card %d %ld", - csta->cardnr + 1, ic->arg >> 8); - chanp->l2_protocol = ic->arg >> 8; - break; - case (ISDN_CMD_SETL3): - chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) - link_debug(chanp, 1, "SETL3 card %d %ld", - csta->cardnr + 1, ic->arg >> 8); - chanp->l3_protocol = ic->arg >> 8; - break; - case (ISDN_CMD_DIAL): - chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) - link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", - ic->parm.setup.eazmsn, ic->parm.setup.phone, - ic->parm.setup.si1, ic->parm.setup.si2); - memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); - if (!strcmp(chanp->setup.eazmsn, "0")) - chanp->setup.eazmsn[0] = '\0'; - /* this solution is dirty and may be change, if - * we make a callreference based callmanager */ - if (chanp->fi.state == ST_NULL) { - FsmEvent(&chanp->fi, EV_DIAL, NULL); - } else { - FsmDelTimer(&chanp->dial_timer, 70); - FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71); - } - break; - case (ISDN_CMD_ACCEPTB): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "ACCEPTB"); - FsmEvent(&chanp->fi, EV_ACCEPTB, NULL); - break; - case (ISDN_CMD_ACCEPTD): - chanp = csta->channel + ic->arg; - memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); - if (chanp->debug & 1) - link_debug(chanp, 1, "ACCEPTD"); - FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); - break; - case (ISDN_CMD_HANGUP): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "HANGUP"); - FsmEvent(&chanp->fi, EV_HANGUP, NULL); - break; - case (CAPI_PUT_MESSAGE): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - capi_debug(chanp, &ic->parm.cmsg); - if (ic->parm.cmsg.Length < 8) - break; - switch (ic->parm.cmsg.Command) { - case CAPI_FACILITY: - if (ic->parm.cmsg.Subcommand == CAPI_REQ) - lli_got_fac_req(chanp, &ic->parm.cmsg); - break; - case CAPI_MANUFACTURER: - if (ic->parm.cmsg.Subcommand == CAPI_REQ) - lli_got_manufacturer(chanp, csta, &ic->parm.cmsg); - break; - default: - break; - } - break; - case (ISDN_CMD_IOCTL): - switch (ic->arg) { - case (0): - num = *(unsigned int *) ic->parm.num; - HiSax_reportcard(csta->cardnr, num); - break; - case (1): - num = *(unsigned int *) ic->parm.num; - distr_debug(csta, num); - printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n", - csta->cardnr + 1, num); - HiSax_putstatus(csta, "debugging flags ", - "card %d set to %x", csta->cardnr + 1, num); - break; - case (2): - num = *(unsigned int *) ic->parm.num; - csta->channel[0].b_st->l1.delay = num; - csta->channel[1].b_st->l1.delay = num; - HiSax_putstatus(csta, "delay ", "card %d set to %d ms", - csta->cardnr + 1, num); - printk(KERN_DEBUG "HiSax: delay card %d set to %d ms\n", - csta->cardnr + 1, num); - break; - case (5): /* set card in leased mode */ - num = *(unsigned int *) ic->parm.num; - if ((num < 1) || (num > 2)) { - HiSax_putstatus(csta, "Set LEASED ", - "wrong channel %d", num); - printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n", - num); - } else { - num--; - chanp = csta->channel + num; - chanp->leased = 1; - HiSax_putstatus(csta, "Card", - "%d channel %d set leased mode\n", - csta->cardnr + 1, num + 1); - chanp->d_st->l1.l1l2 = leased_l1l2; - chanp->d_st->lli.l4l3 = leased_l4l3; - chanp->d_st->lli.l4l3(chanp->d_st, - DL_ESTABLISH | REQUEST, NULL); - } - break; - case (6): /* set B-channel test loop */ - num = *(unsigned int *) ic->parm.num; - if (csta->stlist) - csta->stlist->l2.l2l1(csta->stlist, - PH_TESTLOOP | REQUEST, (void *) (long)num); - break; - case (7): /* set card in PTP mode */ - num = *(unsigned int *) ic->parm.num; - if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { - printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n"); - } else if (num) { - test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); - test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); - csta->channel[0].d_st->l2.tei = 0; - HiSax_putstatus(csta, "set card ", "in PTP mode"); - printk(KERN_DEBUG "HiSax: set card in PTP mode\n"); - printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); - csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st, - DL_ESTABLISH | REQUEST, NULL); - } else { - test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); - test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); - HiSax_putstatus(csta, "set card ", "in PTMP mode"); - printk(KERN_DEBUG "HiSax: set card in PTMP mode\n"); - } - break; - case (8): /* set card in FIXED TEI mode */ - num = *(unsigned int *)ic->parm.num; - chanp = csta->channel + (num & 1); - num = num >> 1; - if (num == 127) { - test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); - chanp->d_st->l2.tei = -1; - HiSax_putstatus(csta, "set card ", "in VAR TEI mode"); - printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n"); - } else { - test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); - chanp->d_st->l2.tei = num; - HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num); - printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", - num); - } - chanp->d_st->lli.l4l3(chanp->d_st, - DL_ESTABLISH | REQUEST, NULL); - break; - case (11): - num = csta->debug & DEB_DLOG_HEX; - csta->debug = *(unsigned int *) ic->parm.num; - csta->debug |= num; - HiSax_putstatus(cards[0].cs, "l1 debugging ", - "flags card %d set to %x", - csta->cardnr + 1, csta->debug); - printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n", - csta->cardnr + 1, csta->debug); - break; - case (13): - csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num; - csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num; - HiSax_putstatus(cards[0].cs, "l3 debugging ", - "flags card %d set to %x\n", csta->cardnr + 1, - *(unsigned int *) ic->parm.num); - printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n", - csta->cardnr + 1, *(unsigned int *) ic->parm.num); - break; - case (10): - i = *(unsigned int *) ic->parm.num; - return (set_channel_limit(csta, i)); - default: - if (csta->auxcmd) - return (csta->auxcmd(csta, ic)); - printk(KERN_DEBUG "HiSax: invalid ioctl %d\n", - (int) ic->arg); - return (-EINVAL); - } - break; - - case (ISDN_CMD_PROCEED): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "PROCEED"); - FsmEvent(&chanp->fi, EV_PROCEED, NULL); - break; - - case (ISDN_CMD_ALERT): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "ALERT"); - FsmEvent(&chanp->fi, EV_ALERT, NULL); - break; - - case (ISDN_CMD_REDIR): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "REDIR"); - memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); - FsmEvent(&chanp->fi, EV_REDIR, NULL); - break; - - /* protocol specific io commands */ - case (ISDN_CMD_PROT_IO): - for (st = csta->stlist; st; st = st->next) - if (st->protocol == (ic->arg & 0xFF)) - return (st->lli.l4l3_proto(st, ic)); - return (-EINVAL); - break; - default: - if (csta->auxcmd) - return (csta->auxcmd(csta, ic)); - return (-EINVAL); - } - return (0); -} - -int -HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) -{ - struct IsdnCardState *csta = hisax_findcard(id); - struct Channel *chanp; - struct PStack *st; - int len = skb->len; - struct sk_buff *nskb; - - if (!csta) { - printk(KERN_ERR - "HiSax: if_sendbuf called with invalid driverId!\n"); - return -ENODEV; - } - chanp = csta->channel + chan; - st = chanp->b_st; - if (!chanp->data_open) { - link_debug(chanp, 1, "writebuf: channel not open"); - return -EIO; - } - if (len > MAX_DATA_SIZE) { - link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len); - printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n", - len); - return -EINVAL; - } - if (len) { - if ((len + chanp->bcs->tx_cnt) > MAX_DATA_MEM) { - /* Must return 0 here, since this is not an error - * but a temporary lack of resources. - */ - if (chanp->debug & 0x800) - link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len); - return 0; - } else if (chanp->debug & 0x800) - link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt, MAX_DATA_MEM); - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - nskb->truesize = nskb->len; - if (!ack) - nskb->pkt_type = PACKET_NOACK; - if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I) - st->l3.l3l2(st, DL_DATA | REQUEST, nskb); - else { - chanp->bcs->tx_cnt += len; - st->l2.l2l1(st, PH_DATA | REQUEST, nskb); - } - dev_kfree_skb(skb); - } else - len = 0; - } - return (len); -} diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c deleted file mode 100644 index de965115a183..000000000000 --- a/drivers/isdn/hisax/config.c +++ /dev/null @@ -1,1993 +0,0 @@ -/* $Id: config.c,v 2.84.2.5 2004/02/11 13:21:33 keil Exp $ - * - * Author Karsten Keil - * Copyright by Karsten Keil - * by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * based on the teles driver from Jan den Ouden - * - */ - -#include -#include -#include -#include -#include "hisax.h" -#include -#include -#include -#include -#include -#define HISAX_STATUS_BUFSIZE 4096 - -/* - * This structure array contains one entry per card. An entry looks - * like this: - * - * { type, protocol, p0, p1, p2, NULL } - * - * type - * 1 Teles 16.0 p0=irq p1=membase p2=iobase - * 2 Teles 8.0 p0=irq p1=membase - * 3 Teles 16.3 p0=irq p1=iobase - * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX) - * 5 AVM A1 (Fritz) p0=irq p1=iobase - * 6 ELSA PC [p0=iobase] or nothing (autodetect) - * 7 ELSA Quickstep p0=irq p1=iobase - * 8 Teles PCMCIA p0=irq p1=iobase - * 9 ITK ix1-micro p0=irq p1=iobase - * 10 ELSA PCMCIA p0=irq p1=iobase - * 11 Eicon.Diehl Diva p0=irq p1=iobase - * 12 Asuscom ISDNLink p0=irq p1=iobase - * 13 Teleint p0=irq p1=iobase - * 14 Teles 16.3c p0=irq p1=iobase - * 15 Sedlbauer speed p0=irq p1=iobase - * 15 Sedlbauer PC/104 p0=irq p1=iobase - * 15 Sedlbauer speed pci no parameter - * 16 USR Sportster internal p0=irq p1=iobase - * 17 MIC card p0=irq p1=iobase - * 18 ELSA Quickstep 1000PCI no parameter - * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 - * 20 Travers Technologies NETjet-S PCI card - * 21 TELES PCI no parameter - * 22 Sedlbauer Speed Star p0=irq p1=iobase - * 23 reserved - * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only) - * 25 Teles S0Box p0=irq p1=iobase (from isapnp setup) - * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase - * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter) - * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup) - * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup) - * 30 ACER P10 p0=irq p1=iobase (from isapnp setup) - * 31 HST Saphir p0=irq p1=iobase - * 32 Telekom A4T none - * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4) - * 34 Gazel ISDN cards - * 35 HFC 2BDS0 PCI none - * 36 Winbond 6692 PCI none - * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase - * 38 Travers Technologies NETspider-U PCI card - * 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase - * 40 hotplug interface - * 41 Formula-n enter:now ISDN PCI a/b none - * - * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 - * - * - */ - -const char *CardType[] = { - "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", - "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep", - "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", - "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", - "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", - "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI", - "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", - "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", - "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", - "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", - "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA", - "Hotplug", "Formula-n enter:now PCI a/b", -}; - -#ifdef CONFIG_HISAX_ELSA -#define DEFAULT_CARD ISDN_CTYPE_ELSA -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_AVM_A1 -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_A1 -#define DEFAULT_CFG {10, 0x340, 0, 0} -#endif - -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA -#define DEFAULT_CFG {11, 0x170, 0, 0} -#endif - -#ifdef CONFIG_HISAX_FRITZPCI -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_16_3 -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_16_3 -#define DEFAULT_CFG {15, 0x180, 0, 0} -#endif - -#ifdef CONFIG_HISAX_S0BOX -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_S0BOX -#define DEFAULT_CFG {7, 0x378, 0, 0} -#endif - -#ifdef CONFIG_HISAX_16_0 -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_16_0 -#define DEFAULT_CFG {15, 0xd0000, 0xd80, 0} -#endif - -#ifdef CONFIG_HISAX_TELESPCI -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_TELESPCI -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_IX1MICROR2 -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2 -#define DEFAULT_CFG {5, 0x390, 0, 0} -#endif - -#ifdef CONFIG_HISAX_DIEHLDIVA -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_DIEHLDIVA -#define DEFAULT_CFG {0, 0x0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_ASUSCOM -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_ASUSCOM -#define DEFAULT_CFG {5, 0x200, 0, 0} -#endif - -#ifdef CONFIG_HISAX_TELEINT -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_TELEINT -#define DEFAULT_CFG {5, 0x300, 0, 0} -#endif - -#ifdef CONFIG_HISAX_SEDLBAUER -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER -#define DEFAULT_CFG {11, 0x270, 0, 0} -#endif - -#ifdef CONFIG_HISAX_SPORTSTER -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_SPORTSTER -#define DEFAULT_CFG {7, 0x268, 0, 0} -#endif - -#ifdef CONFIG_HISAX_MIC -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_MIC -#define DEFAULT_CFG {12, 0x3e0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_NETJET -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NETJET_S -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_HFCS -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_TELES3C -#define DEFAULT_CFG {5, 0x500, 0, 0} -#endif - -#ifdef CONFIG_HISAX_HFC_PCI -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_HFC_PCI -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_HFC_SX -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_HFC_SX -#define DEFAULT_CFG {5, 0x2E0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_NICCY -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NICCY -#define DEFAULT_CFG {0, 0x0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_ISURF -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_ISURF -#define DEFAULT_CFG {5, 0x100, 0xc8000, 0} -#endif - -#ifdef CONFIG_HISAX_HSTSAPHIR -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_HSTSAPHIR -#define DEFAULT_CFG {5, 0x250, 0, 0} -#endif - -#ifdef CONFIG_HISAX_BKM_A4T -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T -#define DEFAULT_CFG {0, 0x0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_SCT_QUADRO -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_SCT_QUADRO -#define DEFAULT_CFG {1, 0x0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_GAZEL -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_GAZEL -#define DEFAULT_CFG {15, 0x180, 0, 0} -#endif - -#ifdef CONFIG_HISAX_W6692 -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_W6692 -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_NETJET_U -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NETJET_U -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#ifdef CONFIG_HISAX_1TR6 -#define DEFAULT_PROTO ISDN_PTYPE_1TR6 -#define DEFAULT_PROTO_NAME "1TR6" -#endif -#ifdef CONFIG_HISAX_NI1 -#undef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_NI1 -#undef DEFAULT_PROTO_NAME -#define DEFAULT_PROTO_NAME "NI1" -#endif -#ifdef CONFIG_HISAX_EURO -#undef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_EURO -#undef DEFAULT_PROTO_NAME -#define DEFAULT_PROTO_NAME "EURO" -#endif -#ifndef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN -#define DEFAULT_PROTO_NAME "UNKNOWN" -#endif -#ifndef DEFAULT_CARD -#define DEFAULT_CARD 0 -#define DEFAULT_CFG {0, 0, 0, 0} -#endif - -#define FIRST_CARD { \ - DEFAULT_CARD, \ - DEFAULT_PROTO, \ - DEFAULT_CFG, \ - NULL, \ - } - -struct IsdnCard cards[HISAX_MAX_CARDS] = { - FIRST_CARD, -}; - -#define HISAX_IDSIZE (HISAX_MAX_CARDS * 8) -static char HiSaxID[HISAX_IDSIZE] = { 0, }; - -static char *HiSax_id = HiSaxID; -#ifdef MODULE -/* Variables for insmod */ -static int type[HISAX_MAX_CARDS] = { 0, }; -static int protocol[HISAX_MAX_CARDS] = { 0, }; -static int io[HISAX_MAX_CARDS] = { 0, }; -#undef IO0_IO1 -#ifdef CONFIG_HISAX_16_3 -#define IO0_IO1 -#endif -#ifdef CONFIG_HISAX_NICCY -#undef IO0_IO1 -#define IO0_IO1 -#endif -#ifdef IO0_IO1 -static int io0[HISAX_MAX_CARDS] = { 0, }; -static int io1[HISAX_MAX_CARDS] = { 0, }; -#endif -static int irq[HISAX_MAX_CARDS] = { 0, }; -static int mem[HISAX_MAX_CARDS] = { 0, }; -static char *id = HiSaxID; - -MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards"); -MODULE_AUTHOR("Karsten Keil"); -MODULE_LICENSE("GPL"); -module_param_array(type, int, NULL, 0); -module_param_array(protocol, int, NULL, 0); -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_hw_array(mem, int, iomem, NULL, 0); -module_param(id, charp, 0); -#ifdef IO0_IO1 -module_param_hw_array(io0, int, ioport, NULL, 0); -module_param_hw_array(io1, int, ioport, NULL, 0); -#endif -#endif /* MODULE */ - -int nrcards; - -char *HiSax_getrev(const char *revision) -{ - char *rev; - char *p; - - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; -} - -static void __init HiSaxVersion(void) -{ - char tmp[64]; - - printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); -#ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.5 (module)\n"); -#else - printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n"); -#endif - strcpy(tmp, l1_revision); - printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); - strcpy(tmp, l2_revision); - printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp)); - strcpy(tmp, tei_revision); - printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp)); - strcpy(tmp, l3_revision); - printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp)); - strcpy(tmp, lli_revision); - printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", - HiSax_getrev(tmp)); -} - -#ifndef MODULE -#define MAX_ARG (HISAX_MAX_CARDS * 5) -static int __init HiSax_setup(char *line) -{ - int i, j, argc; - int ints[MAX_ARG + 1]; - char *str; - - str = get_options(line, MAX_ARG, ints); - argc = ints[0]; - printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str); - i = 0; - j = 1; - while (argc && (i < HISAX_MAX_CARDS)) { - cards[i].protocol = DEFAULT_PROTO; - if (argc) { - cards[i].typ = ints[j]; - j++; - argc--; - } - if (argc) { - cards[i].protocol = ints[j]; - j++; - argc--; - } - if (argc) { - cards[i].para[0] = ints[j]; - j++; - argc--; - } - if (argc) { - cards[i].para[1] = ints[j]; - j++; - argc--; - } - if (argc) { - cards[i].para[2] = ints[j]; - j++; - argc--; - } - i++; - } - if (str && *str) { - if (strlen(str) < HISAX_IDSIZE) - strcpy(HiSaxID, str); - else - printk(KERN_WARNING "HiSax: ID too long!"); - } else - strcpy(HiSaxID, "HiSax"); - - HiSax_id = HiSaxID; - return 1; -} - -__setup("hisax=", HiSax_setup); -#endif /* MODULES */ - -#if CARD_TELES0 -extern int setup_teles0(struct IsdnCard *card); -#endif - -#if CARD_TELES3 -extern int setup_teles3(struct IsdnCard *card); -#endif - -#if CARD_S0BOX -extern int setup_s0box(struct IsdnCard *card); -#endif - -#if CARD_TELESPCI -extern int setup_telespci(struct IsdnCard *card); -#endif - -#if CARD_AVM_A1 -extern int setup_avm_a1(struct IsdnCard *card); -#endif - -#if CARD_AVM_A1_PCMCIA -extern int setup_avm_a1_pcmcia(struct IsdnCard *card); -#endif - -#if CARD_FRITZPCI -extern int setup_avm_pcipnp(struct IsdnCard *card); -#endif - -#if CARD_ELSA -extern int setup_elsa(struct IsdnCard *card); -#endif - -#if CARD_IX1MICROR2 -extern int setup_ix1micro(struct IsdnCard *card); -#endif - -#if CARD_DIEHLDIVA -extern int setup_diva(struct IsdnCard *card); -#endif - -#if CARD_ASUSCOM -extern int setup_asuscom(struct IsdnCard *card); -#endif - -#if CARD_TELEINT -extern int setup_TeleInt(struct IsdnCard *card); -#endif - -#if CARD_SEDLBAUER -extern int setup_sedlbauer(struct IsdnCard *card); -#endif - -#if CARD_SPORTSTER -extern int setup_sportster(struct IsdnCard *card); -#endif - -#if CARD_MIC -extern int setup_mic(struct IsdnCard *card); -#endif - -#if CARD_NETJET_S -extern int setup_netjet_s(struct IsdnCard *card); -#endif - -#if CARD_HFCS -extern int setup_hfcs(struct IsdnCard *card); -#endif - -#if CARD_HFC_PCI -extern int setup_hfcpci(struct IsdnCard *card); -#endif - -#if CARD_HFC_SX -extern int setup_hfcsx(struct IsdnCard *card); -#endif - -#if CARD_NICCY -extern int setup_niccy(struct IsdnCard *card); -#endif - -#if CARD_ISURF -extern int setup_isurf(struct IsdnCard *card); -#endif - -#if CARD_HSTSAPHIR -extern int setup_saphir(struct IsdnCard *card); -#endif - -#if CARD_BKM_A4T -extern int setup_bkm_a4t(struct IsdnCard *card); -#endif - -#if CARD_SCT_QUADRO -extern int setup_sct_quadro(struct IsdnCard *card); -#endif - -#if CARD_GAZEL -extern int setup_gazel(struct IsdnCard *card); -#endif - -#if CARD_W6692 -extern int setup_w6692(struct IsdnCard *card); -#endif - -#if CARD_NETJET_U -extern int setup_netjet_u(struct IsdnCard *card); -#endif - -#if CARD_FN_ENTERNOW_PCI -extern int setup_enternow_pci(struct IsdnCard *card); -#endif - -/* - * Find card with given driverId - */ -static inline struct IsdnCardState *hisax_findcard(int driverid) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].cs) - if (cards[i].cs->myid == driverid) - return cards[i].cs; - return NULL; -} - -/* - * Find card with given card number - */ -#if 0 -struct IsdnCardState *hisax_get_card(int cardnr) -{ - if ((cardnr <= nrcards) && (cardnr > 0)) - if (cards[cardnr - 1].cs) - return cards[cardnr - 1].cs; - return NULL; -} -#endif /* 0 */ - -static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) -{ - int count, cnt; - u_char __user *p = buf; - struct IsdnCardState *cs = hisax_findcard(id); - - if (cs) { - if (len > HISAX_STATUS_BUFSIZE) { - printk(KERN_WARNING - "HiSax: status overflow readstat %d/%d\n", - len, HISAX_STATUS_BUFSIZE); - } - count = cs->status_end - cs->status_read + 1; - if (count >= len) - count = len; - if (copy_to_user(p, cs->status_read, count)) - return -EFAULT; - cs->status_read += count; - if (cs->status_read > cs->status_end) - cs->status_read = cs->status_buf; - p += count; - count = len - count; - while (count) { - if (count > HISAX_STATUS_BUFSIZE) - cnt = HISAX_STATUS_BUFSIZE; - else - cnt = count; - if (copy_to_user(p, cs->status_read, cnt)) - return -EFAULT; - p += cnt; - cs->status_read += cnt % HISAX_STATUS_BUFSIZE; - count -= cnt; - } - return len; - } else { - printk(KERN_ERR - "HiSax: if_readstatus called with invalid driverId!\n"); - return -ENODEV; - } -} - -int jiftime(char *s, long mark) -{ - s += 8; - - *s-- = '\0'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = '.'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 6 + '0'; - mark /= 6; - *s-- = ':'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - return 8; -} - -static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; - -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, - va_list args) -{ - /* if head == NULL the fmt contains the full info */ - - u_long flags; - int count, i; - u_char *p; - isdn_ctrl ic; - int len; - const u_char *data; - - if (!cs) { - printk(KERN_WARNING "HiSax: No CardStatus for message"); - return; - } - spin_lock_irqsave(&cs->statlock, flags); - if (head) { - p = tmpbuf; - p += jiftime(p, jiffies); - p += sprintf(p, " %s", head); - p += vsprintf(p, fmt, args); - *p++ = '\n'; - *p = 0; - len = p - tmpbuf; - data = tmpbuf; - } else { - data = fmt; - len = strlen(fmt); - } - if (len > HISAX_STATUS_BUFSIZE) { - spin_unlock_irqrestore(&cs->statlock, flags); - printk(KERN_WARNING "HiSax: status overflow %d/%d\n", - len, HISAX_STATUS_BUFSIZE); - return; - } - count = len; - i = cs->status_end - cs->status_write + 1; - if (i >= len) - i = len; - len -= i; - memcpy(cs->status_write, data, i); - cs->status_write += i; - if (cs->status_write > cs->status_end) - cs->status_write = cs->status_buf; - if (len) { - memcpy(cs->status_write, data + i, len); - cs->status_write += len; - } -#ifdef KERNELSTACK_DEBUG - i = (ulong) & len - current->kernel_stack_page; - sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm, - current->kernel_stack_page, i); - len = strlen(tmpbuf); - for (p = tmpbuf, i = len; i > 0; i--, p++) { - *cs->status_write++ = *p; - if (cs->status_write > cs->status_end) - cs->status_write = cs->status_buf; - count++; - } -#endif - spin_unlock_irqrestore(&cs->statlock, flags); - if (count) { - ic.command = ISDN_STAT_STAVAIL; - ic.driver = cs->myid; - ic.arg = count; - cs->iif.statcallb(&ic); - } -} - -void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - VHiSax_putstatus(cs, head, fmt, args); - va_end(args); -} - -int ll_run(struct IsdnCardState *cs, int addfeatures) -{ - isdn_ctrl ic; - - ic.driver = cs->myid; - ic.command = ISDN_STAT_RUN; - cs->iif.features |= addfeatures; - cs->iif.statcallb(&ic); - return 0; -} - -static void ll_stop(struct IsdnCardState *cs) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_STOP; - ic.driver = cs->myid; - cs->iif.statcallb(&ic); - // CallcFreeChan(cs); -} - -static void ll_unload(struct IsdnCardState *cs) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_UNLOAD; - ic.driver = cs->myid; - cs->iif.statcallb(&ic); - kfree(cs->status_buf); - cs->status_read = NULL; - cs->status_write = NULL; - cs->status_end = NULL; - kfree(cs->dlog); - cs->dlog = NULL; -} - -static void closecard(int cardnr) -{ - struct IsdnCardState *csta = cards[cardnr].cs; - - if (csta->bcs->BC_Close != NULL) { - csta->bcs->BC_Close(csta->bcs + 1); - csta->bcs->BC_Close(csta->bcs); - } - - skb_queue_purge(&csta->rq); - skb_queue_purge(&csta->sq); - kfree(csta->rcvbuf); - csta->rcvbuf = NULL; - if (csta->tx_skb) { - dev_kfree_skb(csta->tx_skb); - csta->tx_skb = NULL; - } - if (csta->DC_Close != NULL) { - csta->DC_Close(csta); - } - if (csta->cardmsg) - csta->cardmsg(csta, CARD_RELEASE, NULL); - if (csta->dbusytimer.function != NULL) // FIXME? - del_timer(&csta->dbusytimer); - ll_unload(csta); -} - -static irqreturn_t card_irq(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - irqreturn_t ret = cs->irq_func(intno, cs); - - if (ret == IRQ_HANDLED) - cs->irq_cnt++; - return ret; -} - -static int init_card(struct IsdnCardState *cs) -{ - int irq_cnt, cnt = 3, ret; - - if (!cs->irq) { - ret = cs->cardmsg(cs, CARD_INIT, NULL); - return (ret); - } - irq_cnt = cs->irq_cnt = 0; - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], - cs->irq, irq_cnt); - if (request_irq(cs->irq, card_irq, cs->irq_flags, "HiSax", cs)) { - printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", - cs->irq); - return 1; - } - while (cnt) { - cs->cardmsg(cs, CARD_INIT, NULL); - /* Timeout 10ms */ - msleep(10); - printk(KERN_INFO "%s: IRQ %d count %d\n", - CardType[cs->typ], cs->irq, cs->irq_cnt); - if (cs->irq_cnt == irq_cnt) { - printk(KERN_WARNING - "%s: IRQ(%d) getting no interrupts during init %d\n", - CardType[cs->typ], cs->irq, 4 - cnt); - if (cnt == 1) { - free_irq(cs->irq, cs); - return 2; - } else { - cs->cardmsg(cs, CARD_RESET, NULL); - cnt--; - } - } else { - cs->cardmsg(cs, CARD_TEST, NULL); - return 0; - } - } - return 3; -} - -static int hisax_cs_setup_card(struct IsdnCard *card) -{ - int ret; - - switch (card->typ) { -#if CARD_TELES0 - case ISDN_CTYPE_16_0: - case ISDN_CTYPE_8_0: - ret = setup_teles0(card); - break; -#endif -#if CARD_TELES3 - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_COMPAQ_ISA: - ret = setup_teles3(card); - break; -#endif -#if CARD_S0BOX - case ISDN_CTYPE_S0BOX: - ret = setup_s0box(card); - break; -#endif -#if CARD_TELESPCI - case ISDN_CTYPE_TELESPCI: - ret = setup_telespci(card); - break; -#endif -#if CARD_AVM_A1 - case ISDN_CTYPE_A1: - ret = setup_avm_a1(card); - break; -#endif -#if CARD_AVM_A1_PCMCIA - case ISDN_CTYPE_A1_PCMCIA: - ret = setup_avm_a1_pcmcia(card); - break; -#endif -#if CARD_FRITZPCI - case ISDN_CTYPE_FRITZPCI: - ret = setup_avm_pcipnp(card); - break; -#endif -#if CARD_ELSA - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_ELSA_PCI: - ret = setup_elsa(card); - break; -#endif -#if CARD_IX1MICROR2 - case ISDN_CTYPE_IX1MICROR2: - ret = setup_ix1micro(card); - break; -#endif -#if CARD_DIEHLDIVA - case ISDN_CTYPE_DIEHLDIVA: - ret = setup_diva(card); - break; -#endif -#if CARD_ASUSCOM - case ISDN_CTYPE_ASUSCOM: - ret = setup_asuscom(card); - break; -#endif -#if CARD_TELEINT - case ISDN_CTYPE_TELEINT: - ret = setup_TeleInt(card); - break; -#endif -#if CARD_SEDLBAUER - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - case ISDN_CTYPE_SEDLBAUER_FAX: - ret = setup_sedlbauer(card); - break; -#endif -#if CARD_SPORTSTER - case ISDN_CTYPE_SPORTSTER: - ret = setup_sportster(card); - break; -#endif -#if CARD_MIC - case ISDN_CTYPE_MIC: - ret = setup_mic(card); - break; -#endif -#if CARD_NETJET_S - case ISDN_CTYPE_NETJET_S: - ret = setup_netjet_s(card); - break; -#endif -#if CARD_HFCS - case ISDN_CTYPE_TELES3C: - case ISDN_CTYPE_ACERP10: - ret = setup_hfcs(card); - break; -#endif -#if CARD_HFC_PCI - case ISDN_CTYPE_HFC_PCI: - ret = setup_hfcpci(card); - break; -#endif -#if CARD_HFC_SX - case ISDN_CTYPE_HFC_SX: - ret = setup_hfcsx(card); - break; -#endif -#if CARD_NICCY - case ISDN_CTYPE_NICCY: - ret = setup_niccy(card); - break; -#endif -#if CARD_ISURF - case ISDN_CTYPE_ISURF: - ret = setup_isurf(card); - break; -#endif -#if CARD_HSTSAPHIR - case ISDN_CTYPE_HSTSAPHIR: - ret = setup_saphir(card); - break; -#endif -#if CARD_BKM_A4T - case ISDN_CTYPE_BKM_A4T: - ret = setup_bkm_a4t(card); - break; -#endif -#if CARD_SCT_QUADRO - case ISDN_CTYPE_SCT_QUADRO: - ret = setup_sct_quadro(card); - break; -#endif -#if CARD_GAZEL - case ISDN_CTYPE_GAZEL: - ret = setup_gazel(card); - break; -#endif -#if CARD_W6692 - case ISDN_CTYPE_W6692: - ret = setup_w6692(card); - break; -#endif -#if CARD_NETJET_U - case ISDN_CTYPE_NETJET_U: - ret = setup_netjet_u(card); - break; -#endif -#if CARD_FN_ENTERNOW_PCI - case ISDN_CTYPE_ENTERNOW: - ret = setup_enternow_pci(card); - break; -#endif - case ISDN_CTYPE_DYNAMIC: - ret = 2; - break; - default: - printk(KERN_WARNING - "HiSax: Support for %s Card not selected\n", - CardType[card->typ]); - ret = 0; - break; - } - - return ret; -} - -static int hisax_cs_new(int cardnr, char *id, struct IsdnCard *card, - struct IsdnCardState **cs_out, int *busy_flag, - struct module *lockowner) -{ - struct IsdnCardState *cs; - - *cs_out = NULL; - - cs = kzalloc(sizeof(struct IsdnCardState), GFP_KERNEL); - if (!cs) { - printk(KERN_WARNING - "HiSax: No memory for IsdnCardState(card %d)\n", - cardnr + 1); - goto out; - } - card->cs = cs; - spin_lock_init(&cs->statlock); - spin_lock_init(&cs->lock); - cs->chanlimit = 2; /* maximum B-channel number */ - cs->logecho = 0; /* No echo logging */ - cs->cardnr = cardnr; - cs->debug = L1_DEB_WARN; - cs->HW_Flags = 0; - cs->busy_flag = busy_flag; - cs->irq_flags = I4L_IRQ_FLAG; -#if TEI_PER_CARD - if (card->protocol == ISDN_PTYPE_NI1) - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#else - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#endif - cs->protocol = card->protocol; - - if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { - printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", card->typ); - goto outf_cs; - } - if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_KERNEL))) { - printk(KERN_WARNING - "HiSax: No memory for dlog(card %d)\n", cardnr + 1); - goto outf_cs; - } - if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_KERNEL))) { - printk(KERN_WARNING - "HiSax: No memory for status_buf(card %d)\n", - cardnr + 1); - goto outf_dlog; - } - cs->stlist = NULL; - cs->status_read = cs->status_buf; - cs->status_write = cs->status_buf; - cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; - cs->typ = card->typ; -#ifdef MODULE - cs->iif.owner = lockowner; -#endif - strcpy(cs->iif.id, id); - cs->iif.channels = 2; - cs->iif.maxbufsize = MAX_DATA_SIZE; - cs->iif.hl_hdrlen = MAX_HEADER_LEN; - cs->iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_HDLC_56K | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | -#ifdef CONFIG_HISAX_1TR6 - ISDN_FEATURE_P_1TR6 | -#endif -#ifdef CONFIG_HISAX_EURO - ISDN_FEATURE_P_EURO | -#endif -#ifdef CONFIG_HISAX_NI1 - ISDN_FEATURE_P_NI1 | -#endif - 0; - - cs->iif.command = HiSax_command; - cs->iif.writecmd = NULL; - cs->iif.writebuf_skb = HiSax_writebuf_skb; - cs->iif.readstat = HiSax_readstatus; - register_isdn(&cs->iif); - cs->myid = cs->iif.channels; - - *cs_out = cs; - return 1; /* success */ - -outf_dlog: - kfree(cs->dlog); -outf_cs: - kfree(cs); - card->cs = NULL; -out: - return 0; /* error */ -} - -static int hisax_cs_setup(int cardnr, struct IsdnCard *card, - struct IsdnCardState *cs) -{ - int ret; - - if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_KERNEL))) { - printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n"); - ll_unload(cs); - goto outf_cs; - } - cs->rcvidx = 0; - cs->tx_skb = NULL; - cs->tx_cnt = 0; - cs->event = 0; - - skb_queue_head_init(&cs->rq); - skb_queue_head_init(&cs->sq); - - init_bcstate(cs, 0); - init_bcstate(cs, 1); - - /* init_card only handles interrupts which are not */ - /* used here for the loadable driver */ - switch (card->typ) { - case ISDN_CTYPE_DYNAMIC: - ret = 0; - break; - default: - ret = init_card(cs); - break; - } - if (ret) { - closecard(cardnr); - goto outf_cs; - } - init_tei(cs, cs->protocol); - ret = CallcNewChan(cs); - if (ret) { - closecard(cardnr); - goto outf_cs; - } - /* ISAR needs firmware download first */ - if (!test_bit(HW_ISAR, &cs->HW_Flags)) - ll_run(cs, 0); - - return 1; - -outf_cs: - kfree(cs); - card->cs = NULL; - return 0; -} - -static int checkcard(int cardnr, char *id, int *busy_flag, - struct module *lockowner, hisax_setup_func_t card_setup) -{ - int ret; - struct IsdnCard *card = cards + cardnr; - struct IsdnCardState *cs; - - ret = hisax_cs_new(cardnr, id, card, &cs, busy_flag, lockowner); - if (!ret) - return 0; - - printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, - (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : - "NONE", cs->iif.id, cs->myid); - - ret = card_setup(card); - if (!ret) { - ll_unload(cs); - goto outf_cs; - } - - ret = hisax_cs_setup(cardnr, card, cs); - goto out; - -outf_cs: - kfree(cs); - card->cs = NULL; -out: - return ret; -} - -static void HiSax_shiftcards(int idx) -{ - int i; - - for (i = idx; i < (HISAX_MAX_CARDS - 1); i++) - memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); -} - -static int __init HiSax_inithardware(int *busy_flag) -{ - int foundcards = 0; - int i = 0; - int t = ','; - int flg = 0; - char *id; - char *next_id = HiSax_id; - char ids[20]; - - if (strchr(HiSax_id, ',')) - t = ','; - else if (strchr(HiSax_id, '%')) - t = '%'; - - while (i < nrcards) { - if (cards[i].typ < 1) - break; - id = next_id; - if ((next_id = strchr(id, t))) { - *next_id++ = 0; - strcpy(ids, id); - flg = i + 1; - } else { - next_id = id; - if (flg >= i) - strcpy(ids, id); - else - sprintf(ids, "%s%d", id, i); - } - if (checkcard(i, ids, busy_flag, THIS_MODULE, - hisax_cs_setup_card)) { - foundcards++; - i++; - } else { - /* make sure we don't oops the module */ - if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) { - printk(KERN_WARNING - "HiSax: Card %s not installed !\n", - CardType[cards[i].typ]); - } - HiSax_shiftcards(i); - nrcards--; - } - } - return foundcards; -} - -void HiSax_closecard(int cardnr) -{ - int i, last = nrcards - 1; - - if (cardnr > last || cardnr < 0) - return; - if (cards[cardnr].cs) { - ll_stop(cards[cardnr].cs); - release_tei(cards[cardnr].cs); - CallcFreeChan(cards[cardnr].cs); - - closecard(cardnr); - if (cards[cardnr].cs->irq) - free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); - kfree((void *) cards[cardnr].cs); - cards[cardnr].cs = NULL; - } - i = cardnr; - while (i <= last) { - cards[i] = cards[i + 1]; - i++; - } - nrcards--; -} - -void HiSax_reportcard(int cardnr, int sel) -{ - struct IsdnCardState *cs = cards[cardnr].cs; - - printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); - printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); - printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); - printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%px\n", - HiSax_reportcard); - printk(KERN_DEBUG "HiSax: cs 0x%px\n", cs); - printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n", - cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); - printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n", - cs->bcs[0].mode, cs->bcs[0].channel); - printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n", - cs->bcs[1].mode, cs->bcs[1].channel); -#ifdef ERROR_STATISTIC - printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n", - cs->err_rx, cs->err_crc, cs->err_tx); - printk(KERN_DEBUG - "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", - cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, - cs->bcs[0].err_tx); - printk(KERN_DEBUG - "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", - cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, - cs->bcs[1].err_tx); - if (sel == 99) { - cs->err_rx = 0; - cs->err_crc = 0; - cs->err_tx = 0; - cs->bcs[0].err_inv = 0; - cs->bcs[0].err_rdo = 0; - cs->bcs[0].err_crc = 0; - cs->bcs[0].err_tx = 0; - cs->bcs[1].err_inv = 0; - cs->bcs[1].err_rdo = 0; - cs->bcs[1].err_crc = 0; - cs->bcs[1].err_tx = 0; - } -#endif -} - -static int __init HiSax_init(void) -{ - int i, retval; -#ifdef MODULE - int j; - int nzproto = 0; -#endif - - HiSaxVersion(); - retval = CallcNew(); - if (retval) - goto out; - retval = Isdnl3New(); - if (retval) - goto out_callc; - retval = Isdnl2New(); - if (retval) - goto out_isdnl3; - retval = TeiNew(); - if (retval) - goto out_isdnl2; - retval = Isdnl1New(); - if (retval) - goto out_tei; - -#ifdef MODULE - if (!type[0]) { - /* We 'll register drivers later, but init basic functions */ - for (i = 0; i < HISAX_MAX_CARDS; i++) - cards[i].typ = 0; - return 0; - } -#ifdef CONFIG_HISAX_ELSA - if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { - /* we have exported and return in this case */ - return 0; - } -#endif -#ifdef CONFIG_HISAX_SEDLBAUER - if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) { - /* we have to export and return in this case */ - return 0; - } -#endif -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA - if (type[0] == ISDN_CTYPE_A1_PCMCIA) { - /* we have to export and return in this case */ - return 0; - } -#endif -#ifdef CONFIG_HISAX_HFC_SX - if (type[0] == ISDN_CTYPE_HFC_SP_PCMCIA) { - /* we have to export and return in this case */ - return 0; - } -#endif -#endif - nrcards = 0; -#ifdef MODULE - if (id) /* If id= string used */ - HiSax_id = id; - for (i = j = 0; j < HISAX_MAX_CARDS; i++) { - cards[j].typ = type[i]; - if (protocol[i]) { - cards[j].protocol = protocol[i]; - nzproto++; - } else { - cards[j].protocol = DEFAULT_PROTO; - } - switch (type[i]) { - case ISDN_CTYPE_16_0: - cards[j].para[0] = irq[i]; - cards[j].para[1] = mem[i]; - cards[j].para[2] = io[i]; - break; - - case ISDN_CTYPE_8_0: - cards[j].para[0] = irq[i]; - cards[j].para[1] = mem[i]; - break; - -#ifdef IO0_IO1 - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_NICCY: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io0[i]; - cards[j].para[2] = io1[i]; - break; - case ISDN_CTYPE_COMPAQ_ISA: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io0[i]; - cards[j].para[2] = io1[i]; - cards[j].para[3] = io[i]; - break; -#endif - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_HFC_PCI: - cards[j].para[0] = io[i]; - break; - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_A1: - case ISDN_CTYPE_A1_PCMCIA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_IX1MICROR2: - case ISDN_CTYPE_DIEHLDIVA: - case ISDN_CTYPE_ASUSCOM: - case ISDN_CTYPE_TELEINT: - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - case ISDN_CTYPE_SEDLBAUER_FAX: - case ISDN_CTYPE_SPORTSTER: - case ISDN_CTYPE_MIC: - case ISDN_CTYPE_TELES3C: - case ISDN_CTYPE_ACERP10: - case ISDN_CTYPE_S0BOX: - case ISDN_CTYPE_FRITZPCI: - case ISDN_CTYPE_HSTSAPHIR: - case ISDN_CTYPE_GAZEL: - case ISDN_CTYPE_HFC_SX: - case ISDN_CTYPE_HFC_SP_PCMCIA: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io[i]; - break; - case ISDN_CTYPE_ISURF: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io[i]; - cards[j].para[2] = mem[i]; - break; - case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET_S: - case ISDN_CTYPE_TELESPCI: - case ISDN_CTYPE_W6692: - case ISDN_CTYPE_NETJET_U: - break; - case ISDN_CTYPE_BKM_A4T: - break; - case ISDN_CTYPE_SCT_QUADRO: - if (irq[i]) { - cards[j].para[0] = irq[i]; - } else { - /* QUADRO is a 4 BRI card */ - cards[j++].para[0] = 1; - /* we need to check if further cards can be added */ - if (j < HISAX_MAX_CARDS) { - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 2; - } - if (j < HISAX_MAX_CARDS) { - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 3; - } - if (j < HISAX_MAX_CARDS) { - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j].para[0] = 4; - } - } - break; - } - j++; - } - if (!nzproto) { - printk(KERN_WARNING - "HiSax: Warning - no protocol specified\n"); - printk(KERN_WARNING "HiSax: using protocol %s\n", - DEFAULT_PROTO_NAME); - } -#endif - if (!HiSax_id) - HiSax_id = HiSaxID; - if (!HiSaxID[0]) - strcpy(HiSaxID, "HiSax"); - for (i = 0; i < HISAX_MAX_CARDS; i++) - if (cards[i].typ > 0) - nrcards++; - printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - - /* Install only, if at least one card found */ - if (!HiSax_inithardware(NULL)) - return -ENODEV; - return 0; - -out_tei: - TeiFree(); -out_isdnl2: - Isdnl2Free(); -out_isdnl3: - Isdnl3Free(); -out_callc: - CallcFree(); -out: - return retval; -} - -static void __exit HiSax_exit(void) -{ - int cardnr = nrcards - 1; - - while (cardnr >= 0) - HiSax_closecard(cardnr--); - Isdnl1Free(); - TeiFree(); - Isdnl2Free(); - Isdnl3Free(); - CallcFree(); - printk(KERN_INFO "HiSax module removed\n"); -} - -int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) -{ - u_char ids[16]; - int ret = -1; - - cards[nrcards] = *card; - if (nrcards) - sprintf(ids, "HiSax%d", nrcards); - else - sprintf(ids, "HiSax"); - if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE, - hisax_cs_setup_card)) - goto error; - - ret = nrcards; - nrcards++; -error: - return ret; -} -EXPORT_SYMBOL(hisax_init_pcmcia); - -EXPORT_SYMBOL(HiSax_closecard); - -#include "hisax_if.h" - -EXPORT_SYMBOL(hisax_register); -EXPORT_SYMBOL(hisax_unregister); - -static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg); -static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg); -static void hisax_d_l2l1(struct PStack *st, int pr, void *arg); -static void hisax_b_l2l1(struct PStack *st, int pr, void *arg); -static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg); -static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs); -static void hisax_bc_close(struct BCState *bcs); -static void hisax_bh(struct work_struct *work); -static void EChannel_proc_rcv(struct hisax_d_if *d_if); - -static int hisax_setup_card_dynamic(struct IsdnCard *card) -{ - return 2; -} - -int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], - char *name, int protocol) -{ - int i, retval; - char id[20]; - struct IsdnCardState *cs; - - for (i = 0; i < HISAX_MAX_CARDS; i++) { - if (!cards[i].typ) - break; - } - - if (i >= HISAX_MAX_CARDS) - return -EBUSY; - - cards[i].typ = ISDN_CTYPE_DYNAMIC; - cards[i].protocol = protocol; - sprintf(id, "%s%d", name, i); - nrcards++; - retval = checkcard(i, id, NULL, hisax_d_if->owner, - hisax_setup_card_dynamic); - if (retval == 0) { // yuck - cards[i].typ = 0; - nrcards--; - return -EINVAL; - } - cs = cards[i].cs; - hisax_d_if->cs = cs; - cs->hw.hisax_d_if = hisax_d_if; - cs->cardmsg = hisax_cardmsg; - INIT_WORK(&cs->tqueue, hisax_bh); - cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1; - for (i = 0; i < 2; i++) { - cs->bcs[i].BC_SetStack = hisax_bc_setstack; - cs->bcs[i].BC_Close = hisax_bc_close; - - b_if[i]->ifc.l1l2 = hisax_b_l1l2; - - hisax_d_if->b_if[i] = b_if[i]; - } - hisax_d_if->ifc.l1l2 = hisax_d_l1l2; - skb_queue_head_init(&hisax_d_if->erq); - clear_bit(0, &hisax_d_if->ph_state); - - return 0; -} - -void hisax_unregister(struct hisax_d_if *hisax_d_if) -{ - cards[hisax_d_if->cs->cardnr].typ = 0; - HiSax_closecard(hisax_d_if->cs->cardnr); - skb_queue_purge(&hisax_d_if->erq); -} - -#include "isdnl1.h" - -static void hisax_sched_event(struct IsdnCardState *cs, int event) -{ - test_and_set_bit(event, &cs->event); - schedule_work(&cs->tqueue); -} - -static void hisax_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *st; - int pr; - - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(E_RCVBUFREADY, &cs->event)) - EChannel_proc_rcv(cs->hw.hisax_d_if); - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (test_bit(0, &cs->hw.hisax_d_if->ph_state)) - pr = PH_ACTIVATE | INDICATION; - else - pr = PH_DEACTIVATE | INDICATION; - for (st = cs->stlist; st; st = st->next) - st->l1.l1l2(st, pr, NULL); - - } -} - -static void hisax_b_sched_event(struct BCState *bcs, int event) -{ - test_and_set_bit(event, &bcs->event); - schedule_work(&bcs->tqueue); -} - -static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) d_if; - ifc->l2l1(ifc, pr, arg); -} - -static inline void B_L2L1(struct hisax_b_if *b_if, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) b_if; - ifc->l2l1(ifc, pr, arg); -} - -static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg) -{ - struct hisax_d_if *d_if = (struct hisax_d_if *) ifc; - struct IsdnCardState *cs = d_if->cs; - struct PStack *st; - struct sk_buff *skb; - - switch (pr) { - case PH_ACTIVATE | INDICATION: - set_bit(0, &d_if->ph_state); - hisax_sched_event(cs, D_L1STATECHANGE); - break; - case PH_DEACTIVATE | INDICATION: - clear_bit(0, &d_if->ph_state); - hisax_sched_event(cs, D_L1STATECHANGE); - break; - case PH_DATA | INDICATION: - skb_queue_tail(&cs->rq, arg); - hisax_sched_event(cs, D_RCVBUFREADY); - break; - case PH_DATA | CONFIRM: - skb = skb_dequeue(&cs->sq); - if (skb) { - D_L2L1(d_if, PH_DATA | REQUEST, skb); - break; - } - clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); - for (st = cs->stlist; st; st = st->next) { - if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) { - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - break; - } - } - break; - case PH_DATA_E | INDICATION: - skb_queue_tail(&d_if->erq, arg); - hisax_sched_event(cs, E_RCVBUFREADY); - break; - default: - printk("pr %#x\n", pr); - break; - } -} - -static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg) -{ - struct hisax_b_if *b_if = (struct hisax_b_if *) ifc; - struct BCState *bcs = b_if->bcs; - struct PStack *st = bcs->st; - struct sk_buff *skb; - - // FIXME use isdnl1? - switch (pr) { - case PH_ACTIVATE | INDICATION: - st->l1.l1l2(st, pr, NULL); - break; - case PH_DEACTIVATE | INDICATION: - st->l1.l1l2(st, pr, NULL); - clear_bit(BC_FLG_BUSY, &bcs->Flag); - skb_queue_purge(&bcs->squeue); - bcs->hw.b_if = NULL; - break; - case PH_DATA | INDICATION: - skb_queue_tail(&bcs->rqueue, arg); - hisax_b_sched_event(bcs, B_RCVBUFREADY); - break; - case PH_DATA | CONFIRM: - bcs->tx_cnt -= (long)arg; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += (long)arg; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - skb = skb_dequeue(&bcs->squeue); - if (skb) { - B_L2L1(b_if, PH_DATA | REQUEST, skb); - break; - } - clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) { - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } - break; - default: - printk("hisax_b_l1l2 pr %#x\n", pr); - break; - } -} - -static void hisax_d_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if; - struct sk_buff *skb = arg; - - switch (pr) { - case PH_DATA | REQUEST: - case PH_PULL | INDICATION: - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - Logl2Frame(cs, skb, "PH_DATA_REQ", 0); - // FIXME lock? - if (!test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - D_L2L1(hisax_d_if, PH_DATA | REQUEST, skb); - else - skb_queue_tail(&cs->sq, skb); - break; - case PH_PULL | REQUEST: - if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - default: - D_L2L1(hisax_d_if, pr, arg); - break; - } -} - -static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg) -{ - return 0; -} - -static void hisax_b_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct hisax_b_if *b_if = bcs->hw.b_if; - - switch (pr) { - case PH_ACTIVATE | REQUEST: - B_L2L1(b_if, pr, (void *)(unsigned long)st->l1.mode); - break; - case PH_DATA | REQUEST: - case PH_PULL | INDICATION: - // FIXME lock? - if (!test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) { - B_L2L1(b_if, PH_DATA | REQUEST, arg); - } else { - skb_queue_tail(&bcs->squeue, arg); - } - break; - case PH_PULL | REQUEST: - if (!test_bit(BC_FLG_BUSY, &bcs->Flag)) - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case PH_DEACTIVATE | REQUEST: - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - skb_queue_purge(&bcs->squeue); - /* fall through */ - default: - B_L2L1(b_if, pr, arg); - break; - } -} - -static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if; - - bcs->channel = st->l1.bc; - - bcs->hw.b_if = hisax_d_if->b_if[st->l1.bc]; - hisax_d_if->b_if[st->l1.bc]->bcs = bcs; - - st->l1.bcs = bcs; - st->l2.l2l1 = hisax_b_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - return 0; -} - -static void hisax_bc_close(struct BCState *bcs) -{ - struct hisax_b_if *b_if = bcs->hw.b_if; - - if (b_if) - B_L2L1(b_if, PH_DEACTIVATE | REQUEST, NULL); -} - -static void EChannel_proc_rcv(struct hisax_d_if *d_if) -{ - struct IsdnCardState *cs = d_if->cs; - u_char *ptr; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&d_if->erq)) != NULL) { - if (cs->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += QuickHex(ptr, skb->data, skb->len); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogEcho: ", - "warning Frame too big (%d)", - skb->len); - } - dev_kfree_skb_any(skb); - } -} - -#ifdef CONFIG_PCI -#include - -static const struct pci_device_id hisax_pci_tbl[] __used = { -#ifdef CONFIG_HISAX_FRITZPCI - {PCI_VDEVICE(AVM, PCI_DEVICE_ID_AVM_A1) }, -#endif -#ifdef CONFIG_HISAX_DIEHLDIVA - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20) }, - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U) }, - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201) }, -/*##########################################################################*/ - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202) }, -/*##########################################################################*/ -#endif -#ifdef CONFIG_HISAX_ELSA - {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK) }, - {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000) }, -#endif -#ifdef CONFIG_HISAX_GAZEL - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685) }, - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753) }, - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO) }, - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC) }, -#endif -#ifdef CONFIG_HISAX_SCT_QUADRO - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_9050) }, -#endif -#ifdef CONFIG_HISAX_NICCY - {PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY) }, -#endif -#ifdef CONFIG_HISAX_SEDLBAUER - {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_100) }, -#endif -#if defined(CONFIG_HISAX_NETJET) || defined(CONFIG_HISAX_NETJET_U) - {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_300) }, -#endif -#if defined(CONFIG_HISAX_TELESPCI) || defined(CONFIG_HISAX_SCT_QUADRO) - {PCI_VDEVICE(ZORAN, PCI_DEVICE_ID_ZORAN_36120) }, -#endif -#ifdef CONFIG_HISAX_W6692 - {PCI_VDEVICE(DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH) }, - {PCI_VDEVICE(WINBOND2, PCI_DEVICE_ID_WINBOND2_6692) }, -#endif -#ifdef CONFIG_HISAX_HFC_PCI - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701) }, - {PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1) }, - {PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675) }, - {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT) }, - {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T) }, - {PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575) }, - {PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A) }, -#endif - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(pci, hisax_pci_tbl); -#endif /* CONFIG_PCI */ - -module_init(HiSax_init); -module_exit(HiSax_exit); - -EXPORT_SYMBOL(FsmNew); -EXPORT_SYMBOL(FsmFree); -EXPORT_SYMBOL(FsmEvent); -EXPORT_SYMBOL(FsmChangeState); -EXPORT_SYMBOL(FsmInitTimer); -EXPORT_SYMBOL(FsmDelTimer); -EXPORT_SYMBOL(FsmRestartTimer); diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c deleted file mode 100644 index d23df7a7784d..000000000000 --- a/drivers/isdn/hisax/diva.c +++ /dev/null @@ -1,1282 +0,0 @@ -/* $Id: diva.c,v 1.33.2.6 2004/02/11 13:21:33 keil Exp $ - * - * low level stuff for Eicon.Diehl Diva Family ISDN cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Eicon Technology for documents and information - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "ipac.h" -#include "ipacx.h" -#include "isdnl1.h" -#include -#include - -static const char *Diva_revision = "$Revision: 1.33.2.6 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define DIVA_HSCX_DATA 0 -#define DIVA_HSCX_ADR 4 -#define DIVA_ISA_ISAC_DATA 2 -#define DIVA_ISA_ISAC_ADR 6 -#define DIVA_ISA_CTRL 7 -#define DIVA_IPAC_ADR 0 -#define DIVA_IPAC_DATA 1 - -#define DIVA_PCI_ISAC_DATA 8 -#define DIVA_PCI_ISAC_ADR 0xc -#define DIVA_PCI_CTRL 0x10 - -/* SUB Types */ -#define DIVA_ISA 1 -#define DIVA_PCI 2 -#define DIVA_IPAC_ISA 3 -#define DIVA_IPAC_PCI 4 -#define DIVA_IPACX_PCI 5 - -/* CTRL (Read) */ -#define DIVA_IRQ_STAT 0x01 -#define DIVA_EEPROM_SDA 0x02 - -/* CTRL (Write) */ -#define DIVA_IRQ_REQ 0x01 -#define DIVA_RESET 0x08 -#define DIVA_EEPROM_CLK 0x40 -#define DIVA_PCI_LED_A 0x10 -#define DIVA_PCI_LED_B 0x20 -#define DIVA_ISA_LED_A 0x20 -#define DIVA_ISA_LED_B 0x40 -#define DIVA_IRQ_CLR 0x80 - -/* Siemens PITA */ -#define PITA_MISC_REG 0x1c -#ifdef __BIG_ENDIAN -#define PITA_PARA_SOFTRESET 0x00000001 -#define PITA_SER_SOFTRESET 0x00000002 -#define PITA_PARA_MPX_MODE 0x00000004 -#define PITA_INT0_ENABLE 0x00000200 -#else -#define PITA_PARA_SOFTRESET 0x01000000 -#define PITA_SER_SOFTRESET 0x02000000 -#define PITA_PARA_MPX_MODE 0x04000000 -#define PITA_INT0_ENABLE 0x00020000 -#endif -#define PITA_INT0_STATUS 0x02 - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -static inline u_char -memreadreg(unsigned long adr, u_char off) -{ - return (*((unsigned char *) - (((unsigned int *)adr) + off))); -} - -static inline void -memwritereg(unsigned long adr, u_char off, u_char data) -{ - register u_char *p; - - p = (unsigned char *)(((unsigned int *)adr) + off); - *p = data; -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset + 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.diva.hscx_adr, - cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.diva.hscx_adr, - cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value); -} - -static u_char -MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset + 0x80)); -} - -static void -MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset | 0x80, value); -} - -static void -MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80); -} - -static void -MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++); -} - -static u_char -MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0))); -} - -static void -MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value); -} - -/* IO-Functions for IPACX type cards */ -static u_char -MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset)); -} - -static void -MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset, value); -} - -static void -MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - *data++ = memreadreg(cs->hw.diva.cfg_reg, 0); -} - -static void -MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - memwritereg(cs->hw.diva.cfg_reg, 0, *data++); -} - -static u_char -MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset + - (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1))); -} - -static void -MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset + - (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -diva_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - int cnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) { - val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40); - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); - cnt--; - } - if (!cnt) - printk(KERN_WARNING "Diva: IRQ LOOP\n"); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -diva_irq_ipac_isa(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val; - u_long flags; - int icnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); -Start_IPACISA: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPACISA; - } - if (!icnt) - printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n"); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static inline void -MemwaitforCEC(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); -} - - -static inline void -MemwaitforXFW(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while (((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); -} - -static inline void -MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) -{ - MemwaitforCEC(cs, hscx); - MemWriteHSCX(cs, hscx, HSCX_CMDR, data); -} - -static void -Memhscx_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - int cnt; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_empty_fifo"); - - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hscx_empty_fifo: incoming packet too large"); - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - bcs->hw.hscx.rcvidx = 0; - return; - } - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - cnt = count; - while (cnt--) - *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0); - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_empty_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -Memhscx_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count, cnt; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - u_char *ptr, *p; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_fill_fifo"); - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > fifo_size) { - more = !0; - count = fifo_size; - } else - count = bcs->tx_skb->len; - cnt = count; - MemwaitforXFW(cs, bcs->hw.hscx.hscx); - p = ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - while (cnt--) - memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0, - *p++); - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_fill_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) -{ - u_char r; - struct BCState *bcs = cs->bcs + hscx; - struct sk_buff *skb; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - int count; - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - if (val & 0x80) { /* RME */ - r = MemReadHSCX(cs, hscx, HSCX_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!(r & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX invalid frame"); - if ((r & 0x40) && bcs->mode) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX RDO mode=%d", - bcs->mode); - if (!(r & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX CRC error"); - MemWriteHSCXCMDR(cs, hscx, 0x80); - } else { - count = MemReadHSCX(cs, hscx, HSCX_RBCL) & ( - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f); - if (count == 0) - count = fifo_size; - Memhscx_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HSCX: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - Memhscx_empty_fifo(bcs, fifo_size); - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(fifo_size))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - fifo_size); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & 0x10) { /* XPR */ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - Memhscx_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - Memhscx_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static inline void -Memhscx_int_main(struct IsdnCardState *cs, u_char val) -{ - - u_char exval; - struct BCState *bcs; - - if (val & 0x01) { // EXB - bcs = cs->bcs + 1; - exval = MemReadHSCX(cs, 1, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == 1) - Memhscx_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX B EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B EXIR %x", exval); - } - if (val & 0xf8) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B interrupt %x", val); - Memhscx_interrupt(cs, val, 1); - } - if (val & 0x02) { // EXA - bcs = cs->bcs; - exval = MemReadHSCX(cs, 0, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == L1_MODE_TRANS) - Memhscx_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX A EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A EXIR %x", exval); - } - if (val & 0x04) { // ICA - exval = MemReadHSCX(cs, 0, HSCX_ISTA); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A interrupt %x", exval); - Memhscx_interrupt(cs, exval, 0); - } -} - -static irqreturn_t -diva_irq_ipac_pci(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val; - int icnt = 5; - u_char *cfg; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - cfg = (u_char *) cs->hw.diva.pci_cfg; - val = *cfg; - if (!(val & PITA_INT0_STATUS)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; /* other shared IRQ */ - } - *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */ - ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); -Start_IPACPCI: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - Memhscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPACPCI; - } - if (!icnt) - printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n"); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -diva_irq_ipacx_pci(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_char *cfg; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - cfg = (u_char *) cs->hw.diva.pci_cfg; - val = *cfg; - if (!(val & PITA_INT0_STATUS)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; // other shared IRQ - } - interrupt_ipacx(cs); // handler for chip - *cfg = PITA_INT0_STATUS; // Reset PLX interrupt - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_diva(struct IsdnCardState *cs) -{ - int bytecnt; - - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI)) { - u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg; - - *cfg = 0; /* disable INT0/1 */ - *cfg = 2; /* reset pending INT0 */ - if (cs->hw.diva.cfg_reg) - iounmap((void *)cs->hw.diva.cfg_reg); - if (cs->hw.diva.pci_cfg) - iounmap((void *)cs->hw.diva.pci_cfg); - return; - } else if (cs->subtyp != DIVA_IPAC_ISA) { - del_timer(&cs->hw.diva.tl); - if (cs->hw.diva.cfg_reg) - byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ - } - if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) - bytecnt = 8; - else - bytecnt = 32; - if (cs->hw.diva.cfg_reg) { - release_region(cs->hw.diva.cfg_reg, bytecnt); - } -} - -static void -iounmap_diva(struct IsdnCardState *cs) -{ - if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) { - if (cs->hw.diva.cfg_reg) { - iounmap((void *)cs->hw.diva.cfg_reg); - cs->hw.diva.cfg_reg = 0; - } - if (cs->hw.diva.pci_cfg) { - iounmap((void *)cs->hw.diva.pci_cfg); - cs->hw.diva.pci_cfg = 0; - } - } - - return; -} - -static void -reset_diva(struct IsdnCardState *cs) -{ - if (cs->subtyp == DIVA_IPAC_ISA) { - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); - mdelay(10); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); - mdelay(10); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); - } else if (cs->subtyp == DIVA_IPAC_PCI) { - unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + - PITA_MISC_REG); - *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; - mdelay(10); - *ireg = PITA_PARA_MPX_MODE; - mdelay(10); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); - } else if (cs->subtyp == DIVA_IPACX_PCI) { - unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + - PITA_MISC_REG); - *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; - mdelay(10); - *ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET; - mdelay(10); - MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off - } else { /* DIVA 2.0 */ - cs->hw.diva.ctrl_reg = 0; /* Reset On */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - mdelay(10); - cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - mdelay(10); - if (cs->subtyp == DIVA_ISA) - cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; - else { - /* Workaround PCI9060 */ - byteout(cs->hw.diva.pci_cfg + 0x69, 9); - cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; - } - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - } -} - -#define DIVA_ASSIGN 1 - -static void -diva_led_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.diva.tl); - int blink = 0; - - if ((cs->subtyp == DIVA_IPAC_ISA) || - (cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI)) - return; - del_timer(&cs->hw.diva.tl); - if (cs->hw.diva.status & DIVA_ASSIGN) - cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_A : DIVA_PCI_LED_A; - else { - cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_A : DIVA_PCI_LED_A; - blink = 250; - } - if (cs->hw.diva.status & 0xf000) - cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_B : DIVA_PCI_LED_B; - else if (cs->hw.diva.status & 0x0f00) { - cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_B : DIVA_PCI_LED_B; - blink = 500; - } else - cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_B : DIVA_PCI_LED_B); - - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - if (blink) { - cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000); - add_timer(&cs->hw.diva.tl); - } -} - -static int -Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_int *ireg; - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_diva(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_diva(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_diva(cs); - if (cs->subtyp == DIVA_IPACX_PCI) { - ireg = (unsigned int *)cs->hw.diva.pci_cfg; - *ireg = PITA_INT0_ENABLE; - init_ipacx(cs, 3); // init chip and enable interrupts - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - } - if (cs->subtyp == DIVA_IPAC_PCI) { - ireg = (unsigned int *)cs->hw.diva.pci_cfg; - *ireg = PITA_INT0_ENABLE; - } - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - case (MDL_REMOVE | REQUEST): - cs->hw.diva.status = 0; - break; - case (MDL_ASSIGN | REQUEST): - cs->hw.diva.status |= DIVA_ASSIGN; - break; - case MDL_INFO_SETUP: - if ((long)arg) - cs->hw.diva.status |= 0x0200; - else - cs->hw.diva.status |= 0x0100; - break; - case MDL_INFO_CONN: - if ((long)arg) - cs->hw.diva.status |= 0x2000; - else - cs->hw.diva.status |= 0x1000; - break; - case MDL_INFO_REL: - if ((long)arg) { - cs->hw.diva.status &= ~0x2000; - cs->hw.diva.status &= ~0x0200; - } else { - cs->hw.diva.status &= ~0x1000; - cs->hw.diva.status &= ~0x0100; - } - break; - } - if ((cs->subtyp != DIVA_IPAC_ISA) && - (cs->subtyp != DIVA_IPAC_PCI) && - (cs->subtyp != DIVA_IPACX_PCI)) { - spin_lock_irqsave(&cs->lock, flags); - diva_led_handler(&cs->hw.diva.tl); - spin_unlock_irqrestore(&cs->lock, flags); - } - return (0); -} - -static int setup_diva_common(struct IsdnCardState *cs) -{ - int bytecnt; - u_char val; - - if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) - bytecnt = 8; - else - bytecnt = 32; - - printk(KERN_INFO - "Diva: %s card configured at %#lx IRQ %d\n", - (cs->subtyp == DIVA_PCI) ? "PCI" : - (cs->subtyp == DIVA_ISA) ? "ISA" : - (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : - (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI", - cs->hw.diva.cfg_reg, cs->irq); - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI) || - (cs->subtyp == DIVA_PCI)) - printk(KERN_INFO "Diva: %s space at %#lx\n", - (cs->subtyp == DIVA_PCI) ? "PCI" : - (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI", - cs->hw.diva.pci_cfg); - if ((cs->subtyp != DIVA_IPAC_PCI) && - (cs->subtyp != DIVA_IPACX_PCI)) { - if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { - printk(KERN_WARNING - "HiSax: %s config port %lx-%lx already in use\n", - "diva", - cs->hw.diva.cfg_reg, - cs->hw.diva.cfg_reg + bytecnt); - iounmap_diva(cs); - return (0); - } - } - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Diva_card_msg; - setup_isac(cs); - if (cs->subtyp == DIVA_IPAC_ISA) { - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &diva_irq_ipac_isa; - val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - } else if (cs->subtyp == DIVA_IPAC_PCI) { - cs->readisac = &MemReadISAC_IPAC; - cs->writeisac = &MemWriteISAC_IPAC; - cs->readisacfifo = &MemReadISACfifo_IPAC; - cs->writeisacfifo = &MemWriteISACfifo_IPAC; - cs->BC_Read_Reg = &MemReadHSCX; - cs->BC_Write_Reg = &MemWriteHSCX; - cs->BC_Send_Data = &Memhscx_fill_fifo; - cs->irq_func = &diva_irq_ipac_pci; - val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - } else if (cs->subtyp == DIVA_IPACX_PCI) { - cs->readisac = &MemReadISAC_IPACX; - cs->writeisac = &MemWriteISAC_IPACX; - cs->readisacfifo = &MemReadISACfifo_IPACX; - cs->writeisacfifo = &MemWriteISACfifo_IPACX; - cs->BC_Read_Reg = &MemReadHSCX_IPACX; - cs->BC_Write_Reg = &MemWriteHSCX_IPACX; - cs->BC_Send_Data = NULL; // function located in ipacx module - cs->irq_func = &diva_irq_ipacx_pci; - printk(KERN_INFO "Diva: IPACX Design Id: %x\n", - MemReadISAC_IPACX(cs, IPACX_ID) & 0x3F); - } else { /* DIVA 2.0 */ - timer_setup(&cs->hw.diva.tl, diva_led_handler, 0); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->irq_func = &diva_interrupt; - ISACVersion(cs, "Diva:"); - if (HscxVersion(cs, "Diva:")) { - printk(KERN_WARNING - "Diva: wrong HSCX versions check IO address\n"); - release_io_diva(cs); - return (0); - } - } - return (1); -} - -#ifdef CONFIG_ISA - -static int setup_diva_isa(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - - if (!card->para[1]) - return (-1); /* card not found; continue search */ - - cs->hw.diva.ctrl_reg = 0; - cs->hw.diva.cfg_reg = card->para[1]; - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - if ((val == 1) || (val == 2)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - } - cs->irq = card->para[0]; - - return (1); /* card found */ -} - -#else /* if !CONFIG_ISA */ - -static int setup_diva_isa(struct IsdnCard *card) -{ - return (-1); /* card not found; continue search */ -} - -#endif /* CONFIG_ISA */ - -#ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] = { - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &diva_ids[0]; -static struct pnp_card *pnp_c = NULL; - -static int setup_diva_isapnp(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - struct pnp_dev *pnp_d; - - if (!isapnp_present()) - return (-1); /* card not found; continue search */ - - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - cs->hw.diva.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0xA1)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = - card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = - card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_HSCX_ADR; - } - return (1); /* card found */ - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return (0); - } - } - ipid++; - pnp_c = NULL; - } - - return (-1); /* card not found; continue search */ -} - -#else /* if !ISAPNP */ - -static int setup_diva_isapnp(struct IsdnCard *card) -{ - return (-1); /* card not found; continue search */ -} - -#endif /* ISAPNP */ - -#ifdef CONFIG_PCI -static struct pci_dev *dev_diva = NULL; -static struct pci_dev *dev_diva_u = NULL; -static struct pci_dev *dev_diva201 = NULL; -static struct pci_dev *dev_diva202 = NULL; - -static int setup_diva_pci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - - cs->subtyp = 0; - if ((dev_diva = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { - if (pci_enable_device(dev_diva)) - return (0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { - if (pci_enable_device(dev_diva_u)) - return (0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { - if (pci_enable_device(dev_diva201)) - return (0); - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = dev_diva201->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); - } else if ((dev_diva202 = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { - if (pci_enable_device(dev_diva202)) - return (0); - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = dev_diva202->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); - } else { - return (-1); /* card not found; continue search */ - } - - if (!cs->irq) { - printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); - iounmap_diva(cs); - return (0); - } - - if (!cs->hw.diva.cfg_reg) { - printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); - iounmap_diva(cs); - return (0); - } - cs->irq_flags |= IRQF_SHARED; - - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI)) { - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = 0; - cs->hw.diva.hscx = 0; - cs->hw.diva.isac_adr = 0; - cs->hw.diva.hscx_adr = 0; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - } - - return (1); /* card found */ -} - -#else /* if !CONFIG_PCI */ - -static int setup_diva_pci(struct IsdnCard *card) -{ - return (-1); /* card not found; continue search */ -} - -#endif /* CONFIG_PCI */ - -int setup_diva(struct IsdnCard *card) -{ - int rc, have_card = 0; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Diva_revision); - printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_DIEHLDIVA) - return (0); - cs->hw.diva.status = 0; - - rc = setup_diva_isa(card); - if (!rc) - return rc; - if (rc > 0) { - have_card = 1; - goto ready; - } - - rc = setup_diva_isapnp(card); - if (!rc) - return rc; - if (rc > 0) { - have_card = 1; - goto ready; - } - - rc = setup_diva_pci(card); - if (!rc) - return rc; - if (rc > 0) - have_card = 1; - -ready: - if (!have_card) { - printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n"); - return (0); - } - - return setup_diva_common(card->cs); -} diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c deleted file mode 100644 index 0754c0743790..000000000000 --- a/drivers/isdn/hisax/elsa.c +++ /dev/null @@ -1,1245 +0,0 @@ -/* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $ - * - * low level stuff for Elsa isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Elsa GmbH for documents and information - * - * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE) - * for ELSA PCMCIA support - * - */ - -#include -#include -#include "hisax.h" -#include "arcofi.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isdnl1.h" -#include -#include -#include -#include - -static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; -static const char *Elsa_Types[] = -{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", - "PCMCIA-IPAC" }; - -static const char *ITACVer[] = -{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", - "B1", "A1"}; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ELSA_ISAC 0 -#define ELSA_ISAC_PCM 1 -#define ELSA_ITAC 1 -#define ELSA_HSCX 2 -#define ELSA_ALE 3 -#define ELSA_ALE_PCM 4 -#define ELSA_CONTROL 4 -#define ELSA_CONFIG 5 -#define ELSA_START_TIMER 6 -#define ELSA_TRIG_IRQ 7 - -#define ELSA_PC 1 -#define ELSA_PCC8 2 -#define ELSA_PCC16 3 -#define ELSA_PCF 4 -#define ELSA_PCFPRO 5 -#define ELSA_PCMCIA 6 -#define ELSA_QS1000 7 -#define ELSA_QS3000 8 -#define ELSA_QS1000PCI 9 -#define ELSA_QS3000PCI 10 -#define ELSA_PCMCIA_IPAC 11 - -/* PCI stuff */ -#define ELSA_PCI_IRQ_MASK 0x04 - -/* ITAC Registeradressen (only Microlink PC) */ -#define ITAC_SYS 0x34 -#define ITAC_ISEN 0x48 -#define ITAC_RFIE 0x4A -#define ITAC_XFIE 0x4C -#define ITAC_SCIE 0x4E -#define ITAC_STIE 0x46 - -/*** *** - *** Makros als Befehle fuer die Kartenregister *** - *** (mehrere Befehle werden durch Bit-Oderung kombiniert) *** - *** ***/ - -/* Config-Register (Read) */ -#define ELIRQF_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */ -#define ELIRQF_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */ -#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */ -#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */ -#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */ - -/* Control-Register (Write) */ -#define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */ -#define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */ -#define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */ -#define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */ - -/* ALE-Register (Read) */ -#define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */ -#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */ - -/* Status Flags */ -#define ELIRQF_TIMER_AKTIV 1 -#define ELSA_BAD_PWR 2 -#define ELSA_ASSIGN 4 - -#define RS_ISR_PASS_LIMIT 256 -#define FLG_MODEM_ACTIVE 1 -/* IPAC AUX */ -#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ -#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ - -#if ARCOFI_USE -static struct arcofi_msg ARCOFI_XOP_F = -{NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */ -static struct arcofi_msg ARCOFI_XOP_1 = -{&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */ -static struct arcofi_msg ARCOFI_SOP_F = -{&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}}; -static struct arcofi_msg ARCOFI_COP_9 = -{&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */ -static struct arcofi_msg ARCOFI_COP_8 = -{&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */ -static struct arcofi_msg ARCOFI_COP_7 = -{&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */ -static struct arcofi_msg ARCOFI_COP_6 = -{&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */ -static struct arcofi_msg ARCOFI_COP_5 = -{&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */ -static struct arcofi_msg ARCOFI_VERSION = -{NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}}; -static struct arcofi_msg ARCOFI_XOP_0 = -{NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */ - -static void set_arcofi(struct IsdnCardState *cs, int bc); - -#include "elsa_ser.c" -#endif /* ARCOFI_USE */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset + 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.elsa.ale, - cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.elsa.ale, - cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value); -} - -static inline u_char -readitac(struct IsdnCardState *cs, u_char off) -{ - register u_char ret; - - byteout(cs->hw.elsa.ale, off); - ret = bytein(cs->hw.elsa.itac); - return (ret); -} - -static inline void -writeitac(struct IsdnCardState *cs, u_char off, u_char data) -{ - byteout(cs->hw.elsa.ale, off); - byteout(cs->hw.elsa.itac, data); -} - -static inline int -TimerRun(struct IsdnCardState *cs) -{ - register u_char v; - - v = bytein(cs->hw.elsa.cfg); - if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000)) - return (0 == (v & ELIRQF_TIMER_RUN)); - else if (cs->subtyp == ELSA_PCC8) - return (v & ELIRQF_TIMER_RUN_PCC8); - return (v & ELIRQF_TIMER_RUN); -} -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -elsa_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_long flags; - u_char val; - int icnt = 5; - - if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Elsa: card not available!\n"); - return IRQ_NONE; - } - spin_lock_irqsave(&cs->lock, flags); -#if ARCOFI_USE - if (cs->hw.elsa.MFlag) { - val = serial_inp(cs, UART_IIR); - if (!(val & UART_IIR_NO_INT)) { - debugl1(cs, "IIR %02x", val); - rs_interrupt_elsa(cs); - } - } -#endif - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) { - hscx_int_main(cs, val); - } - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); -Start_ISAC: - if (val) { - isac_interrupt(cs, val); - } - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); - if (val && icnt) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - icnt--; - goto Start_HSCX; - } - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); - if (val && icnt) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - icnt--; - goto Start_ISAC; - } - if (!icnt) - printk(KERN_WARNING"ELSA IRQ LOOP\n"); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF); - if (cs->hw.elsa.status & ELIRQF_TIMER_AKTIV) { - if (!TimerRun(cs)) { - /* Timer Restart */ - byteout(cs->hw.elsa.timer, 0); - cs->hw.elsa.counter++; - } - } -#if ARCOFI_USE - if (cs->hw.elsa.MFlag) { - val = serial_inp(cs, UART_MCR); - val ^= 0x8; - serial_outp(cs, UART_MCR, val); - val = serial_inp(cs, UART_MCR); - val ^= 0x8; - serial_outp(cs, UART_MCR, val); - } -#endif - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0x00); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -elsa_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_long flags; - u_char ista, val; - int icnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { - val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ - if (!(val & ELSA_PCI_IRQ_MASK)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - } -#if ARCOFI_USE - if (cs->hw.elsa.MFlag) { - val = serial_inp(cs, UART_IIR); - if (!(val & UART_IIR_NO_INT)) { - debugl1(cs, "IIR %02x", val); - rs_interrupt_elsa(cs); - } - } -#endif - ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "ELSA IRQ LOOP\n"); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_elsa(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - del_timer(&cs->hw.elsa.tl); -#if ARCOFI_USE - clear_arcofi(cs); -#endif - if (cs->hw.elsa.ctrl) - byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ - if (cs->subtyp == ELSA_QS1000PCI) { - byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - bytecnt = 2; - release_region(cs->hw.elsa.cfg, 0x80); - } - if (cs->subtyp == ELSA_QS3000PCI) { - byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - release_region(cs->hw.elsa.cfg, 0x80); - } - if (cs->subtyp == ELSA_PCMCIA_IPAC) { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - } - if ((cs->subtyp == ELSA_PCFPRO) || - (cs->subtyp == ELSA_QS3000) || - (cs->subtyp == ELSA_PCF) || - (cs->subtyp == ELSA_QS3000PCI)) { - bytecnt = 16; -#if ARCOFI_USE - release_modem(cs); -#endif - } - if (cs->hw.elsa.base) - release_region(cs->hw.elsa.base, bytecnt); -} - -static void -reset_elsa(struct IsdnCardState *cs) -{ - if (cs->hw.elsa.timer) { - /* Wait 1 Timer */ - byteout(cs->hw.elsa.timer, 0); - while (TimerRun(cs)); - cs->hw.elsa.ctrl_reg |= 0x50; - cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */ - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - /* Wait 1 Timer */ - byteout(cs->hw.elsa.timer, 0); - while (TimerRun(cs)); - cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */ - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - /* Wait 1 Timer */ - byteout(cs->hw.elsa.timer, 0); - while (TimerRun(cs)); - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - } - if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); - mdelay(10); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); - mdelay(10); - if (cs->subtyp != ELSA_PCMCIA_IPAC) { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c); - } else { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8); - } - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - if (cs->subtyp == ELSA_QS1000PCI) - byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ - else if (cs->subtyp == ELSA_QS3000PCI) - byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */ - } -} - -#if ARCOFI_USE - -static void -set_arcofi(struct IsdnCardState *cs, int bc) { - cs->dc.isac.arcofi_bc = bc; - arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5); - wait_event_interruptible(cs->dc.isac.arcofi_wait, - cs->dc.isac.arcofi_state == ARCOFI_NOP); -} - -static int -check_arcofi(struct IsdnCardState *cs) -{ - int arcofi_present = 0; - char tmp[40]; - char *t; - u_char *p; - - if (!cs->dc.isac.mon_tx) - if (!(cs->dc.isac.mon_tx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON TX out of buffers!"); - return (0); - } - cs->dc.isac.arcofi_bc = 0; - arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION); - wait_event_interruptible(cs->dc.isac.arcofi_wait, - cs->dc.isac.arcofi_state == ARCOFI_NOP); - if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) { - debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp); - p = cs->dc.isac.mon_rx; - t = tmp; - t += sprintf(tmp, "Arcofi data"); - QuickHex(t, p, cs->dc.isac.mon_rxp); - debugl1(cs, "%s", tmp); - if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) { - switch (cs->dc.isac.mon_rx[1]) { - case 0x80: - debugl1(cs, "Arcofi 2160 detected"); - arcofi_present = 1; - break; - case 0x82: - debugl1(cs, "Arcofi 2165 detected"); - arcofi_present = 2; - break; - case 0x84: - debugl1(cs, "Arcofi 2163 detected"); - arcofi_present = 3; - break; - default: - debugl1(cs, "unknown Arcofi response"); - break; - } - } else - debugl1(cs, "undefined Monitor response"); - cs->dc.isac.mon_rxp = 0; - } else if (cs->dc.isac.mon_tx) { - debugl1(cs, "Arcofi not detected"); - } - if (arcofi_present) { - if (cs->subtyp == ELSA_QS1000) { - cs->subtyp = ELSA_QS3000; - printk(KERN_INFO - "Elsa: %s detected modem at 0x%lx\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8); - release_region(cs->hw.elsa.base, 8); - if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { - printk(KERN_WARNING - "HiSax: %s config port %lx-%lx already in use\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8, - cs->hw.elsa.base + 16); - } - } else if (cs->subtyp == ELSA_PCC16) { - cs->subtyp = ELSA_PCF; - printk(KERN_INFO - "Elsa: %s detected modem at 0x%lx\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8); - release_region(cs->hw.elsa.base, 8); - if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { - printk(KERN_WARNING - "HiSax: %s config port %lx-%lx already in use\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8, - cs->hw.elsa.base + 16); - } - } else - printk(KERN_INFO - "Elsa: %s detected modem at 0x%lx\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8); - arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); - wait_event_interruptible(cs->dc.isac.arcofi_wait, - cs->dc.isac.arcofi_state == ARCOFI_NOP); - return (1); - } - return (0); -} -#endif /* ARCOFI_USE */ - -static void -elsa_led_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.elsa.tl); - int blink = 0; - - if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC) - return; - del_timer(&cs->hw.elsa.tl); - if (cs->hw.elsa.status & ELSA_ASSIGN) - cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED; - else if (cs->hw.elsa.status & ELSA_BAD_PWR) - cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED; - else { - cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED; - blink = 250; - } - if (cs->hw.elsa.status & 0xf000) - cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED; - else if (cs->hw.elsa.status & 0x0f00) { - cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED; - blink = 500; - } else - cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED; - - if ((cs->subtyp == ELSA_QS1000PCI) || - (cs->subtyp == ELSA_QS3000PCI)) { - u_char led = 0xff; - if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) - led ^= ELSA_IPAC_LINE_LED; - if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) - led ^= ELSA_IPAC_STAT_LED; - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); - } else - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - if (blink) { - cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); - add_timer(&cs->hw.elsa.tl); - } -} - -static int -Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - int ret = 0; - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_elsa(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_elsa(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - cs->debug |= L1_DEB_IPAC; - reset_elsa(cs); - inithscxisac(cs, 1); - if ((cs->subtyp == ELSA_QS1000) || - (cs->subtyp == ELSA_QS3000)) - { - byteout(cs->hw.elsa.timer, 0); - } - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - if ((cs->subtyp == ELSA_PCMCIA) || - (cs->subtyp == ELSA_PCMCIA_IPAC) || - (cs->subtyp == ELSA_QS1000PCI)) { - return (0); - } else if (cs->subtyp == ELSA_QS3000PCI) { - ret = 0; - } else { - spin_lock_irqsave(&cs->lock, flags); - cs->hw.elsa.counter = 0; - cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT; - cs->hw.elsa.status |= ELIRQF_TIMER_AKTIV; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - byteout(cs->hw.elsa.timer, 0); - spin_unlock_irqrestore(&cs->lock, flags); - msleep(110); - spin_lock_irqsave(&cs->lock, flags); - cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - cs->hw.elsa.status &= ~ELIRQF_TIMER_AKTIV; - spin_unlock_irqrestore(&cs->lock, flags); - printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", - cs->hw.elsa.counter); - if ((cs->hw.elsa.counter > 10) && - (cs->hw.elsa.counter < 16)) { - printk(KERN_INFO "Elsa: timer and irq OK\n"); - ret = 0; - } else { - printk(KERN_WARNING - "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", - cs->hw.elsa.counter, cs->irq); - ret = 1; - } - } -#if ARCOFI_USE - if (check_arcofi(cs)) { - init_modem(cs); - } -#endif - elsa_led_handler(&cs->hw.elsa.tl); - return (ret); - case (MDL_REMOVE | REQUEST): - cs->hw.elsa.status &= 0; - break; - case (MDL_ASSIGN | REQUEST): - cs->hw.elsa.status |= ELSA_ASSIGN; - break; - case MDL_INFO_SETUP: - if ((long) arg) - cs->hw.elsa.status |= 0x0200; - else - cs->hw.elsa.status |= 0x0100; - break; - case MDL_INFO_CONN: - if ((long) arg) - cs->hw.elsa.status |= 0x2000; - else - cs->hw.elsa.status |= 0x1000; - break; - case MDL_INFO_REL: - if ((long) arg) { - cs->hw.elsa.status &= ~0x2000; - cs->hw.elsa.status &= ~0x0200; - } else { - cs->hw.elsa.status &= ~0x1000; - cs->hw.elsa.status &= ~0x0100; - } - break; -#if ARCOFI_USE - case CARD_AUX_IND: - if (cs->hw.elsa.MFlag) { - int len; - u_char *msg; - - if (!arg) - return (0); - msg = arg; - len = *msg; - msg++; - modem_write_cmd(cs, msg, len); - } - break; -#endif - } - if (cs->typ == ISDN_CTYPE_ELSA) { - int pwr = bytein(cs->hw.elsa.ale); - if (pwr & 0x08) - cs->hw.elsa.status |= ELSA_BAD_PWR; - else - cs->hw.elsa.status &= ~ELSA_BAD_PWR; - } - elsa_led_handler(&cs->hw.elsa.tl); - return (ret); -} - -static unsigned char -probe_elsa_adr(unsigned int adr, int typ) -{ - int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0, - pc_2 = 0, pfp_1 = 0, pfp_2 = 0; - - /* In case of the elsa pcmcia card, this region is in use, - reserved for us by the card manager. So we do not check it - here, it would fail. */ - if (typ != ISDN_CTYPE_ELSA_PCMCIA) { - if (request_region(adr, 8, "elsa card")) { - release_region(adr, 8); - } else { - printk(KERN_WARNING - "Elsa: Probing Port 0x%x: already in use\n", adr); - return (0); - } - } - for (i = 0; i < 16; i++) { - in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */ - in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */ - p16_1 += 0x04 & in1; - p16_2 += 0x04 & in2; - p8_1 += 0x02 & in1; - p8_2 += 0x02 & in2; - pc_1 += 0x01 & in1; - pc_2 += 0x01 & in2; - pfp_1 += 0x40 & in1; - pfp_2 += 0x40 & in2; - } - printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); - if (65 == ++p16_1 * ++p16_2) { - printk(" PCC-16/PCF found\n"); - return (ELSA_PCC16); - } else if (1025 == ++pfp_1 * ++pfp_2) { - printk(" PCF-Pro found\n"); - return (ELSA_PCFPRO); - } else if (33 == ++p8_1 * ++p8_2) { - printk(" PCC8 found\n"); - return (ELSA_PCC8); - } else if (17 == ++pc_1 * ++pc_2) { - printk(" PC found\n"); - return (ELSA_PC); - } else { - printk(" failed\n"); - return (0); - } -} - -static unsigned int -probe_elsa(struct IsdnCardState *cs) -{ - int i; - unsigned int CARD_portlist[] = - {0x160, 0x170, 0x260, 0x360, 0}; - - for (i = 0; CARD_portlist[i]; i++) { - if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ))) - break; - } - return (CARD_portlist[i]); -} - -static int setup_elsa_isa(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, - cs->typ))) { - printk(KERN_WARNING - "Elsa: no Elsa Microlink at %#lx\n", - cs->hw.elsa.base); - return (0); - } - } else - cs->hw.elsa.base = probe_elsa(cs); - - if (!cs->hw.elsa.base) { - printk(KERN_WARNING - "No Elsa Microlink found\n"); - return (0); - } - - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u_char CARD_IrqTab[8] = - {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val == 'G')) - val = 'C'; - printk(KERN_INFO - "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING - "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - - return (1); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id elsa_ids[] = { - { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), - ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), - (unsigned long) "Elsa QS1000" }, - { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), - ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), - (unsigned long) "Elsa QS3000" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &elsa_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif /* __ISAPNP__ */ - -static int setup_elsa_isapnp(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - if (ipid->function == ISAPNP_FUNCTION(0x133)) - cs->subtyp = ELSA_QS1000; - else - cs->subtyp = ELSA_QS3000; - break; - } else { - printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); - return (0); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif /* __ISAPNP__ */ - - if (card->para[1] && card->para[0]) { - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - if (!cs->subtyp) - cs->subtyp = ELSA_QS1000; - } else { - printk(KERN_ERR "Elsa PnP: no parameter\n"); - } - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - - return (1); -} - -static void setup_elsa_pcmcia(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - cs->hw.elsa.hscx = cs->hw.elsa.base + 2; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); -} - -#ifdef CONFIG_PCI -static struct pci_dev *dev_qs1000 = NULL; -static struct pci_dev *dev_qs3000 = NULL; - -static int setup_elsa_pci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - - cs->subtyp = 0; - if ((dev_qs1000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (pci_enable_device(dev_qs1000)) - return (0); - cs->subtyp = ELSA_QS1000PCI; - cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (pci_enable_device(dev_qs3000)) - return (0); - cs->subtyp = ELSA_QS3000PCI; - cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); - } else { - printk(KERN_WARNING "Elsa: No PCI card found\n"); - return (0); - } - if (!cs->irq) { - printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); - return (0); - } - - if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { - printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); - return (0); - } - if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { - printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); - printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); - printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base + 1; - cs->hw.elsa.hscx = cs->hw.elsa.base + 1; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); - - return (1); -} - -#else - -static int setup_elsa_pci(struct IsdnCard *card) -{ - return (1); -} -#endif /* CONFIG_PCI */ - -static int setup_elsa_common(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - int bytecnt; - - switch (cs->subtyp) { - case ELSA_PC: - case ELSA_PCC8: - case ELSA_PCC16: - case ELSA_QS1000: - case ELSA_PCMCIA: - case ELSA_PCMCIA_IPAC: - bytecnt = 8; - break; - case ELSA_PCFPRO: - case ELSA_PCF: - case ELSA_QS3000: - case ELSA_QS3000PCI: - bytecnt = 16; - break; - case ELSA_QS1000PCI: - bytecnt = 2; - break; - default: - printk(KERN_WARNING - "Unknown ELSA subtype %d\n", cs->subtyp); - return (0); - } - /* In case of the elsa pcmcia card, this region is in use, - reserved for us by the card manager. So we do not check it - here, it would fail. */ - if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { - printk(KERN_WARNING - "HiSax: ELSA config port %#lx-%#lx already in use\n", - cs->hw.elsa.base, - cs->hw.elsa.base + bytecnt); - return (0); - } - if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { - if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { - printk(KERN_WARNING - "HiSax: ELSA pci port %x-%x already in use\n", - cs->hw.elsa.cfg, - cs->hw.elsa.cfg + 0x80); - release_region(cs->hw.elsa.base, bytecnt); - return (0); - } - } -#if ARCOFI_USE - init_arcofi(cs); -#endif - setup_isac(cs); - timer_setup(&cs->hw.elsa.tl, elsa_led_handler, 0); - /* Teste Timer */ - if (cs->hw.elsa.timer) { - byteout(cs->hw.elsa.trig, 0xff); - byteout(cs->hw.elsa.timer, 0); - if (!TimerRun(cs)) { - byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */ - if (!TimerRun(cs)) { - printk(KERN_WARNING - "Elsa: timer do not start\n"); - release_io_elsa(cs); - return (0); - } - } - HZDELAY((HZ / 100) + 1); /* wait >=10 ms */ - if (TimerRun(cs)) { - printk(KERN_WARNING "Elsa: timer do not run down\n"); - release_io_elsa(cs); - return (0); - } - printk(KERN_INFO "Elsa: timer OK; resetting card\n"); - } - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Elsa_card_msg; - if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &elsa_interrupt_ipac; - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID); - printk(KERN_INFO "Elsa: IPAC version %x\n", val); - } else { - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->irq_func = &elsa_interrupt; - ISACVersion(cs, "Elsa:"); - if (HscxVersion(cs, "Elsa:")) { - printk(KERN_WARNING - "Elsa: wrong HSCX versions check IO address\n"); - release_io_elsa(cs); - return (0); - } - } - if (cs->subtyp == ELSA_PC) { - val = readitac(cs, ITAC_SYS); - printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); - writeitac(cs, ITAC_ISEN, 0); - writeitac(cs, ITAC_RFIE, 0); - writeitac(cs, ITAC_XFIE, 0); - writeitac(cs, ITAC_SCIE, 0); - writeitac(cs, ITAC_STIE, 0); - } - return (1); -} - -int setup_elsa(struct IsdnCard *card) -{ - int rc; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Elsa_revision); - printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - cs->hw.elsa.ctrl_reg = 0; - cs->hw.elsa.status = 0; - cs->hw.elsa.MFlag = 0; - cs->subtyp = 0; - - if (cs->typ == ISDN_CTYPE_ELSA) { - rc = setup_elsa_isa(card); - if (!rc) - return (0); - - } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { - rc = setup_elsa_isapnp(card); - if (!rc) - return (0); - - } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) - setup_elsa_pcmcia(card); - - else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { - rc = setup_elsa_pci(card); - if (!rc) - return (0); - - } else - return (0); - - return setup_elsa_common(card); -} diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c deleted file mode 100644 index 40f6fad79de3..000000000000 --- a/drivers/isdn/hisax/elsa_cs.c +++ /dev/null @@ -1,218 +0,0 @@ -/*====================================================================== - - An elsa_cs PCMCIA client driver - - This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink - - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus - Lichtenwalder . All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - - ======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards"); -MODULE_AUTHOR("Klaus Lichtenwalder"); -MODULE_LICENSE("Dual MPL/GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int elsa_cs_config(struct pcmcia_device *link); -static void elsa_cs_release(struct pcmcia_device *link); -static void elsa_cs_detach(struct pcmcia_device *p_dev); - -typedef struct local_info_t { - struct pcmcia_device *p_dev; - int busy; - int cardnr; -} local_info_t; - -static int elsa_cs_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - dev_dbg(&link->dev, "elsa_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) return -ENOMEM; - - local->p_dev = link; - link->priv = local; - - local->cardnr = -1; - - return elsa_cs_config(link); -} /* elsa_cs_attach */ - -static void elsa_cs_detach(struct pcmcia_device *link) -{ - local_info_t *info = link->priv; - - dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link); - - info->busy = 1; - elsa_cs_release(link); - - kfree(info); -} /* elsa_cs_detach */ - -static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - int j; - - p_dev->io_lines = 3; - p_dev->resource[0]->end = 8; - p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { - printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); - if (!pcmcia_request_io(p_dev)) - return 0; - } else { - printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); - for (j = 0x2f0; j > 0x100; j -= 0x10) { - p_dev->resource[0]->start = j; - if (!pcmcia_request_io(p_dev)) - return 0; - } - } - return -ENODEV; -} - -static int elsa_cs_config(struct pcmcia_device *link) -{ - int i; - IsdnCard_t icard; - - dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL); - if (i != 0) - goto failed; - - if (!link->irq) - goto failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto failed; - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = protocol; - icard.typ = ISDN_CTYPE_ELSA_PCMCIA; - - i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard); - if (i < 0) { - printk(KERN_ERR "elsa_cs: failed to initialize Elsa " - "PCMCIA %d with %pR\n", i, link->resource[0]); - elsa_cs_release(link); - } else - ((local_info_t *)link->priv)->cardnr = i; - - return 0; -failed: - elsa_cs_release(link); - return -ENODEV; -} /* elsa_cs_config */ - -static void elsa_cs_release(struct pcmcia_device *link) -{ - local_info_t *local = link->priv; - - dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link); - - if (local) { - if (local->cardnr >= 0) { - /* no unregister function with hisax */ - HiSax_closecard(local->cardnr); - } - } - - pcmcia_disable_device(link); -} /* elsa_cs_release */ - -static int elsa_suspend(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 1; - - return 0; -} - -static int elsa_resume(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 0; - - return 0; -} - -static const struct pcmcia_device_id elsa_ids[] = { - PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257), - PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, elsa_ids); - -static struct pcmcia_driver elsa_cs_driver = { - .owner = THIS_MODULE, - .name = "elsa_cs", - .probe = elsa_cs_probe, - .remove = elsa_cs_detach, - .id_table = elsa_ids, - .suspend = elsa_suspend, - .resume = elsa_resume, -}; -module_pcmcia_driver(elsa_cs_driver); diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c deleted file mode 100644 index 999effd7a276..000000000000 --- a/drivers/isdn/hisax/elsa_ser.c +++ /dev/null @@ -1,659 +0,0 @@ -/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $ - * - * stuff for the serial modem on ELSA cards - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include - -#define MAX_MODEM_BUF 256 -#define WAKEUP_CHARS (MAX_MODEM_BUF / 2) -#define RS_ISR_PASS_LIMIT 256 -#define BASE_BAUD (1843200 / 16) - -//#define SERIAL_DEBUG_OPEN 1 -//#define SERIAL_DEBUG_INTR 1 -//#define SERIAL_DEBUG_FLOW 1 -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_REG -//#define SERIAL_DEBUG_REG 1 - -#ifdef SERIAL_DEBUG_REG -static u_char deb[32]; -const char *ModemIn[] = {"RBR", "IER", "IIR", "LCR", "MCR", "LSR", "MSR", "SCR"}; -const char *ModemOut[] = {"THR", "IER", "FCR", "LCR", "MCR", "LSR", "MSR", "SCR"}; -#endif - -static char *MInit_1 = "AT&F&C1E0&D2\r\0"; -static char *MInit_2 = "ATL2M1S64=13\r\0"; -static char *MInit_3 = "AT+FCLASS=0\r\0"; -static char *MInit_4 = "ATV1S2=128X1\r\0"; -static char *MInit_5 = "AT\\V8\\N3\r\0"; -static char *MInit_6 = "ATL0M0&G0%E1\r\0"; -static char *MInit_7 = "AT%L1%M0%C3\r\0"; - -static char *MInit_speed28800 = "AT%G0%B28800\r\0"; - -static char *MInit_dialout = "ATs7=60 x1 d\r\0"; -static char *MInit_dialin = "ATs7=60 x1 a\r\0"; - - -static inline unsigned int serial_in(struct IsdnCardState *cs, int offset) -{ -#ifdef SERIAL_DEBUG_REG - u_int val = inb(cs->hw.elsa.base + 8 + offset); - debugl1(cs, "in %s %02x", ModemIn[offset], val); - return (val); -#else - return inb(cs->hw.elsa.base + 8 + offset); -#endif -} - -static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset) -{ -#ifdef SERIAL_DEBUG_REG -#ifdef ELSA_SERIAL_NOPAUSE_IO - u_int val = inb(cs->hw.elsa.base + 8 + offset); - debugl1(cs, "inp %s %02x", ModemIn[offset], val); -#else - u_int val = inb_p(cs->hw.elsa.base + 8 + offset); - debugl1(cs, "inP %s %02x", ModemIn[offset], val); -#endif - return (val); -#else -#ifdef ELSA_SERIAL_NOPAUSE_IO - return inb(cs->hw.elsa.base + 8 + offset); -#else - return inb_p(cs->hw.elsa.base + 8 + offset); -#endif -#endif -} - -static inline void serial_out(struct IsdnCardState *cs, int offset, int value) -{ -#ifdef SERIAL_DEBUG_REG - debugl1(cs, "out %s %02x", ModemOut[offset], value); -#endif - outb(value, cs->hw.elsa.base + 8 + offset); -} - -static inline void serial_outp(struct IsdnCardState *cs, int offset, - int value) -{ -#ifdef SERIAL_DEBUG_REG -#ifdef ELSA_SERIAL_NOPAUSE_IO - debugl1(cs, "outp %s %02x", ModemOut[offset], value); -#else - debugl1(cs, "outP %s %02x", ModemOut[offset], value); -#endif -#endif -#ifdef ELSA_SERIAL_NOPAUSE_IO - outb(value, cs->hw.elsa.base + 8 + offset); -#else - outb_p(value, cs->hw.elsa.base + 8 + offset); -#endif -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(struct IsdnCardState *cs, int baud) -{ - int quot = 0, baud_base; - unsigned cval, fcr = 0; - - - /* byte size and parity */ - cval = 0x03; - /* Determine divisor based on baud rate */ - baud_base = BASE_BAUD; - quot = baud_base / baud; - /* If the quotient is ever zero, default to 9600 bps */ - if (!quot) - quot = baud_base / 9600; - - /* Set up FIFO's */ - if ((baud_base / quot) < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; - serial_outp(cs, UART_FCR, fcr); - /* CTS flow control flag and modem status interrupts */ - cs->hw.elsa.IER &= ~UART_IER_MSI; - cs->hw.elsa.IER |= UART_IER_MSI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - - debugl1(cs, "modem quot=0x%x", quot); - serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */ - serial_outp(cs, UART_LCR, cval); /* reset DLAB */ - serial_inp(cs, UART_RX); -} - -static int mstartup(struct IsdnCardState *cs) -{ - int retval = 0; - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); - - /* - * At this point there's no way the LSR could still be 0xFF; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (serial_inp(cs, UART_LSR) == 0xff) { - retval = -ENODEV; - goto errout; - } - - /* - * Clear the interrupt registers. - */ - (void) serial_inp(cs, UART_RX); - (void) serial_inp(cs, UART_IIR); - (void) serial_inp(cs, UART_MSR); - - /* - * Now, initialize the UART - */ - serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - - cs->hw.elsa.MCR = 0; - cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; - serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); - - /* - * Finally, enable interrupts - */ - cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */ - - /* - * And clear the interrupt registers again for luck. - */ - (void)serial_inp(cs, UART_LSR); - (void)serial_inp(cs, UART_RX); - (void)serial_inp(cs, UART_IIR); - (void)serial_inp(cs, UART_MSR); - - cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0; - cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp = 0; - - /* - * and set the speed of the serial port - */ - change_speed(cs, BASE_BAUD); - cs->hw.elsa.MFlag = 1; -errout: - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void mshutdown(struct IsdnCardState *cs) -{ - -#ifdef SERIAL_DEBUG_OPEN - printk(KERN_DEBUG"Shutting down serial ...."); -#endif - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - - cs->hw.elsa.IER = 0; - serial_outp(cs, UART_IER, 0x00); /* disable all intrs */ - cs->hw.elsa.MCR &= ~UART_MCR_OUT2; - - /* disable break condition */ - serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC); - - cs->hw.elsa.MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); - serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); - - /* disable FIFO's */ - serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); - serial_inp(cs, UART_RX); /* read data port to reset things */ - -#ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); -#endif -} - -static inline int -write_modem(struct BCState *bcs) { - int ret = 0; - struct IsdnCardState *cs = bcs->cs; - int count, len, fp; - - if (!bcs->tx_skb) - return 0; - if (bcs->tx_skb->len <= 0) - return 0; - len = bcs->tx_skb->len; - if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt) - len = MAX_MODEM_BUF - cs->hw.elsa.transcnt; - fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; - fp &= (MAX_MODEM_BUF - 1); - count = len; - if (count > MAX_MODEM_BUF - fp) { - count = MAX_MODEM_BUF - fp; - skb_copy_from_linear_data(bcs->tx_skb, - cs->hw.elsa.transbuf + fp, count); - skb_pull(bcs->tx_skb, count); - cs->hw.elsa.transcnt += count; - ret = count; - count = len - count; - fp = 0; - } - skb_copy_from_linear_data(bcs->tx_skb, - cs->hw.elsa.transbuf + fp, count); - skb_pull(bcs->tx_skb, count); - cs->hw.elsa.transcnt += count; - ret += count; - - if (cs->hw.elsa.transcnt && - !(cs->hw.elsa.IER & UART_IER_THRI)) { - cs->hw.elsa.IER |= UART_IER_THRI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - } - return (ret); -} - -static inline void -modem_fill(struct BCState *bcs) { - - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - write_modem(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - write_modem(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } -} - -static inline void receive_chars(struct IsdnCardState *cs, - int *status) -{ - unsigned char ch; - struct sk_buff *skb; - - do { - ch = serial_in(cs, UART_RX); - if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF) - break; - cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch; -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, *status); -#endif - if (*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE)) { - -#ifdef SERIAL_DEBUG_INTR - printk("handling exept...."); -#endif - } - *status = serial_inp(cs, UART_LSR); - } while (*status & UART_LSR_DR); - if (cs->hw.elsa.MFlag == 2) { - if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt))) - printk(KERN_WARNING "ElsaSER: receive out of memory\n"); - else { - skb_put_data(skb, cs->hw.elsa.rcvbuf, - cs->hw.elsa.rcvcnt); - skb_queue_tail(&cs->hw.elsa.bcs->rqueue, skb); - } - schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY); - } else { - char tmp[128]; - char *t = tmp; - - t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt); - QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt); - debugl1(cs, "%s", tmp); - } - cs->hw.elsa.rcvcnt = 0; -} - -static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done) -{ - int count; - - debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp, - cs->hw.elsa.transcnt); - - if (cs->hw.elsa.transcnt <= 0) { - cs->hw.elsa.IER &= ~UART_IER_THRI; - serial_out(cs, UART_IER, cs->hw.elsa.IER); - return; - } - count = 16; - do { - serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]); - if (cs->hw.elsa.transp >= MAX_MODEM_BUF) - cs->hw.elsa.transp = 0; - if (--cs->hw.elsa.transcnt <= 0) - break; - } while (--count > 0); - if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag == 2)) - modem_fill(cs->hw.elsa.bcs); - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif - if (intr_done) - *intr_done = 0; - if (cs->hw.elsa.transcnt <= 0) { - cs->hw.elsa.IER &= ~UART_IER_THRI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - } -} - - -static void rs_interrupt_elsa(struct IsdnCardState *cs) -{ - int status, iir, msr; - int pass_counter = 0; - -#ifdef SERIAL_DEBUG_INTR - printk(KERN_DEBUG "rs_interrupt_single(%d)...", cs->irq); -#endif - - do { - status = serial_inp(cs, UART_LSR); - debugl1(cs, "rs LSR %02x", status); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(cs, &status); - if (status & UART_LSR_THRE) - transmit_chars(cs, NULL); - if (pass_counter++ > RS_ISR_PASS_LIMIT) { - printk("rs_single loop break.\n"); - break; - } - iir = serial_inp(cs, UART_IIR); - debugl1(cs, "rs IIR %02x", iir); - if ((iir & 0xf) == 0) { - msr = serial_inp(cs, UART_MSR); - debugl1(cs, "rs MSR %02x", msr); - } - } while (!(iir & UART_IIR_NO_INT)); -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - -extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs); -extern void modehscx(struct BCState *bcs, int mode, int bc); -extern void hscx_l2l1(struct PStack *st, int pr, void *arg); - -static void -close_elsastate(struct BCState *bcs) -{ - modehscx(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.hscx.rcvbuf) { - if (bcs->mode != L1_MODE_MODEM) - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - } - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static void -modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { - int count, fp; - u_char *msg = buf; - - if (!len) - return; - if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) { - return; - } - fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; - fp &= (MAX_MODEM_BUF - 1); - count = len; - if (count > MAX_MODEM_BUF - fp) { - count = MAX_MODEM_BUF - fp; - memcpy(cs->hw.elsa.transbuf + fp, msg, count); - cs->hw.elsa.transcnt += count; - msg += count; - count = len - count; - fp = 0; - } - memcpy(cs->hw.elsa.transbuf + fp, msg, count); - cs->hw.elsa.transcnt += count; - if (cs->hw.elsa.transcnt && - !(cs->hw.elsa.IER & UART_IER_THRI)) { - cs->hw.elsa.IER |= UART_IER_THRI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - } -} - -static void -modem_set_init(struct IsdnCardState *cs) { - int timeout; - -#define RCV_DELAY 20 - modem_write_cmd(cs, MInit_1, strlen(MInit_1)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_2, strlen(MInit_2)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_3, strlen(MInit_3)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_4, strlen(MInit_4)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_5, strlen(MInit_5)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_6, strlen(MInit_6)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_7, strlen(MInit_7)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); -} - -static void -modem_set_dial(struct IsdnCardState *cs, int outgoing) { - int timeout; -#define RCV_DELAY 20 - - modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - if (outgoing) - modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout)); - else - modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); -} - -static void -modem_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - if (pr == (PH_DATA | REQUEST)) { - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - write_modem(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - } else if (pr == (PH_ACTIVATE | REQUEST)) { - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - set_arcofi(bcs->cs, st->l1.bc); - mstartup(bcs->cs); - modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag)); - bcs->cs->hw.elsa.MFlag = 2; - } else if (pr == (PH_DEACTIVATE | REQUEST)) { - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - bcs->cs->dc.isac.arcofi_bc = st->l1.bc; - arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); - wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait, - bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP); - bcs->cs->hw.elsa.MFlag = 1; - } else { - printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr); - } -} - -static int -setstack_elsa(struct PStack *st, struct BCState *bcs) -{ - - bcs->channel = st->l1.bc; - switch (st->l1.mode) { - case L1_MODE_HDLC: - case L1_MODE_TRANS: - if (open_hscxstate(st->l1.hardware, bcs)) - return (-1); - st->l2.l2l1 = hscx_l2l1; - break; - case L1_MODE_MODEM: - bcs->mode = L1_MODE_MODEM; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf; - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - bcs->cs->hw.elsa.bcs = bcs; - st->l2.l2l1 = modem_l2l1; - break; - } - st->l1.bcs = bcs; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void -init_modem(struct IsdnCardState *cs) { - - cs->bcs[0].BC_SetStack = setstack_elsa; - cs->bcs[1].BC_SetStack = setstack_elsa; - cs->bcs[0].BC_Close = close_elsastate; - cs->bcs[1].BC_Close = close_elsastate; - if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF, - GFP_ATOMIC))) { - printk(KERN_WARNING - "Elsa: No modem mem hw.elsa.rcvbuf\n"); - return; - } - if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF, - GFP_ATOMIC))) { - printk(KERN_WARNING - "Elsa: No modem mem hw.elsa.transbuf\n"); - kfree(cs->hw.elsa.rcvbuf); - cs->hw.elsa.rcvbuf = NULL; - return; - } - if (mstartup(cs)) { - printk(KERN_WARNING "Elsa: problem startup modem\n"); - } - modem_set_init(cs); -} - -static void -release_modem(struct IsdnCardState *cs) { - - cs->hw.elsa.MFlag = 0; - if (cs->hw.elsa.transbuf) { - if (cs->hw.elsa.rcvbuf) { - mshutdown(cs); - kfree(cs->hw.elsa.rcvbuf); - cs->hw.elsa.rcvbuf = NULL; - } - kfree(cs->hw.elsa.transbuf); - cs->hw.elsa.transbuf = NULL; - } -} diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c deleted file mode 100644 index e8d431a8302d..000000000000 --- a/drivers/isdn/hisax/enternow_pci.c +++ /dev/null @@ -1,420 +0,0 @@ -/* enternow_pci.c,v 0.99 2001/10/02 - * - * enternow_pci.c Card-specific routines for - * Formula-n enter:now ISDN PCI ab - * Gerdes AG Power ISDN PCI - * Woerltronic SA 16 PCI - * (based on HiSax driver by Karsten Keil) - * - * Author Christoph Ersfeld - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - * - * Notes: - * This driver interfaces to netjet.c which performs B-channel - * processing. - * - * Version 0.99 is the first release of this driver and there are - * certainly a few bugs. - * It isn't testet on linux 2.4 yet, so consider this code to be - * beta. - * - * Please don't report me any malfunction without sending - * (compressed) debug-logs. - * It would be nearly impossible to retrace it. - * - * Log D-channel-processing as follows: - * - * 1. Load hisax with card-specific parameters, this example ist for - * Formula-n enter:now ISDN PCI and compatible - * (f.e. Gerdes Power ISDN PCI) - * - * modprobe hisax type=41 protocol=2 id=gerdes - * - * if you chose an other value for id, you need to modify the - * code below, too. - * - * 2. set debug-level - * - * hisaxctrl gerdes 1 0x3ff - * hisaxctrl gerdes 11 0x4f - * cat /dev/isdnctrl >> ~/log & - * - * Please take also a look into /var/log/messages if there is - * anything importand concerning HISAX. - * - * - * Credits: - * Programming the driver for Formula-n enter:now ISDN PCI and - * necessary the driver for the used Amd 7930 D-channel-controller - * was spnsored by Formula-n Europe AG. - * Thanks to Karsten Keil and Petr Novak, who gave me support in - * Hisax-specific questions. - * I want so say special thanks to Carl-Friedrich Braun, who had to - * answer a lot of questions about generally ISDN and about handling - * of the Amd-Chip. - * - */ - - -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include "amd7930_fn.h" -#include -#include -#include -#include -#include "netjet.h" - - - -static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $"; - - -/* for PowerISDN PCI */ -#define TJ_AMD_IRQ 0x20 -#define TJ_LED1 0x40 -#define TJ_LED2 0x80 - - -/* The window to [the] AMD [chip]... - * From address hw.njet.base + TJ_AMD_PORT onwards, the AMD - * maps [consecutive/multiple] 8 bits into the TigerJet I/O space - * -> 0x01 of the AMD at hw.njet.base + 0C4 */ -#define TJ_AMD_PORT 0xC0 - - - -/* *************************** I/O-Interface functions ************************************* */ - - -/* cs->readisac, macro rByteAMD */ -static unsigned char -ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset) -{ - /* direct register */ - if (offset < 8) - return (inb(cs->hw.njet.isac + 4 * offset)); - - /* indirect register */ - else { - outb(offset, cs->hw.njet.isac + 4 * AMD_CR); - return (inb(cs->hw.njet.isac + 4 * AMD_DR)); - } -} - -/* cs->writeisac, macro wByteAMD */ -static void -WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value) -{ - /* direct register */ - if (offset < 8) - outb(value, cs->hw.njet.isac + 4 * offset); - - /* indirect register */ - else { - outb(offset, cs->hw.njet.isac + 4 * AMD_CR); - outb(value, cs->hw.njet.isac + 4 * AMD_DR); - } -} - - -static void -enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) { - if (!val) - outb(0x00, cs->hw.njet.base + NETJET_IRQMASK1); - else - outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); -} - - -static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off) -{ - return (5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value) -{ - -} - - -/* ******************************************************************************** */ - - -static void -reset_enpci(struct IsdnCardState *cs) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: reset"); - - /* Reset on, (also for AMD) */ - cs->hw.njet.ctrl_reg = 0x07; - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - mdelay(20); - /* Reset off */ - cs->hw.njet.ctrl_reg = 0x30; - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - /* 20ms delay */ - mdelay(20); - cs->hw.njet.auxd = 0; // LED-status - cs->hw.njet.dmactrl = 0; - outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL); - outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); - outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off -} - - -static int -enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - unsigned char *chan; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt); - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_enpci(cs); - Amd7930_init(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case CARD_RELEASE: - release_io_netjet(cs); - break; - case CARD_INIT: - reset_enpci(cs); - inittiger(cs); - /* irq must be on here */ - Amd7930_init(cs); - break; - case CARD_TEST: - break; - case MDL_ASSIGN: - /* TEI assigned, LED1 on */ - cs->hw.njet.auxd = TJ_AMD_IRQ << 1; - outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); - break; - case MDL_REMOVE: - /* TEI removed, LEDs off */ - cs->hw.njet.auxd = 0; - outb(0x00, cs->hw.njet.base + NETJET_AUXDATA); - break; - case MDL_BC_ASSIGN: - /* activate B-channel */ - chan = (unsigned char *)arg; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan); - - cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN"); - /* at least one b-channel in use, LED 2 on */ - cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; - outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); - break; - case MDL_BC_RELEASE: - /* deactivate B-channel */ - chan = (unsigned char *)arg; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan); - - cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE"); - /* no b-channel active -> LED2 off */ - if (!(cs->dc.amd7930.lmr1 & 3)) { - cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); - outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); - } - break; - default: - break; - - } - return (0); -} - -static irqreturn_t -enpci_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - unsigned char s0val, s1val, ir; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1); - - /* AMD threw an interrupt */ - if (!(s1val & TJ_AMD_IRQ)) { - /* read and clear interrupt-register */ - ir = ReadByteAmd7930(cs, 0x00); - Amd7930_interrupt(cs, ir); - s1val = 1; - } else - s1val = 0; - s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0); - if ((s0val | s1val) == 0) { // shared IRQ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (s0val) - outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0); - - /* DMA-Interrupt: B-channel-stuff */ - /* set bits in sval to indicate which page is free */ - if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) - /* the 2nd write page is free */ - s0val = 0x08; - else /* the 1st write page is free */ - s0val = 0x04; - if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) - /* the 2nd read page is free */ - s0val = s0val | 0x02; - else /* the 1st read page is free */ - s0val = s0val | 0x01; - if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ - { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - cs->hw.njet.irqstat0 = s0val; - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) - /* we have a read dma int */ - read_tiger(cs); - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) - /* we have a write dma int */ - write_tiger(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static int en_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) -{ - if (pci_enable_device(dev_netjet)) - return (0); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n"); - return (0); - } - /* checks Sub-Vendor ID because system crashes with Traverse-Card */ - if ((dev_netjet->subsystem_vendor != 0x55) || - (dev_netjet->subsystem_device != 0x02)) { - printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n"); - printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n"); - return (0); - } - - return (1); -} - -static void en_cs_init(struct IsdnCard *card, struct IsdnCardState *cs) -{ - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD - - /* Reset an */ - cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - /* 20 ms Pause */ - mdelay(20); - - cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */ - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - mdelay(10); - - cs->hw.njet.auxd = 0x00; // war 0xc0 - cs->hw.njet.dmactrl = 0; - - outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL); - outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); - outb(cs->hw.njet.auxd, cs->hw.njet.auxa); -} - -static int en_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs) -{ - const int bytecnt = 256; - - printk(KERN_INFO - "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) { - printk(KERN_WARNING - "HiSax: enter:now config port %lx-%lx already in use\n", - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } - - setup_Amd7930(cs); - cs->hw.njet.last_is0 = 0; - /* macro rByteAMD */ - cs->readisac = &ReadByteAmd7930; - /* macro wByteAMD */ - cs->writeisac = &WriteByteAmd7930; - cs->dc.amd7930.setIrqMask = &enpci_setIrqMask; - - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &netjet_fill_dma; - cs->cardmsg = &enpci_card_msg; - cs->irq_func = &enpci_interrupt; - cs->irq_flags |= IRQF_SHARED; - - return (1); -} - -static struct pci_dev *dev_netjet = NULL; - -/* called by config.c */ -int setup_enternow_pci(struct IsdnCard *card) -{ - int ret; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif - - strcpy(tmp, enternow_pci_rev); - printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_ENTERNOW) - return (0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - - for (;;) - { - if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { - ret = en_pci_probe(dev_netjet, cs); - if (!ret) - return (0); - } else { - printk(KERN_WARNING "enter:now PCI: No PCI card found\n"); - return (0); - } - - en_cs_init(card, cs); - break; - } - - return en_cs_init_rest(card, cs); -} diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c deleted file mode 100644 index 80ba82f77c63..000000000000 --- a/drivers/isdn/hisax/fsm.c +++ /dev/null @@ -1,161 +0,0 @@ -/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $ - * - * Finite state machine - * - * Author Karsten Keil - * Copyright by Karsten Keil - * by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include -#include -#include -#include "hisax.h" - -#define FSM_TIMER_DEBUG 0 - -int -FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount) -{ - int i; - - fsm->jumpmatrix = - kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count, - fsm->event_count), - GFP_KERNEL); - if (!fsm->jumpmatrix) - return -ENOMEM; - - for (i = 0; i < fncount; i++) - if ((fnlist[i].state >= fsm->state_count) || (fnlist[i].event >= fsm->event_count)) { - printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n", - i, (long)fnlist[i].state, (long)fsm->state_count, - (long)fnlist[i].event, (long)fsm->event_count); - } else - fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (FSMFNPTR)fnlist[i].routine; - return 0; -} - -void -FsmFree(struct Fsm *fsm) -{ - kfree((void *) fsm->jumpmatrix); -} - -int -FsmEvent(struct FsmInst *fi, int event, void *arg) -{ - FSMFNPTR r; - - if ((fi->state >= fi->fsm->state_count) || (event >= fi->fsm->event_count)) { - printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", - (long)fi->state, (long)fi->fsm->state_count, event, (long)fi->fsm->event_count); - return (1); - } - r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; - if (r) { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - r(fi, event, arg); - return (0); - } else { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s no routine", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - return (!0); - } -} - -void -FsmChangeState(struct FsmInst *fi, int newstate) -{ - fi->state = newstate; - if (fi->debug) - fi->printdebug(fi, "ChangeState %s", - fi->fsm->strState[newstate]); -} - -static void -FsmExpireTimer(struct timer_list *t) -{ - struct FsmTimer *ft = from_timer(ft, t, tl); -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); -#endif - FsmEvent(ft->fi, ft->event, ft->arg); -} - -void -FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) -{ - ft->fi = fi; -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft); -#endif - timer_setup(&ft->tl, FsmExpireTimer, 0); -} - -void -FsmDelTimer(struct FsmTimer *ft, int where) -{ -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where); -#endif - del_timer(&ft->tl); -} - -int -FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) { - printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); - ft->fi->printdebug(ft->fi, "FsmAddTimer already active!"); - return -1; - } - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); - return 0; -} - -void -FsmRestartTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) - del_timer(&ft->tl); - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); -} diff --git a/drivers/isdn/hisax/fsm.h b/drivers/isdn/hisax/fsm.h deleted file mode 100644 index 8c7385619a46..000000000000 --- a/drivers/isdn/hisax/fsm.h +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $ - * - * Finite state machine - * - * Author Karsten Keil - * Copyright by Karsten Keil - * by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __FSM_H__ -#define __FSM_H__ - -#include - -struct FsmInst; - -typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); - -struct Fsm { - FSMFNPTR *jumpmatrix; - int state_count, event_count; - char **strEvent, **strState; -}; - -struct FsmInst { - struct Fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct FsmInst *, char *, ...); -}; - -struct FsmNode { - int state, event; - void (*routine) (struct FsmInst *, int, void *); -}; - -struct FsmTimer { - struct FsmInst *fi; - struct timer_list tl; - int event; - void *arg; -}; - -int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); -void FsmFree(struct Fsm *fsm); -int FsmEvent(struct FsmInst *fi, int event, void *arg); -void FsmChangeState(struct FsmInst *fi, int newstate); -void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft); -int FsmAddTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmDelTimer(struct FsmTimer *ft, int where); - -#endif diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c deleted file mode 100644 index a6d8af02354a..000000000000 --- a/drivers/isdn/hisax/gazel.c +++ /dev/null @@ -1,691 +0,0 @@ -/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $ - * - * low level stuff for Gazel isdn cards - * - * Author BeWan Systems - * based on source code from Karsten Keil - * Copyright by BeWan Systems - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include "ipac.h" -#include - -static const char *gazel_revision = "$Revision: 2.19.2.4 $"; - -#define R647 1 -#define R685 2 -#define R753 3 -#define R742 4 - -#define PLX_CNTRL 0x50 /* registre de controle PLX */ -#define RESET_GAZEL 0x4 -#define RESET_9050 0x40000000 -#define PLX_INCSR 0x4C /* registre d'IT du 9050 */ -#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */ -#define INT_ISAC 0x20 /* 1 = IT isac en cours */ -#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */ -#define INT_HSCX 0x4 /* 1 = IT hscx en cours */ -#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */ -#define INT_IPAC_EN 0x3 /* enable IT ipac */ - - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int adr, u_short off) -{ - return bytein(adr + off); -} - -static inline void -writereg(unsigned int adr, u_short off, u_char data) -{ - byteout(adr + off, data); -} - - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -static inline u_char -readreg_ipac(unsigned int adr, u_short off) -{ - register u_char ret; - - byteout(adr, off); - ret = bytein(adr + 4); - return ret; -} - -static inline void -writereg_ipac(unsigned int adr, u_short off, u_char data) -{ - byteout(adr, off); - byteout(adr + 4, data); -} - - -static inline void -read_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size) -{ - byteout(adr, off); - insb(adr + 4, data, size); -} - -static void -write_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size) -{ - byteout(adr, off); - outsb(adr + 4, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - return (readreg(cs->hw.gazel.isac, off2)); - case R753: - case R742: - return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2)); - } - return 0; -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - writereg(cs->hw.gazel.isac, off2, value); - break; - case R753: - case R742: - writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value); - break; - } -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - read_fifo(cs->hw.gazel.isacfifo, data, size); - break; - case R753: - case R742: - read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); - break; - } -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - write_fifo(cs->hw.gazel.isacfifo, data, size); - break; - case R753: - case R742: - write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); - break; - } -} - -static void -ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); - break; - case R753: - case R742: - read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); - break; - } -} - -static void -WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); - break; - case R753: - case R742: - write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); - break; - } -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - return (readreg(cs->hw.gazel.hscx[hscx], off2)); - case R753: - case R742: - return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2)); - } - return 0; -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - writereg(cs->hw.gazel.hscx[hscx], off2, value); - break; - case R753: - case R742: - writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value); - break; - } -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -gazel_interrupt(int intno, void *dev_id) -{ -#define MAXCOUNT 5 - struct IsdnCardState *cs = dev_id; - u_char valisac, valhscx; - int count = 0; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - do { - valhscx = ReadHSCX(cs, 1, HSCX_ISTA); - if (valhscx) - hscx_int_main(cs, valhscx); - valisac = ReadISAC(cs, ISAC_ISTA); - if (valisac) - isac_interrupt(cs, valisac); - count++; - } while ((valhscx || valisac) && (count < MAXCOUNT)); - - WriteHSCX(cs, 0, HSCX_MASK, 0xFF); - WriteHSCX(cs, 1, HSCX_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - WriteHSCX(cs, 0, HSCX_MASK, 0x0); - WriteHSCX(cs, 1, HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - - -static irqreturn_t -gazel_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val; - int count = 0; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = ReadISAC(cs, IPAC_ISTA - 0x80); - do { - if (ista & 0x0f) { - val = ReadHSCX(cs, 1, HSCX_ISTA); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) { - hscx_int_main(cs, val); - } - } - if (ista & 0x20) { - val = 0xfe & ReadISAC(cs, ISAC_ISTA); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = ReadISAC(cs, IPAC_ISTA - 0x80); - count++; - } - while ((ista & 0x3f) && (count < MAXCOUNT)); - - WriteISAC(cs, IPAC_MASK - 0x80, 0xFF); - WriteISAC(cs, IPAC_MASK - 0x80, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_gazel(struct IsdnCardState *cs) -{ - unsigned int i; - - switch (cs->subtyp) { - case R647: - for (i = 0x0000; i < 0xC000; i += 0x1000) - release_region(i + cs->hw.gazel.hscx[0], 16); - release_region(0xC000 + cs->hw.gazel.hscx[0], 1); - break; - - case R685: - release_region(cs->hw.gazel.hscx[0], 0x100); - release_region(cs->hw.gazel.cfg_reg, 0x80); - break; - - case R753: - release_region(cs->hw.gazel.ipac, 0x8); - release_region(cs->hw.gazel.cfg_reg, 0x80); - break; - - case R742: - release_region(cs->hw.gazel.ipac, 8); - break; - } -} - -static int -reset_gazel(struct IsdnCardState *cs) -{ - unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; - - switch (cs->subtyp) { - case R647: - writereg(addr, 0, 0); - HZDELAY(10); - writereg(addr, 0, 1); - HZDELAY(2); - break; - case R685: - plxcntrl = inl(addr + PLX_CNTRL); - plxcntrl |= (RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - plxcntrl &= ~(RESET_9050 + RESET_GAZEL); - HZDELAY(4); - outl(plxcntrl, addr + PLX_CNTRL); - HZDELAY(10); - outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR); - break; - case R753: - plxcntrl = inl(addr + PLX_CNTRL); - plxcntrl |= (RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - plxcntrl &= ~(RESET_9050 + RESET_GAZEL); - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); - HZDELAY(4); - outl(plxcntrl, addr + PLX_CNTRL); - HZDELAY(10); - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); - WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); - WriteISAC(cs, IPAC_AOE - 0x80, 0x0); - WriteISAC(cs, IPAC_MASK - 0x80, 0xff); - WriteISAC(cs, IPAC_CONF - 0x80, 0x1); - outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR); - WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); - break; - case R742: - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); - HZDELAY(4); - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); - WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); - WriteISAC(cs, IPAC_AOE - 0x80, 0x0); - WriteISAC(cs, IPAC_MASK - 0x80, 0xff); - WriteISAC(cs, IPAC_CONF - 0x80, 0x1); - WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); - break; - } - return (0); -} - -static int -Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_gazel(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_gazel(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 1); - if ((cs->subtyp == R647) || (cs->subtyp == R685)) { - int i; - for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) { - cs->bcs[i].hw.hscx.tsaxr0 = 0x1f; - cs->bcs[i].hw.hscx.tsaxr1 = 0x23; - } - } - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int -reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs) -{ - unsigned int i, j, base = 0, adr = 0, len = 0; - - switch (cs->subtyp) { - case R647: - base = cs->hw.gazel.hscx[0]; - if (!request_region(adr = (0xC000 + base), len = 1, "gazel")) - goto error; - for (i = 0x0000; i < 0xC000; i += 0x1000) { - if (!request_region(adr = (i + base), len = 16, "gazel")) - goto error; - } - if (i != 0xC000) { - for (j = 0; j < i; j += 0x1000) - release_region(j + base, 16); - release_region(0xC000 + base, 1); - goto error; - } - break; - - case R685: - if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel")) - goto error; - if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { - release_region(cs->hw.gazel.hscx[0], 0x100); - goto error; - } - break; - - case R753: - if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) - goto error; - if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { - release_region(cs->hw.gazel.ipac, 8); - goto error; - } - break; - - case R742: - if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) - goto error; - break; - } - - return 0; - -error: - printk(KERN_WARNING "Gazel: io ports 0x%x-0x%x already in use\n", - adr, adr + len); - return 1; -} - -static int setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) -{ - printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n"); - // we got an irq parameter, assume it is an ISA card - // R742 decodes address even in not started... - // R647 returns FF if not present or not started - // eventually needs improvment - if (readreg_ipac(card->para[1], IPAC_ID) == 1) - cs->subtyp = R742; - else - cs->subtyp = R647; - - setup_isac(cs); - cs->hw.gazel.cfg_reg = card->para[1] + 0xC000; - cs->hw.gazel.ipac = card->para[1]; - cs->hw.gazel.isac = card->para[1] + 0x8000; - cs->hw.gazel.hscx[0] = card->para[1]; - cs->hw.gazel.hscx[1] = card->para[1] + 0x4000; - cs->irq = card->para[0]; - cs->hw.gazel.isacfifo = cs->hw.gazel.isac; - cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; - cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; - - switch (cs->subtyp) { - case R647: - printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n"); - cs->dc.isac.adf2 = 0x87; - printk(KERN_INFO - "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); - printk(KERN_INFO - "Gazel: hscx A:0x%X hscx B:0x%X\n", - cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - - break; - case R742: - printk(KERN_INFO "Gazel: Card ISA R742 found\n"); - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - printk(KERN_INFO - "Gazel: config irq:%d ipac:0x%X\n", - cs->irq, cs->hw.gazel.ipac); - break; - } - - return (0); -} - -#ifdef CONFIG_PCI -static struct pci_dev *dev_tel = NULL; - -static int setup_gazelpci(struct IsdnCardState *cs) -{ - u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0; - u_char pci_irq = 0, found; - u_int nbseek, seekcard; - - printk(KERN_WARNING "Gazel: PCI card automatic recognition\n"); - - found = 0; - seekcard = PCI_DEVICE_ID_PLX_R685; - for (nbseek = 0; nbseek < 4; nbseek++) { - if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_PLX, - seekcard, dev_tel))) { - if (pci_enable_device(dev_tel)) - return 1; - pci_irq = dev_tel->irq; - pci_ioaddr0 = pci_resource_start(dev_tel, 1); - pci_ioaddr1 = pci_resource_start(dev_tel, 2); - found = 1; - } - if (found) - break; - else { - switch (seekcard) { - case PCI_DEVICE_ID_PLX_R685: - seekcard = PCI_DEVICE_ID_PLX_R753; - break; - case PCI_DEVICE_ID_PLX_R753: - seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; - break; - case PCI_DEVICE_ID_PLX_DJINN_ITOO: - seekcard = PCI_DEVICE_ID_PLX_OLITEC; - break; - } - } - } - if (!found) { - printk(KERN_WARNING "Gazel: No PCI card found\n"); - return (1); - } - if (!pci_irq) { - printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n"); - return 1; - } - cs->hw.gazel.pciaddr[0] = pci_ioaddr0; - cs->hw.gazel.pciaddr[1] = pci_ioaddr1; - setup_isac(cs); - pci_ioaddr1 &= 0xfffe; - cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe; - cs->hw.gazel.ipac = pci_ioaddr1; - cs->hw.gazel.isac = pci_ioaddr1 + 0x80; - cs->hw.gazel.hscx[0] = pci_ioaddr1; - cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40; - cs->hw.gazel.isacfifo = cs->hw.gazel.isac; - cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; - cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; - cs->irq = pci_irq; - cs->irq_flags |= IRQF_SHARED; - - switch (seekcard) { - case PCI_DEVICE_ID_PLX_R685: - printk(KERN_INFO "Gazel: Card PCI R685 found\n"); - cs->subtyp = R685; - cs->dc.isac.adf2 = 0x87; - printk(KERN_INFO - "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); - printk(KERN_INFO - "Gazel: hscx A:0x%X hscx B:0x%X\n", - cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - break; - case PCI_DEVICE_ID_PLX_R753: - case PCI_DEVICE_ID_PLX_DJINN_ITOO: - case PCI_DEVICE_ID_PLX_OLITEC: - printk(KERN_INFO "Gazel: Card PCI R753 found\n"); - cs->subtyp = R753; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - printk(KERN_INFO - "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg); - break; - } - - return (0); -} -#endif /* CONFIG_PCI */ - -int setup_gazel(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_char val; - - strcpy(tmp, gazel_revision); - printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp)); - - if (cs->typ != ISDN_CTYPE_GAZEL) - return (0); - - if (card->para[0]) { - if (setup_gazelisa(card, cs)) - return (0); - } else { - -#ifdef CONFIG_PCI - if (setup_gazelpci(cs)) - return (0); -#else - printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ - } - - if (reserve_regions(card, cs)) { - return (0); - } - if (reset_gazel(cs)) { - printk(KERN_WARNING "Gazel: wrong IRQ\n"); - release_io_gazel(cs); - return (0); - } - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Gazel_card_msg; - - switch (cs->subtyp) { - case R647: - case R685: - cs->irq_func = &gazel_interrupt; - ISACVersion(cs, "Gazel:"); - if (HscxVersion(cs, "Gazel:")) { - printk(KERN_WARNING - "Gazel: wrong HSCX versions check IO address\n"); - release_io_gazel(cs); - return (0); - } - break; - case R742: - case R753: - cs->irq_func = &gazel_interrupt_ipac; - val = ReadISAC(cs, IPAC_ID - 0x80); - printk(KERN_INFO "Gazel: IPAC version %x\n", val); - break; - } - - return (1); -} diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c deleted file mode 100644 index e9bb8fb67ad0..000000000000 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ /dev/null @@ -1,1584 +0,0 @@ -/*************************************************************************/ -/* $Id: hfc4s8s_l1.c,v 1.10 2005/02/09 16:31:09 martinb1 Exp $ */ -/* HFC-4S/8S low layer interface for Cologne Chip HFC-4S/8S isdn chips */ -/* The low layer (L1) is implemented as a loadable module for usage with */ -/* the HiSax isdn driver for passive cards. */ -/* */ -/* Author: Werner Cornelius */ -/* (C) 2003 Cornelius Consult (werner@cornelius-consult.de) */ -/* */ -/* Driver maintained by Cologne Chip */ -/* - Martin Bachem, support@colognechip.com */ -/* */ -/* This driver only works with chip revisions >= 1, older revision 0 */ -/* engineering samples (only first manufacturer sample cards) will not */ -/* work and are rejected by the driver. */ -/* */ -/* This file distributed under the GNU GPL. */ -/* */ -/* See Version History at the end of this file */ -/* */ -/*************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hisax_if.h" -#include "hfc4s8s_l1.h" - -static const char hfc4s8s_rev[] = "Revision: 1.10"; - -/***************************************************************/ -/* adjustable transparent mode fifo threshold */ -/* The value defines the used fifo threshold with the equation */ -/* */ -/* notify number of bytes = 2 * 2 ^ TRANS_FIFO_THRES */ -/* */ -/* The default value is 5 which results in a buffer size of 64 */ -/* and an interrupt rate of 8ms. */ -/* The maximum value is 7 due to fifo size restrictions. */ -/* Values below 3-4 are not recommended due to high interrupt */ -/* load of the processor. For non critical applications the */ -/* value should be raised to 7 to reduce any interrupt overhead*/ -/***************************************************************/ -#define TRANS_FIFO_THRES 5 - -/*************/ -/* constants */ -/*************/ -#define CLOCKMODE_0 0 /* ext. 24.576 MhZ clk freq, int. single clock mode */ -#define CLOCKMODE_1 1 /* ext. 49.576 MhZ clk freq, int. single clock mode */ -#define CHIP_ID_SHIFT 4 -#define HFC_MAX_ST 8 -#define MAX_D_FRAME_SIZE 270 -#define MAX_B_FRAME_SIZE 1536 -#define TRANS_TIMER_MODE (TRANS_FIFO_THRES & 0xf) -#define TRANS_FIFO_BYTES (2 << TRANS_FIFO_THRES) -#define MAX_F_CNT 0x0f - -#define CLKDEL_NT 0x6c -#define CLKDEL_TE 0xf -#define CTRL0_NT 4 -#define CTRL0_TE 0 - -#define L1_TIMER_T4 2 /* minimum in jiffies */ -#define L1_TIMER_T3 (7 * HZ) /* activation timeout */ -#define L1_TIMER_T1 ((120 * HZ) / 1000) /* NT mode deactivation timeout */ - - -/******************/ -/* types and vars */ -/******************/ -static int card_cnt; - -/* private driver_data */ -typedef struct { - int chip_id; - int clock_mode; - int max_st_ports; - char *device_name; -} hfc4s8s_param; - -static const struct pci_device_id hfc4s8s_ids[] = { - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_4S, - .subvendor = 0x1397, - .subdevice = 0x08b4, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_0, 4, - "HFC-4S Evaluation Board"}), - }, - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_8S, - .subvendor = 0x1397, - .subdevice = 0x16b8, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_0, 8, - "HFC-8S Evaluation Board"}), - }, - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_4S, - .subvendor = 0x1397, - .subdevice = 0xb520, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_1, 4, - "IOB4ST"}), - }, - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_8S, - .subvendor = 0x1397, - .subdevice = 0xb522, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_1, 8, - "IOB8ST"}), - }, - {} -}; - -MODULE_DEVICE_TABLE(pci, hfc4s8s_ids); - -MODULE_AUTHOR("Werner Cornelius, werner@cornelius-consult.de"); -MODULE_DESCRIPTION("ISDN layer 1 for Cologne Chip HFC-4S/8S chips"); -MODULE_LICENSE("GPL"); - -/***********/ -/* layer 1 */ -/***********/ -struct hfc4s8s_btype { - spinlock_t lock; - struct hisax_b_if b_if; - struct hfc4s8s_l1 *l1p; - struct sk_buff_head tx_queue; - struct sk_buff *tx_skb; - struct sk_buff *rx_skb; - __u8 *rx_ptr; - int tx_cnt; - int bchan; - int mode; -}; - -struct _hfc4s8s_hw; - -struct hfc4s8s_l1 { - spinlock_t lock; - struct _hfc4s8s_hw *hw; /* pointer to hardware area */ - int l1_state; /* actual l1 state */ - struct timer_list l1_timer; /* layer 1 timer structure */ - int nt_mode; /* set to nt mode */ - int st_num; /* own index */ - int enabled; /* interface is enabled */ - struct sk_buff_head d_tx_queue; /* send queue */ - int tx_cnt; /* bytes to send */ - struct hisax_d_if d_if; /* D-channel interface */ - struct hfc4s8s_btype b_ch[2]; /* B-channel data */ - struct hisax_b_if *b_table[2]; -}; - -/**********************/ -/* hardware structure */ -/**********************/ -typedef struct _hfc4s8s_hw { - spinlock_t lock; - - int cardnum; - int ifnum; - int iobase; - int nt_mode; - u_char *membase; - u_char *hw_membase; - void *pdev; - int max_fifo; - hfc4s8s_param driver_data; - int irq; - int fifo_sched_cnt; - struct work_struct tqueue; - struct hfc4s8s_l1 l1[HFC_MAX_ST]; - char card_name[60]; - struct { - u_char r_irq_ctrl; - u_char r_ctrl0; - volatile u_char r_irq_statech; /* active isdn l1 status */ - u_char r_irqmsk_statchg; /* enabled isdn status ints */ - u_char r_irq_fifo_blx[8]; /* fifo status registers */ - u_char fifo_rx_trans_enables[8]; /* mask for enabled transparent rx fifos */ - u_char fifo_slow_timer_service[8]; /* mask for fifos needing slower timer service */ - volatile u_char r_irq_oview; /* contents of overview register */ - volatile u_char timer_irq; - int timer_usg_cnt; /* number of channels using timer */ - } mr; -} hfc4s8s_hw; - - - -/* inline functions io mapped */ -static inline void -SetRegAddr(hfc4s8s_hw *a, u_char b) -{ - outb(b, (a->iobase) + 4); -} - -static inline u_char -GetRegAddr(hfc4s8s_hw *a) -{ - return (inb((volatile u_int) (a->iobase + 4))); -} - - -static inline void -Write_hfc8(hfc4s8s_hw *a, u_char b, u_char c) -{ - SetRegAddr(a, b); - outb(c, a->iobase); -} - -static inline void -fWrite_hfc8(hfc4s8s_hw *a, u_char c) -{ - outb(c, a->iobase); -} - -static inline void -fWrite_hfc32(hfc4s8s_hw *a, u_long c) -{ - outl(c, a->iobase); -} - -static inline u_char -Read_hfc8(hfc4s8s_hw *a, u_char b) -{ - SetRegAddr(a, b); - return (inb((volatile u_int) a->iobase)); -} - -static inline u_char -fRead_hfc8(hfc4s8s_hw *a) -{ - return (inb((volatile u_int) a->iobase)); -} - - -static inline u_short -Read_hfc16(hfc4s8s_hw *a, u_char b) -{ - SetRegAddr(a, b); - return (inw((volatile u_int) a->iobase)); -} - -static inline u_long -fRead_hfc32(hfc4s8s_hw *a) -{ - return (inl((volatile u_int) a->iobase)); -} - -static inline void -wait_busy(hfc4s8s_hw *a) -{ - SetRegAddr(a, R_STATUS); - while (inb((volatile u_int) a->iobase) & M_BUSY); -} - -#define PCI_ENA_REGIO 0x01 - -/******************************************************/ -/* function to read critical counter registers that */ -/* may be updated by the chip during read */ -/******************************************************/ -static u_char -Read_hfc8_stable(hfc4s8s_hw *hw, int reg) -{ - u_char ref8; - u_char in8; - ref8 = Read_hfc8(hw, reg); - while (((in8 = Read_hfc8(hw, reg)) != ref8)) { - ref8 = in8; - } - return in8; -} - -static int -Read_hfc16_stable(hfc4s8s_hw *hw, int reg) -{ - int ref16; - int in16; - - ref16 = Read_hfc16(hw, reg); - while (((in16 = Read_hfc16(hw, reg)) != ref16)) { - ref16 = in16; - } - return in16; -} - -/*****************************/ -/* D-channel call from HiSax */ -/*****************************/ -static void -dch_l2l1(struct hisax_d_if *iface, int pr, void *arg) -{ - struct hfc4s8s_l1 *l1 = iface->ifc.priv; - struct sk_buff *skb = (struct sk_buff *) arg; - u_long flags; - - switch (pr) { - - case (PH_DATA | REQUEST): - if (!l1->enabled) { - dev_kfree_skb(skb); - break; - } - spin_lock_irqsave(&l1->lock, flags); - skb_queue_tail(&l1->d_tx_queue, skb); - if ((skb_queue_len(&l1->d_tx_queue) == 1) && - (l1->tx_cnt <= 0)) { - l1->hw->mr.r_irq_fifo_blx[l1->st_num] |= - 0x10; - spin_unlock_irqrestore(&l1->lock, flags); - schedule_work(&l1->hw->tqueue); - } else - spin_unlock_irqrestore(&l1->lock, flags); - break; - - case (PH_ACTIVATE | REQUEST): - if (!l1->enabled) - break; - if (!l1->nt_mode) { - if (l1->l1_state < 6) { - spin_lock_irqsave(&l1->lock, - flags); - - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, - 0x60); - mod_timer(&l1->l1_timer, - jiffies + L1_TIMER_T3); - spin_unlock_irqrestore(&l1->lock, - flags); - } else if (l1->l1_state == 7) - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - } else { - if (l1->l1_state != 3) { - spin_lock_irqsave(&l1->lock, - flags); - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, - 0x60); - spin_unlock_irqrestore(&l1->lock, - flags); - } else if (l1->l1_state == 3) - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - } - break; - - default: - printk(KERN_INFO - "HFC-4S/8S: Unknown D-chan cmd 0x%x received, ignored\n", - pr); - break; - } - if (!l1->enabled) - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); -} /* dch_l2l1 */ - -/*****************************/ -/* B-channel call from HiSax */ -/*****************************/ -static void -bch_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct hfc4s8s_btype *bch = ifc->priv; - struct hfc4s8s_l1 *l1 = bch->l1p; - struct sk_buff *skb = (struct sk_buff *) arg; - long mode = (long) arg; - u_long flags; - - switch (pr) { - - case (PH_DATA | REQUEST): - if (!l1->enabled || (bch->mode == L1_MODE_NULL)) { - dev_kfree_skb(skb); - break; - } - spin_lock_irqsave(&l1->lock, flags); - skb_queue_tail(&bch->tx_queue, skb); - if (!bch->tx_skb && (bch->tx_cnt <= 0)) { - l1->hw->mr.r_irq_fifo_blx[l1->st_num] |= - ((bch->bchan == 1) ? 1 : 4); - spin_unlock_irqrestore(&l1->lock, flags); - schedule_work(&l1->hw->tqueue); - } else - spin_unlock_irqrestore(&l1->lock, flags); - break; - - case (PH_ACTIVATE | REQUEST): - case (PH_DEACTIVATE | REQUEST): - if (!l1->enabled) - break; - if (pr == (PH_DEACTIVATE | REQUEST)) - mode = L1_MODE_NULL; - - switch (mode) { - case L1_MODE_HDLC: - spin_lock_irqsave(&l1->lock, - flags); - l1->hw->mr.timer_usg_cnt++; - l1->hw->mr. - fifo_slow_timer_service[l1-> - st_num] - |= - ((bch->bchan == - 1) ? 0x2 : 0x8); - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 0 : 2))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable TX interrupts for hdlc */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(l1->hw); - - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 1 : 3))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable RX interrupts for hdlc */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - l1->hw->mr.r_ctrl0 |= - (bch->bchan & 3); - Write_hfc8(l1->hw, A_ST_CTRL0, - l1->hw->mr.r_ctrl0); - bch->mode = L1_MODE_HDLC; - spin_unlock_irqrestore(&l1->lock, - flags); - - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - break; - - case L1_MODE_TRANS: - spin_lock_irqsave(&l1->lock, - flags); - l1->hw->mr. - fifo_rx_trans_enables[l1-> - st_num] - |= - ((bch->bchan == - 1) ? 0x2 : 0x8); - l1->hw->mr.timer_usg_cnt++; - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 0 : 2))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(l1->hw); - - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 1 : 3))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - l1->hw->mr.r_ctrl0 |= - (bch->bchan & 3); - Write_hfc8(l1->hw, A_ST_CTRL0, - l1->hw->mr.r_ctrl0); - bch->mode = L1_MODE_TRANS; - spin_unlock_irqrestore(&l1->lock, - flags); - - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - break; - - default: - if (bch->mode == L1_MODE_NULL) - break; - spin_lock_irqsave(&l1->lock, - flags); - l1->hw->mr. - fifo_slow_timer_service[l1-> - st_num] - &= - ~((bch->bchan == - 1) ? 0x3 : 0xc); - l1->hw->mr. - fifo_rx_trans_enables[l1-> - st_num] - &= - ~((bch->bchan == - 1) ? 0x3 : 0xc); - l1->hw->mr.timer_usg_cnt--; - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 0 : 2))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */ - wait_busy(l1->hw); - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 1 : 3))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */ - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - l1->hw->mr.r_ctrl0 &= - ~(bch->bchan & 3); - Write_hfc8(l1->hw, A_ST_CTRL0, - l1->hw->mr.r_ctrl0); - spin_unlock_irqrestore(&l1->lock, - flags); - - bch->mode = L1_MODE_NULL; - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_DEACTIVATE | - INDICATION, - NULL); - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } - skb_queue_purge(&bch->tx_queue); - bch->tx_cnt = 0; - bch->rx_ptr = NULL; - break; - } - - /* timer is only used when at least one b channel */ - /* is set up to transparent mode */ - if (l1->hw->mr.timer_usg_cnt) { - Write_hfc8(l1->hw, R_IRQMSK_MISC, - M_TI_IRQMSK); - } else { - Write_hfc8(l1->hw, R_IRQMSK_MISC, 0); - } - - break; - - default: - printk(KERN_INFO - "HFC-4S/8S: Unknown B-chan cmd 0x%x received, ignored\n", - pr); - break; - } - if (!l1->enabled) - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); -} /* bch_l2l1 */ - -/**************************/ -/* layer 1 timer function */ -/**************************/ -static void -hfc_l1_timer(struct timer_list *t) -{ - struct hfc4s8s_l1 *l1 = from_timer(l1, t, l1_timer); - u_long flags; - - if (!l1->enabled) - return; - - spin_lock_irqsave(&l1->lock, flags); - if (l1->nt_mode) { - l1->l1_state = 1; - Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, 0x11); - spin_unlock_irqrestore(&l1->lock, flags); - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); - spin_lock_irqsave(&l1->lock, flags); - l1->l1_state = 1; - Write_hfc8(l1->hw, A_ST_WR_STA, 0x1); - spin_unlock_irqrestore(&l1->lock, flags); - } else { - /* activation timed out */ - Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, 0x13); - spin_unlock_irqrestore(&l1->lock, flags); - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); - spin_lock_irqsave(&l1->lock, flags); - Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, 0x3); - spin_unlock_irqrestore(&l1->lock, flags); - } -} /* hfc_l1_timer */ - -/****************************************/ -/* a complete D-frame has been received */ -/****************************************/ -static void -rx_d_frame(struct hfc4s8s_l1 *l1p, int ech) -{ - int z1, z2; - u_char f1, f2, df; - struct sk_buff *skb; - u_char *cp; - - - if (!l1p->enabled) - return; - do { - /* E/D RX fifo */ - Write_hfc8(l1p->hw, R_FIFO, - (l1p->st_num * 8 + ((ech) ? 7 : 5))); - wait_busy(l1p->hw); - - f1 = Read_hfc8_stable(l1p->hw, A_F1); - f2 = Read_hfc8(l1p->hw, A_F2); - - if (f1 < f2) - df = MAX_F_CNT + 1 + f1 - f2; - else - df = f1 - f2; - - if (!df) - return; /* no complete frame in fifo */ - - z1 = Read_hfc16_stable(l1p->hw, A_Z1); - z2 = Read_hfc16(l1p->hw, A_Z2); - - z1 = z1 - z2 + 1; - if (z1 < 0) - z1 += 384; - - if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) { - printk(KERN_INFO - "HFC-4S/8S: Could not allocate D/E " - "channel receive buffer"); - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); - wait_busy(l1p->hw); - return; - } - - if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) { - if (skb) - dev_kfree_skb(skb); - /* remove errornous D frame */ - if (df == 1) { - /* reset fifo */ - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); - wait_busy(l1p->hw); - return; - } else { - /* read errornous D frame */ - SetRegAddr(l1p->hw, A_FIFO_DATA0); - - while (z1 >= 4) { - fRead_hfc32(l1p->hw); - z1 -= 4; - } - - while (z1--) - fRead_hfc8(l1p->hw); - - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); - wait_busy(l1p->hw); - return; - } - } - - cp = skb->data; - - SetRegAddr(l1p->hw, A_FIFO_DATA0); - - while (z1 >= 4) { - *((unsigned long *) cp) = fRead_hfc32(l1p->hw); - cp += 4; - z1 -= 4; - } - - while (z1--) - *cp++ = fRead_hfc8(l1p->hw); - - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ - wait_busy(l1p->hw); - - if (*(--cp)) { - dev_kfree_skb(skb); - } else { - skb->len = (cp - skb->data) - 2; - if (ech) - l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, - PH_DATA_E | INDICATION, - skb); - else - l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, - PH_DATA | INDICATION, - skb); - } - } while (1); -} /* rx_d_frame */ - -/*************************************************************/ -/* a B-frame has been received (perhaps not fully completed) */ -/*************************************************************/ -static void -rx_b_frame(struct hfc4s8s_btype *bch) -{ - int z1, z2, hdlc_complete; - u_char f1, f2; - struct hfc4s8s_l1 *l1 = bch->l1p; - struct sk_buff *skb; - - if (!l1->enabled || (bch->mode == L1_MODE_NULL)) - return; - - do { - /* RX Fifo */ - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3))); - wait_busy(l1->hw); - - if (bch->mode == L1_MODE_HDLC) { - f1 = Read_hfc8_stable(l1->hw, A_F1); - f2 = Read_hfc8(l1->hw, A_F2); - hdlc_complete = ((f1 ^ f2) & MAX_F_CNT); - } else - hdlc_complete = 0; - z1 = Read_hfc16_stable(l1->hw, A_Z1); - z2 = Read_hfc16(l1->hw, A_Z2); - z1 = (z1 - z2); - if (hdlc_complete) - z1++; - if (z1 < 0) - z1 += 384; - - if (!z1) - break; - - if (!(skb = bch->rx_skb)) { - if (! - (skb = - dev_alloc_skb((bch->mode == - L1_MODE_TRANS) ? z1 - : (MAX_B_FRAME_SIZE + 3)))) { - printk(KERN_ERR - "HFC-4S/8S: Could not allocate B " - "channel receive buffer"); - return; - } - bch->rx_ptr = skb->data; - bch->rx_skb = skb; - } - - skb->len = (bch->rx_ptr - skb->data) + z1; - - /* HDLC length check */ - if ((bch->mode == L1_MODE_HDLC) && - ((hdlc_complete && (skb->len < 4)) || - (skb->len > (MAX_B_FRAME_SIZE + 3)))) { - - skb->len = 0; - bch->rx_ptr = skb->data; - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(l1->hw); - return; - } - SetRegAddr(l1->hw, A_FIFO_DATA0); - - while (z1 >= 4) { - *((unsigned long *) bch->rx_ptr) = - fRead_hfc32(l1->hw); - bch->rx_ptr += 4; - z1 -= 4; - } - - while (z1--) - *(bch->rx_ptr++) = fRead_hfc8(l1->hw); - - if (hdlc_complete) { - /* increment f counter */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); - wait_busy(l1->hw); - - /* hdlc crc check */ - bch->rx_ptr--; - if (*bch->rx_ptr) { - skb->len = 0; - bch->rx_ptr = skb->data; - continue; - } - skb->len -= 3; - } - if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) { - bch->rx_skb = NULL; - bch->rx_ptr = NULL; - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_DATA | INDICATION, skb); - } - - } while (1); -} /* rx_b_frame */ - -/********************************************/ -/* a D-frame has been/should be transmitted */ -/********************************************/ -static void -tx_d_frame(struct hfc4s8s_l1 *l1p) -{ - struct sk_buff *skb; - u_char f1, f2; - u_char *cp; - long cnt; - - if (l1p->l1_state != 7) - return; - - /* TX fifo */ - Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4)); - wait_busy(l1p->hw); - - f1 = Read_hfc8(l1p->hw, A_F1); - f2 = Read_hfc8_stable(l1p->hw, A_F2); - - if ((f1 ^ f2) & MAX_F_CNT) - return; /* fifo is still filled */ - - if (l1p->tx_cnt > 0) { - cnt = l1p->tx_cnt; - l1p->tx_cnt = 0; - l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM, - (void *) cnt); - } - - if ((skb = skb_dequeue(&l1p->d_tx_queue))) { - cp = skb->data; - cnt = skb->len; - SetRegAddr(l1p->hw, A_FIFO_DATA0); - - while (cnt >= 4) { - SetRegAddr(l1p->hw, A_FIFO_DATA0); - fWrite_hfc32(l1p->hw, *(unsigned long *) cp); - cp += 4; - cnt -= 4; - } - - while (cnt--) - fWrite_hfc8(l1p->hw, *cp++); - - l1p->tx_cnt = skb->truesize; - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ - wait_busy(l1p->hw); - - dev_kfree_skb(skb); - } -} /* tx_d_frame */ - -/******************************************************/ -/* a B-frame may be transmitted (or is not completed) */ -/******************************************************/ -static void -tx_b_frame(struct hfc4s8s_btype *bch) -{ - struct sk_buff *skb; - struct hfc4s8s_l1 *l1 = bch->l1p; - u_char *cp; - int cnt, max, hdlc_num; - long ack_len = 0; - - if (!l1->enabled || (bch->mode == L1_MODE_NULL)) - return; - - /* TX fifo */ - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2))); - wait_busy(l1->hw); - do { - - if (bch->mode == L1_MODE_HDLC) { - hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT; - hdlc_num -= - (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT); - if (hdlc_num < 0) - hdlc_num += 16; - if (hdlc_num >= 15) - break; /* fifo still filled up with hdlc frames */ - } else - hdlc_num = 0; - - if (!(skb = bch->tx_skb)) { - if (!(skb = skb_dequeue(&bch->tx_queue))) { - l1->hw->mr.fifo_slow_timer_service[l1-> - st_num] - &= ~((bch->bchan == 1) ? 1 : 4); - break; /* list empty */ - } - bch->tx_skb = skb; - bch->tx_cnt = 0; - } - - if (!hdlc_num) - l1->hw->mr.fifo_slow_timer_service[l1->st_num] |= - ((bch->bchan == 1) ? 1 : 4); - else - l1->hw->mr.fifo_slow_timer_service[l1->st_num] &= - ~((bch->bchan == 1) ? 1 : 4); - - max = Read_hfc16_stable(l1->hw, A_Z2); - max -= Read_hfc16(l1->hw, A_Z1); - if (max <= 0) - max += 384; - max--; - - if (max < 16) - break; /* don't write to small amounts of bytes */ - - cnt = skb->len - bch->tx_cnt; - if (cnt > max) - cnt = max; - cp = skb->data + bch->tx_cnt; - bch->tx_cnt += cnt; - - SetRegAddr(l1->hw, A_FIFO_DATA0); - while (cnt >= 4) { - fWrite_hfc32(l1->hw, *(unsigned long *) cp); - cp += 4; - cnt -= 4; - } - - while (cnt--) - fWrite_hfc8(l1->hw, *cp++); - - if (bch->tx_cnt >= skb->len) { - if (bch->mode == L1_MODE_HDLC) { - /* increment f counter */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); - } - ack_len += skb->truesize; - bch->tx_skb = NULL; - bch->tx_cnt = 0; - dev_kfree_skb(skb); - } else - /* Re-Select */ - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == 1) ? 0 : 2))); - wait_busy(l1->hw); - } while (1); - - if (ack_len) - bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if, - PH_DATA | CONFIRM, (void *) ack_len); -} /* tx_b_frame */ - -/*************************************/ -/* bottom half handler for interrupt */ -/*************************************/ -static void -hfc4s8s_bh(struct work_struct *work) -{ - hfc4s8s_hw *hw = container_of(work, hfc4s8s_hw, tqueue); - u_char b; - struct hfc4s8s_l1 *l1p; - volatile u_char *fifo_stat; - int idx; - - /* handle layer 1 state changes */ - b = 1; - l1p = hw->l1; - while (b) { - if ((b & hw->mr.r_irq_statech)) { - /* reset l1 event */ - hw->mr.r_irq_statech &= ~b; - if (l1p->enabled) { - if (l1p->nt_mode) { - u_char oldstate = l1p->l1_state; - - Write_hfc8(l1p->hw, R_ST_SEL, - l1p->st_num); - l1p->l1_state = - Read_hfc8(l1p->hw, - A_ST_RD_STA) & 0xf; - - if ((oldstate == 3) - && (l1p->l1_state != 3)) - l1p->d_if.ifc.l1l2(&l1p-> - d_if. - ifc, - PH_DEACTIVATE - | - INDICATION, - NULL); - - if (l1p->l1_state != 2) { - del_timer(&l1p->l1_timer); - if (l1p->l1_state == 3) { - l1p->d_if.ifc. - l1l2(&l1p-> - d_if.ifc, - PH_ACTIVATE - | - INDICATION, - NULL); - } - } else { - /* allow transition */ - Write_hfc8(hw, A_ST_WR_STA, - M_SET_G2_G3); - mod_timer(&l1p->l1_timer, - jiffies + - L1_TIMER_T1); - } - printk(KERN_INFO - "HFC-4S/8S: NT ch %d l1 state %d -> %d\n", - l1p->st_num, oldstate, - l1p->l1_state); - } else { - u_char oldstate = l1p->l1_state; - - Write_hfc8(l1p->hw, R_ST_SEL, - l1p->st_num); - l1p->l1_state = - Read_hfc8(l1p->hw, - A_ST_RD_STA) & 0xf; - - if (((l1p->l1_state == 3) && - ((oldstate == 7) || - (oldstate == 8))) || - ((timer_pending - (&l1p->l1_timer)) - && (l1p->l1_state == 8))) { - mod_timer(&l1p->l1_timer, - L1_TIMER_T4 + - jiffies); - } else { - if (l1p->l1_state == 7) { - del_timer(&l1p-> - l1_timer); - l1p->d_if.ifc. - l1l2(&l1p-> - d_if.ifc, - PH_ACTIVATE - | - INDICATION, - NULL); - tx_d_frame(l1p); - } - if (l1p->l1_state == 3) { - if (oldstate != 3) - l1p->d_if. - ifc. - l1l2 - (&l1p-> - d_if. - ifc, - PH_DEACTIVATE - | - INDICATION, - NULL); - } - } - printk(KERN_INFO - "HFC-4S/8S: TE %d ch %d l1 state %d -> %d\n", - l1p->hw->cardnum, - l1p->st_num, oldstate, - l1p->l1_state); - } - } - } - b <<= 1; - l1p++; - } - - /* now handle the fifos */ - idx = 0; - fifo_stat = hw->mr.r_irq_fifo_blx; - l1p = hw->l1; - while (idx < hw->driver_data.max_st_ports) { - - if (hw->mr.timer_irq) { - *fifo_stat |= hw->mr.fifo_rx_trans_enables[idx]; - if (hw->fifo_sched_cnt <= 0) { - *fifo_stat |= - hw->mr.fifo_slow_timer_service[l1p-> - st_num]; - } - } - /* ignore fifo 6 (TX E fifo) */ - *fifo_stat &= 0xff - 0x40; - - while (*fifo_stat) { - - if (!l1p->nt_mode) { - /* RX Fifo has data to read */ - if ((*fifo_stat & 0x20)) { - *fifo_stat &= ~0x20; - rx_d_frame(l1p, 0); - } - /* E Fifo has data to read */ - if ((*fifo_stat & 0x80)) { - *fifo_stat &= ~0x80; - rx_d_frame(l1p, 1); - } - /* TX Fifo completed send */ - if ((*fifo_stat & 0x10)) { - *fifo_stat &= ~0x10; - tx_d_frame(l1p); - } - } - /* B1 RX Fifo has data to read */ - if ((*fifo_stat & 0x2)) { - *fifo_stat &= ~0x2; - rx_b_frame(l1p->b_ch); - } - /* B1 TX Fifo has send completed */ - if ((*fifo_stat & 0x1)) { - *fifo_stat &= ~0x1; - tx_b_frame(l1p->b_ch); - } - /* B2 RX Fifo has data to read */ - if ((*fifo_stat & 0x8)) { - *fifo_stat &= ~0x8; - rx_b_frame(l1p->b_ch + 1); - } - /* B2 TX Fifo has send completed */ - if ((*fifo_stat & 0x4)) { - *fifo_stat &= ~0x4; - tx_b_frame(l1p->b_ch + 1); - } - } - fifo_stat++; - l1p++; - idx++; - } - - if (hw->fifo_sched_cnt <= 0) - hw->fifo_sched_cnt += (1 << (7 - TRANS_TIMER_MODE)); - hw->mr.timer_irq = 0; /* clear requested timer irq */ -} /* hfc4s8s_bh */ - -/*********************/ -/* interrupt handler */ -/*********************/ -static irqreturn_t -hfc4s8s_interrupt(int intno, void *dev_id) -{ - hfc4s8s_hw *hw = dev_id; - u_char b, ovr; - volatile u_char *ovp; - int idx; - u_char old_ioreg; - - if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN)) - return IRQ_NONE; - - /* read current selected regsister */ - old_ioreg = GetRegAddr(hw); - - /* Layer 1 State change */ - hw->mr.r_irq_statech |= - (Read_hfc8(hw, R_SCI) & hw->mr.r_irqmsk_statchg); - if (! - (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA))) - && !hw->mr.r_irq_statech) { - SetRegAddr(hw, old_ioreg); - return IRQ_NONE; - } - - /* timer event */ - if (Read_hfc8(hw, R_IRQ_MISC) & M_TI_IRQ) { - hw->mr.timer_irq = 1; - hw->fifo_sched_cnt--; - } - - /* FIFO event */ - if ((ovr = Read_hfc8(hw, R_IRQ_OVIEW))) { - hw->mr.r_irq_oview |= ovr; - idx = R_IRQ_FIFO_BL0; - ovp = hw->mr.r_irq_fifo_blx; - while (ovr) { - if ((ovr & 1)) { - *ovp |= Read_hfc8(hw, idx); - } - ovp++; - idx++; - ovr >>= 1; - } - } - - /* queue the request to allow other cards to interrupt */ - schedule_work(&hw->tqueue); - - SetRegAddr(hw, old_ioreg); - return IRQ_HANDLED; -} /* hfc4s8s_interrupt */ - -/***********************************************************************/ -/* reset the complete chip, don't release the chips irq but disable it */ -/***********************************************************************/ -static void -chipreset(hfc4s8s_hw *hw) -{ - u_long flags; - - spin_lock_irqsave(&hw->lock, flags); - Write_hfc8(hw, R_CTRL, 0); /* use internal RAM */ - Write_hfc8(hw, R_RAM_MISC, 0); /* 32k*8 RAM */ - Write_hfc8(hw, R_FIFO_MD, 0); /* fifo mode 386 byte/fifo simple mode */ - Write_hfc8(hw, R_CIRM, M_SRES); /* reset chip */ - hw->mr.r_irq_ctrl = 0; /* interrupt is inactive */ - spin_unlock_irqrestore(&hw->lock, flags); - - udelay(3); - Write_hfc8(hw, R_CIRM, 0); /* disable reset */ - wait_busy(hw); - - Write_hfc8(hw, R_PCM_MD0, M_PCM_MD); /* master mode */ - Write_hfc8(hw, R_RAM_MISC, M_FZ_MD); /* transmit fifo option */ - if (hw->driver_data.clock_mode == 1) - Write_hfc8(hw, R_BRG_PCM_CFG, M_PCM_CLK); /* PCM clk / 2 */ - Write_hfc8(hw, R_TI_WD, TRANS_TIMER_MODE); /* timer interval */ - - memset(&hw->mr, 0, sizeof(hw->mr)); -} /* chipreset */ - -/********************************************/ -/* disable/enable hardware in nt or te mode */ -/********************************************/ -static void -hfc_hardware_enable(hfc4s8s_hw *hw, int enable, int nt_mode) -{ - u_long flags; - char if_name[40]; - int i; - - if (enable) { - /* save system vars */ - hw->nt_mode = nt_mode; - - /* enable fifo and state irqs, but not global irq enable */ - hw->mr.r_irq_ctrl = M_FIFO_IRQ; - Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl); - hw->mr.r_irqmsk_statchg = 0; - Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg); - Write_hfc8(hw, R_PWM_MD, 0x80); - Write_hfc8(hw, R_PWM1, 26); - if (!nt_mode) - Write_hfc8(hw, R_ST_SYNC, M_AUTO_SYNC); - - /* enable the line interfaces and fifos */ - for (i = 0; i < hw->driver_data.max_st_ports; i++) { - hw->mr.r_irqmsk_statchg |= (1 << i); - Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg); - Write_hfc8(hw, R_ST_SEL, i); - Write_hfc8(hw, A_ST_CLK_DLY, - ((nt_mode) ? CLKDEL_NT : CLKDEL_TE)); - hw->mr.r_ctrl0 = ((nt_mode) ? CTRL0_NT : CTRL0_TE); - Write_hfc8(hw, A_ST_CTRL0, hw->mr.r_ctrl0); - Write_hfc8(hw, A_ST_CTRL2, 3); - Write_hfc8(hw, A_ST_WR_STA, 0); /* enable state machine */ - - hw->l1[i].enabled = 1; - hw->l1[i].nt_mode = nt_mode; - - if (!nt_mode) { - /* setup E-fifo */ - Write_hfc8(hw, R_FIFO, i * 8 + 7); /* E fifo */ - wait_busy(hw); - Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */ - Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */ - Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */ - Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(hw); - - /* setup D RX-fifo */ - Write_hfc8(hw, R_FIFO, i * 8 + 5); /* RX fifo */ - wait_busy(hw); - Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */ - Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */ - Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */ - Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(hw); - - /* setup D TX-fifo */ - Write_hfc8(hw, R_FIFO, i * 8 + 4); /* TX fifo */ - wait_busy(hw); - Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */ - Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */ - Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */ - Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(hw); - } - - sprintf(if_name, "hfc4s8s_%d%d_", hw->cardnum, i); - - if (hisax_register - (&hw->l1[i].d_if, hw->l1[i].b_table, if_name, - ((nt_mode) ? 3 : 2))) { - - hw->l1[i].enabled = 0; - hw->mr.r_irqmsk_statchg &= ~(1 << i); - Write_hfc8(hw, R_SCI_MSK, - hw->mr.r_irqmsk_statchg); - printk(KERN_INFO - "HFC-4S/8S: Unable to register S/T device %s, break\n", - if_name); - break; - } - } - spin_lock_irqsave(&hw->lock, flags); - hw->mr.r_irq_ctrl |= M_GLOB_IRQ_EN; - Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl); - spin_unlock_irqrestore(&hw->lock, flags); - } else { - /* disable hardware */ - spin_lock_irqsave(&hw->lock, flags); - hw->mr.r_irq_ctrl &= ~M_GLOB_IRQ_EN; - Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl); - spin_unlock_irqrestore(&hw->lock, flags); - - for (i = hw->driver_data.max_st_ports - 1; i >= 0; i--) { - hw->l1[i].enabled = 0; - hisax_unregister(&hw->l1[i].d_if); - del_timer(&hw->l1[i].l1_timer); - skb_queue_purge(&hw->l1[i].d_tx_queue); - skb_queue_purge(&hw->l1[i].b_ch[0].tx_queue); - skb_queue_purge(&hw->l1[i].b_ch[1].tx_queue); - } - chipreset(hw); - } -} /* hfc_hardware_enable */ - -/******************************************/ -/* disable memory mapped ports / io ports */ -/******************************************/ -static void -release_pci_ports(hfc4s8s_hw *hw) -{ - pci_write_config_word(hw->pdev, PCI_COMMAND, 0); - if (hw->iobase) - release_region(hw->iobase, 8); -} - -/*****************************************/ -/* enable memory mapped ports / io ports */ -/*****************************************/ -static void -enable_pci_ports(hfc4s8s_hw *hw) -{ - pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO); -} - -/*************************************/ -/* initialise the HFC-4s/8s hardware */ -/* return 0 on success. */ -/*************************************/ -static int -setup_instance(hfc4s8s_hw *hw) -{ - int err = -EIO; - int i; - - for (i = 0; i < HFC_MAX_ST; i++) { - struct hfc4s8s_l1 *l1p; - - l1p = hw->l1 + i; - spin_lock_init(&l1p->lock); - l1p->hw = hw; - timer_setup(&l1p->l1_timer, hfc_l1_timer, 0); - l1p->st_num = i; - skb_queue_head_init(&l1p->d_tx_queue); - l1p->d_if.ifc.priv = hw->l1 + i; - l1p->d_if.ifc.l2l1 = (void *) dch_l2l1; - - spin_lock_init(&l1p->b_ch[0].lock); - l1p->b_ch[0].b_if.ifc.l2l1 = (void *) bch_l2l1; - l1p->b_ch[0].b_if.ifc.priv = (void *) &l1p->b_ch[0]; - l1p->b_ch[0].l1p = hw->l1 + i; - l1p->b_ch[0].bchan = 1; - l1p->b_table[0] = &l1p->b_ch[0].b_if; - skb_queue_head_init(&l1p->b_ch[0].tx_queue); - - spin_lock_init(&l1p->b_ch[1].lock); - l1p->b_ch[1].b_if.ifc.l2l1 = (void *) bch_l2l1; - l1p->b_ch[1].b_if.ifc.priv = (void *) &l1p->b_ch[1]; - l1p->b_ch[1].l1p = hw->l1 + i; - l1p->b_ch[1].bchan = 2; - l1p->b_table[1] = &l1p->b_ch[1].b_if; - skb_queue_head_init(&l1p->b_ch[1].tx_queue); - } - - enable_pci_ports(hw); - chipreset(hw); - - i = Read_hfc8(hw, R_CHIP_ID) >> CHIP_ID_SHIFT; - if (i != hw->driver_data.chip_id) { - printk(KERN_INFO - "HFC-4S/8S: invalid chip id 0x%x instead of 0x%x, card ignored\n", - i, hw->driver_data.chip_id); - goto out; - } - - i = Read_hfc8(hw, R_CHIP_RV) & 0xf; - if (!i) { - printk(KERN_INFO - "HFC-4S/8S: chip revision 0 not supported, card ignored\n"); - goto out; - } - - INIT_WORK(&hw->tqueue, hfc4s8s_bh); - - if (request_irq - (hw->irq, hfc4s8s_interrupt, IRQF_SHARED, hw->card_name, hw)) { - printk(KERN_INFO - "HFC-4S/8S: unable to alloc irq %d, card ignored\n", - hw->irq); - goto out; - } - printk(KERN_INFO - "HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n", - hw->iobase, hw->irq); - - hfc_hardware_enable(hw, 1, 0); - - return (0); - -out: - hw->irq = 0; - release_pci_ports(hw); - kfree(hw); - return (err); -} - -/*****************************************/ -/* PCI hotplug interface: probe new card */ -/*****************************************/ -static int -hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data; - hfc4s8s_hw *hw; - - if (!(hw = kzalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) { - printk(KERN_ERR "No kmem for HFC-4S/8S card\n"); - return (err); - } - - hw->pdev = pdev; - err = pci_enable_device(pdev); - - if (err) - goto out; - - hw->cardnum = card_cnt; - sprintf(hw->card_name, "hfc4s8s_%d", hw->cardnum); - printk(KERN_INFO "HFC-4S/8S: found adapter %s (%s) at %s\n", - driver_data->device_name, hw->card_name, pci_name(pdev)); - - spin_lock_init(&hw->lock); - - hw->driver_data = *driver_data; - hw->irq = pdev->irq; - hw->iobase = pci_resource_start(pdev, 0); - - if (!request_region(hw->iobase, 8, hw->card_name)) { - printk(KERN_INFO - "HFC-4S/8S: failed to request address space at 0x%04x\n", - hw->iobase); - err = -EBUSY; - goto out; - } - - pci_set_drvdata(pdev, hw); - err = setup_instance(hw); - if (!err) - card_cnt++; - return (err); - -out: - kfree(hw); - return (err); -} - -/**************************************/ -/* PCI hotplug interface: remove card */ -/**************************************/ -static void -hfc4s8s_remove(struct pci_dev *pdev) -{ - hfc4s8s_hw *hw = pci_get_drvdata(pdev); - - printk(KERN_INFO "HFC-4S/8S: removing card %d\n", hw->cardnum); - hfc_hardware_enable(hw, 0, 0); - - if (hw->irq) - free_irq(hw->irq, hw); - hw->irq = 0; - release_pci_ports(hw); - - card_cnt--; - pci_disable_device(pdev); - kfree(hw); - return; -} - -static struct pci_driver hfc4s8s_driver = { - .name = "hfc4s8s_l1", - .probe = hfc4s8s_probe, - .remove = hfc4s8s_remove, - .id_table = hfc4s8s_ids, -}; - -/**********************/ -/* driver Module init */ -/**********************/ -static int __init -hfc4s8s_module_init(void) -{ - int err; - - printk(KERN_INFO - "HFC-4S/8S: Layer 1 driver module for HFC-4S/8S isdn chips, %s\n", - hfc4s8s_rev); - printk(KERN_INFO - "HFC-4S/8S: (C) 2003 Cornelius Consult, www.cornelius-consult.de\n"); - - card_cnt = 0; - - err = pci_register_driver(&hfc4s8s_driver); - if (err < 0) { - goto out; - } - printk(KERN_INFO "HFC-4S/8S: found %d cards\n", card_cnt); - - return 0; -out: - return (err); -} /* hfc4s8s_init_hw */ - -/*************************************/ -/* driver module exit : */ -/* release the HFC-4s/8s hardware */ -/*************************************/ -static void __exit -hfc4s8s_module_exit(void) -{ - pci_unregister_driver(&hfc4s8s_driver); - printk(KERN_INFO "HFC-4S/8S: module removed\n"); -} /* hfc4s8s_release_hw */ - -module_init(hfc4s8s_module_init); -module_exit(hfc4s8s_module_exit); diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h deleted file mode 100644 index 4665b9d5df16..000000000000 --- a/drivers/isdn/hisax/hfc4s8s_l1.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/***************************************************************/ -/* $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */ -/* */ -/* This file is a minimal required extraction of hfc48scu.h */ -/* (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S) */ -/* */ -/* To get this complete register description contact */ -/* Cologne Chip AG : */ -/* Internet: http://www.colognechip.com/ */ -/* E-Mail: info@colognechip.com */ -/***************************************************************/ - -#ifndef _HFC4S8S_L1_H_ -#define _HFC4S8S_L1_H_ - - -/* - * include Genero generated HFC-4S/8S header file hfc48scu.h - * for complete register description. This will define _HFC48SCU_H_ - * to prevent redefinitions - */ - -// #include "hfc48scu.h" - -#ifndef _HFC48SCU_H_ -#define _HFC48SCU_H_ - -#ifndef PCI_VENDOR_ID_CCD -#define PCI_VENDOR_ID_CCD 0x1397 -#endif - -#define CHIP_ID_4S 0x0C -#define CHIP_ID_8S 0x08 -#define PCI_DEVICE_ID_4S 0x08B4 -#define PCI_DEVICE_ID_8S 0x16B8 - -#define R_IRQ_MISC 0x11 -#define M_TI_IRQ 0x02 -#define A_ST_RD_STA 0x30 -#define A_ST_WR_STA 0x30 -#define M_SET_G2_G3 0x80 -#define A_ST_CTRL0 0x31 -#define A_ST_CTRL2 0x33 -#define A_ST_CLK_DLY 0x37 -#define A_Z1 0x04 -#define A_Z2 0x06 -#define R_CIRM 0x00 -#define M_SRES 0x08 -#define R_CTRL 0x01 -#define R_BRG_PCM_CFG 0x02 -#define M_PCM_CLK 0x20 -#define R_RAM_MISC 0x0C -#define M_FZ_MD 0x80 -#define R_FIFO_MD 0x0D -#define A_INC_RES_FIFO 0x0E -#define R_FIFO 0x0F -#define A_F1 0x0C -#define A_F2 0x0D -#define R_IRQ_OVIEW 0x10 -#define R_CHIP_ID 0x16 -#define R_STATUS 0x1C -#define M_BUSY 0x01 -#define M_MISC_IRQSTA 0x40 -#define M_FR_IRQSTA 0x80 -#define R_CHIP_RV 0x1F -#define R_IRQ_CTRL 0x13 -#define M_FIFO_IRQ 0x01 -#define M_GLOB_IRQ_EN 0x08 -#define R_PCM_MD0 0x14 -#define M_PCM_MD 0x01 -#define A_FIFO_DATA0 0x80 -#define R_TI_WD 0x1A -#define R_PWM1 0x39 -#define R_PWM_MD 0x46 -#define R_IRQ_FIFO_BL0 0xC8 -#define A_CON_HDLC 0xFA -#define A_SUBCH_CFG 0xFB -#define A_IRQ_MSK 0xFF -#define R_SCI_MSK 0x12 -#define R_ST_SEL 0x16 -#define R_ST_SYNC 0x17 -#define M_AUTO_SYNC 0x08 -#define R_SCI 0x12 -#define R_IRQMSK_MISC 0x11 -#define M_TI_IRQMSK 0x02 - -#endif /* _HFC4S8S_L1_H_ */ -#endif /* _HFC48SCU_H_ */ diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c deleted file mode 100644 index 3715fa0343db..000000000000 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $ - * - * specific routines for CCD's HFC 2BDS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include "hisax.h" -#include "hfc_2bds0.h" -#include "isdnl1.h" -#include -/* - #define KDEBUG_DEF - #include "kdebug.h" -*/ - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static void -dummyf(struct IsdnCardState *cs, u_char *data, int size) -{ - printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n"); -} - -static inline u_char -ReadReg(struct IsdnCardState *cs, int data, u_char reg) -{ - register u_char ret; - - if (data) { - if (cs->hw.hfcD.cip != reg) { - cs->hw.hfcD.cip = reg; - byteout(cs->hw.hfcD.addr | 1, reg); - } - ret = bytein(cs->hw.hfcD.addr); -#ifdef HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) - debugl1(cs, "t3c RD %02x %02x", reg, ret); -#endif - } else - ret = bytein(cs->hw.hfcD.addr | 1); - return (ret); -} - -static inline void -WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value) -{ - if (cs->hw.hfcD.cip != reg) { - cs->hw.hfcD.cip = reg; - byteout(cs->hw.hfcD.addr | 1, reg); - } - if (data) - byteout(cs->hw.hfcD.addr, value); -#ifdef HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) - debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value); -#endif -} - -/* Interface functions */ - -static u_char -readreghfcd(struct IsdnCardState *cs, u_char offset) -{ - return (ReadReg(cs, HFCD_DATA, offset)); -} - -static void -writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value) -{ - WriteReg(cs, HFCD_DATA, offset, value); -} - -static inline int -WaitForBusy(struct IsdnCardState *cs) -{ - int to = 130; - - while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: WaitForBusy timeout\n"); - return (to); -} - -static inline int -WaitNoBusy(struct IsdnCardState *cs) -{ - int to = 130; - - while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n"); - return (to); -} - -static int -SelFiFo(struct IsdnCardState *cs, u_char FiFo) -{ - u_char cip; - - if (cs->hw.hfcD.fifo == FiFo) - return (1); - switch (FiFo) { - case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1; - break; - case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1; - break; - case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2; - break; - case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2; - break; - case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND; - break; - case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC; - break; - default: - debugl1(cs, "SelFiFo Error"); - return (0); - } - cs->hw.hfcD.fifo = FiFo; - WaitNoBusy(cs); - cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0); - WaitForBusy(cs); - return (2); -} - -static int -GetFreeFifoBytes_B(struct BCState *bcs) -{ - int s; - - if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2) - return (bcs->cs->hw.hfcD.bfifosize); - s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2]; - if (s <= 0) - s += bcs->cs->hw.hfcD.bfifosize; - s = bcs->cs->hw.hfcD.bfifosize - s; - return (s); -} - -static int -GetFreeFifoBytes_D(struct IsdnCardState *cs) -{ - int s; - - if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2) - return (cs->hw.hfcD.dfifosize); - s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2]; - if (s <= 0) - s += cs->hw.hfcD.dfifosize; - s = cs->hw.hfcD.dfifosize - s; - return (s); -} - -static int -ReadZReg(struct IsdnCardState *cs, u_char reg) -{ - int val; - - WaitNoBusy(cs); - val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH); - WaitNoBusy(cs); - val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW); - return (val); -} - -static struct sk_buff -*hfc_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct sk_buff *skb; - struct IsdnCardState *cs = bcs->cs; - int idx; - int chksum; - u_char stat, cip; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfc_empty_fifo"); - idx = 0; - if (count > HSCX_BUFMAX + 3) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too large"); - cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); - while (idx++ < count) { - WaitNoBusy(cs); - ReadReg(cs, HFCD_DATA_NODEB, cip); - } - skb = NULL; - } else if (count < 4) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too small"); - cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - while ((idx++ < count) && WaitNoBusy(cs)) - ReadReg(cs, HFCD_DATA_NODEB, cip); - skb = NULL; - } else if (!(skb = dev_alloc_skb(count - 3))) - printk(KERN_WARNING "HFC: receive out of memory\n"); - else { - ptr = skb_put(skb, count - 3); - idx = 0; - cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); - while (idx < (count - 3)) { - if (!WaitNoBusy(cs)) - break; - *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip); - ptr++; - idx++; - } - if (idx != count - 3) { - debugl1(cs, "RFIFO BUSY error"); - printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb_irq(skb); - skb = NULL; - } else { - WaitNoBusy(cs); - chksum = (ReadReg(cs, HFCD_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += ReadReg(cs, HFCD_DATA, cip); - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, cip); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", - bcs->channel, chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb_irq(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - } - } - WaitForBusy(cs); - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC | - HFCB_REC | HFCB_CHANNEL(bcs->channel)); - WaitForBusy(cs); - return (skb); -} - -static void -hfc_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int idx, fcnt; - int count; - u_char cip; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); - cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip); - WaitNoBusy(cs); - cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip); - bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", - bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, - bcs->hw.hfc.send[bcs->hw.hfc.f1]); - fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; - if (fcnt < 0) - fcnt += 32; - if (fcnt > 30) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo more as 30 frames"); - return; - } - count = GetFreeFifoBytes_B(bcs); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d count(%u/%d),%lx", - bcs->channel, bcs->tx_skb->len, - count, current->state); - if (count < bcs->tx_skb->len) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo no fifo mem"); - return; - } - cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel); - idx = 0; - WaitForBusy(cs); - WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); - while (idx < bcs->tx_skb->len) { - if (!WaitNoBusy(cs)) - break; - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]); - idx++; - } - if (idx != bcs->tx_skb->len) { - debugl1(cs, "FIFO Send BUSY error"); - printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); - } else { - bcs->tx_cnt -= bcs->tx_skb->len; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - WaitForBusy(cs); - WaitNoBusy(cs); - ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); - WaitForBusy(cs); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - return; -} - -static void -hfc_send_data(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "send_data %d blocked", bcs->channel); -} - -static void -main_rec_2bds0(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int z1, z2, rcnt; - u_char f1, f2, cip; - int receive, count = 5; - struct sk_buff *skb; - -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_data %d blocked", bcs->channel); - return; - } - SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel)); - cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f1 = ReadReg(cs, HFCD_DATA, cip); - cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = ReadReg(cs, HFCD_DATA, cip); - if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d f1(%d) f2(%d)", - bcs->channel, f1, f2); - z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); - z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfcD.bfifosize; - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); - if ((skb = hfc_empty_fifo(bcs, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - rcnt = f1 - f2; - if (rcnt < 0) - rcnt += 32; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else - receive = 0; - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && receive) - goto Begin; - return; -} - -static void -mode_2bs0(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFCD bchannel mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfcD.conn |= 0x18; - cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA; - } else { - cs->hw.hfcD.conn |= 0x3; - cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA; - } - break; - case (L1_MODE_TRANS): - if (bc) { - cs->hw.hfcD.ctmt |= 2; - cs->hw.hfcD.conn &= ~0x18; - cs->hw.hfcD.sctrl |= SCTRL_B2_ENA; - } else { - cs->hw.hfcD.ctmt |= 1; - cs->hw.hfcD.conn &= ~0x3; - cs->hw.hfcD.sctrl |= SCTRL_B1_ENA; - } - break; - case (L1_MODE_HDLC): - if (bc) { - cs->hw.hfcD.ctmt &= ~2; - cs->hw.hfcD.conn &= ~0x18; - cs->hw.hfcD.sctrl |= SCTRL_B2_ENA; - } else { - cs->hw.hfcD.ctmt &= ~1; - cs->hw.hfcD.conn &= ~0x3; - cs->hw.hfcD.sctrl |= SCTRL_B1_ENA; - } - break; - } - WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); - WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn); -} - -static void -hfc_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); - } else { -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_2bs0(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_2bs0(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_2bs0(struct BCState *bcs) -{ - mode_2bs0(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_2b(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfc_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void -hfcd_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - switch (cs->dc.hfcd.ph_state) { - case (0): - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (7): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - default: - break; - } - } - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -} - -static -int receive_dmsg(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int idx; - int rcnt, z1, z2; - u_char stat, cip, f1, f2; - int chksum; - int count = 5; - u_char *ptr; - - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_dmsg blocked"); - return (1); - } - SelFiFo(cs, 4 | HFCD_REC); - cip = HFCD_FIFO | HFCD_F1 | HFCD_REC; - WaitNoBusy(cs); - f1 = cs->readisac(cs, cip) & 0xf; - cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; - WaitNoBusy(cs); - f2 = cs->readisac(cs, cip) & 0xf; - while ((f1 != f2) && count--) { - z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC); - z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfcD.dfifosize; - rcnt++; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", - f1, f2, z1, z2, rcnt); - idx = 0; - cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC; - if (rcnt > MAX_DFRAME_LEN + 3) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo d: incoming packet too large"); - while (idx < rcnt) { - if (!(WaitNoBusy(cs))) - break; - ReadReg(cs, HFCD_DATA_NODEB, cip); - idx++; - } - } else if (rcnt < 4) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo d: incoming packet too small"); - while ((idx++ < rcnt) && WaitNoBusy(cs)) - ReadReg(cs, HFCD_DATA_NODEB, cip); - } else if ((skb = dev_alloc_skb(rcnt - 3))) { - ptr = skb_put(skb, rcnt - 3); - while (idx < (rcnt - 3)) { - if (!(WaitNoBusy(cs))) - break; - *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip); - idx++; - ptr++; - } - if (idx != (rcnt - 3)) { - debugl1(cs, "RFIFO D BUSY error"); - printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); - dev_kfree_skb_irq(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - } else { - WaitNoBusy(cs); - chksum = (ReadReg(cs, HFCD_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += ReadReg(cs, HFCD_DATA, cip); - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, cip); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "empty_dfifo chksum %x stat %x", - chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb_irq(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - cs->err_crc++; -#endif - } else { - skb_queue_tail(&cs->rq, skb); - schedule_event(cs, D_RCVBUFREADY); - } - } - } else - printk(KERN_WARNING "HFC: D receive out of memory\n"); - WaitForBusy(cs); - cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC; - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, cip); - WaitForBusy(cs); - cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; - WaitNoBusy(cs); - f2 = cs->readisac(cs, cip) & 0xf; - } - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return (1); -} - -static void -hfc_fill_dfifo(struct IsdnCardState *cs) -{ - int idx, fcnt; - int count; - u_char cip; - - if (!cs->tx_skb) - return; - if (cs->tx_skb->len <= 0) - return; - - SelFiFo(cs, 4 | HFCD_SEND); - cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND; - WaitNoBusy(cs); - cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf; - WaitNoBusy(cs); - cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND; - cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf; - cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", - cs->hw.hfcD.f1, cs->hw.hfcD.f2, - cs->hw.hfcD.send[cs->hw.hfcD.f1]); - fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2; - if (fcnt < 0) - fcnt += 16; - if (fcnt > 14) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_Dfifo more as 14 frames"); - return; - } - count = GetFreeFifoBytes_D(cs); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfc_fill_Dfifo count(%u/%d)", - cs->tx_skb->len, count); - if (count < cs->tx_skb->len) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfc_fill_Dfifo no fifo mem"); - return; - } - cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND; - idx = 0; - WaitForBusy(cs); - WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]); - while (idx < cs->tx_skb->len) { - if (!(WaitNoBusy(cs))) - break; - WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]); - idx++; - } - if (idx != cs->tx_skb->len) { - debugl1(cs, "DFIFO Send BUSY error"); - printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n"); - } - WaitForBusy(cs); - WaitNoBusy(cs); - ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - WaitForBusy(cs); - return; -} - -static -struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -void -hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) -{ - u_char exval; - struct BCState *bcs; - int count = 15; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCD irq %x %s", val, - test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? - "locked" : "unlocked"); - val &= cs->hw.hfcD.int_m1; - if (val & 0x40) { /* TE state machine irq */ - exval = cs->readisac(cs, HFCD_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state, - exval); - cs->dc.hfcd.ph_state = exval; - schedule_event(cs, D_L1STATECHANGE); - val &= ~0x40; - } - while (val) { - if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - cs->hw.hfcD.int_s1 |= val; - return; - } - if (cs->hw.hfcD.int_s1 & 0x18) { - exval = val; - val = cs->hw.hfcD.int_s1; - cs->hw.hfcD.int_s1 = exval; - } - if (val & 0x08) { - if (!(bcs = Sel_BCS(cs, 0))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x08 IRQ"); - } else - main_rec_2bds0(bcs); - } - if (val & 0x10) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x10 IRQ"); - } else - main_rec_2bds0(bcs); - } - if (val & 0x01) { - if (!(bcs = Sel_BCS(cs, 0))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x01 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x02) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x02 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x20) { /* receive dframe */ - receive_dmsg(cs); - } - if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfc_fill_dfifo irq blocked"); - } - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfc_fill_dfifo irq blocked"); - } - } else - schedule_event(cs, D_XMTBUFREADY); - } - afterXPR: - if (cs->hw.hfcD.int_s1 && count--) { - val = cs->hw.hfcD.int_s1; - cs->hw.hfcD.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCD irq %x loop %d", val, 15-count); - } else - val = 0; - } -} - -static void -HFCD_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfc_fill_dfifo blocked"); - - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfc_fill_dfifo blocked"); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */ - cs->hw.hfcD.mst_m |= HFCD_MASTER; - cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcD.mst_m &= ~HFCD_MASTER; - cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcD.mst_m |= HFCD_MASTER; - cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcd_l1hw unknown pr %4x", pr); - break; - } -} - -static void -setstack_hfcd(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = HFCD_l1hw; -} - -static void -hfc_dbusy_timer(struct timer_list *t) -{ -} - -static unsigned int -*init_send_hfcd(int cnt) -{ - int i; - unsigned *send; - - if (!(send = kmalloc_array(cnt, sizeof(unsigned int), GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hfcd.send\n"); - return (NULL); - } - for (i = 0; i < cnt; i++) - send[i] = 0x1fff; - return (send); -} - -void -init2bds0(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_hfcd; - if (!cs->hw.hfcD.send) - cs->hw.hfcD.send = init_send_hfcd(16); - if (!cs->bcs[0].hw.hfc.send) - cs->bcs[0].hw.hfc.send = init_send_hfcd(32); - if (!cs->bcs[1].hw.hfc.send) - cs->bcs[1].hw.hfc.send = init_send_hfcd(32); - cs->BC_Send_Data = &hfc_send_data; - cs->bcs[0].BC_SetStack = setstack_2b; - cs->bcs[1].BC_SetStack = setstack_2b; - cs->bcs[0].BC_Close = close_2bs0; - cs->bcs[1].BC_Close = close_2bs0; - mode_2bs0(cs->bcs, 0, 0); - mode_2bs0(cs->bcs + 1, 0, 1); -} - -void -release2bds0(struct IsdnCardState *cs) -{ - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; - kfree(cs->hw.hfcD.send); - cs->hw.hfcD.send = NULL; -} - -void -set_cs_func(struct IsdnCardState *cs) -{ - cs->readisac = &readreghfcd; - cs->writeisac = &writereghfcd; - cs->readisacfifo = &dummyf; - cs->writeisacfifo = &dummyf; - cs->BC_Read_Reg = &ReadReg; - cs->BC_Write_Reg = &WriteReg; - timer_setup(&cs->dbusytimer, hfc_dbusy_timer, 0); - INIT_WORK(&cs->tqueue, hfcd_bh); -} diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h deleted file mode 100644 index 8c7582a3c51e..000000000000 --- a/drivers/isdn/hisax/hfc_2bds0.h +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $ - * - * specific defines for CCD's HFC 2BDS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define HFCD_CIRM 0x18 -#define HFCD_CTMT 0x19 -#define HFCD_INT_M1 0x1A -#define HFCD_INT_M2 0x1B -#define HFCD_INT_S1 0x1E -#define HFCD_STAT 0x1C -#define HFCD_STAT_DISB 0x1D -#define HFCD_STATES 0x30 -#define HFCD_SCTRL 0x31 -#define HFCD_TEST 0x32 -#define HFCD_SQ 0x34 -#define HFCD_CLKDEL 0x37 -#define HFCD_MST_MODE 0x2E -#define HFCD_CONN 0x2F - -#define HFCD_FIFO 0x80 -#define HFCD_Z1 0x10 -#define HFCD_Z2 0x18 -#define HFCD_Z_LOW 0x00 -#define HFCD_Z_HIGH 0x04 -#define HFCD_F1_INC 0x12 -#define HFCD_FIFO_IN 0x16 -#define HFCD_F1 0x1a -#define HFCD_F2 0x1e -#define HFCD_F2_INC 0x22 -#define HFCD_FIFO_OUT 0x26 -#define HFCD_REC 0x01 -#define HFCD_SEND 0x00 - -#define HFCB_FIFO 0x80 -#define HFCB_Z1 0x00 -#define HFCB_Z2 0x08 -#define HFCB_Z_LOW 0x00 -#define HFCB_Z_HIGH 0x04 -#define HFCB_F1_INC 0x28 -#define HFCB_FIFO_IN 0x2c -#define HFCB_F1 0x30 -#define HFCB_F2 0x34 -#define HFCB_F2_INC 0x38 -#define HFCB_FIFO_OUT 0x3c -#define HFCB_REC 0x01 -#define HFCB_SEND 0x00 -#define HFCB_B1 0x00 -#define HFCB_B2 0x02 -#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1) - -#define HFCD_STATUS 0 -#define HFCD_DATA 1 -#define HFCD_DATA_NODEB 2 - -/* Status (READ) */ -#define HFCD_BUSY 0x01 -#define HFCD_BUSY_NBUSY 0x04 -#define HFCD_TIMER_ELAP 0x10 -#define HFCD_STATINT 0x20 -#define HFCD_FRAMEINT 0x40 -#define HFCD_ANYINT 0x80 - -/* CTMT (Write) */ -#define HFCD_CLTIMER 0x80 -#define HFCD_TIM25 0x00 -#define HFCD_TIM50 0x08 -#define HFCD_TIM400 0x10 -#define HFCD_TIM800 0x18 -#define HFCD_AUTO_TIMER 0x20 -#define HFCD_TRANSB2 0x02 -#define HFCD_TRANSB1 0x01 - -/* CIRM (Write) */ -#define HFCD_RESET 0x08 -#define HFCD_MEM8K 0x10 -#define HFCD_INTA 0x01 -#define HFCD_INTB 0x02 -#define HFCD_INTC 0x03 -#define HFCD_INTD 0x04 -#define HFCD_INTE 0x05 -#define HFCD_INTF 0x06 - -/* INT_M1;INT_S1 */ -#define HFCD_INTS_B1TRANS 0x01 -#define HFCD_INTS_B2TRANS 0x02 -#define HFCD_INTS_DTRANS 0x04 -#define HFCD_INTS_B1REC 0x08 -#define HFCD_INTS_B2REC 0x10 -#define HFCD_INTS_DREC 0x20 -#define HFCD_INTS_L1STATE 0x40 -#define HFCD_INTS_TIMER 0x80 - -/* INT_M2 */ -#define HFCD_IRQ_ENABLE 0x08 - -/* STATES */ -#define HFCD_LOAD_STATE 0x10 -#define HFCD_ACTIVATE 0x20 -#define HFCD_DO_ACTION 0x40 - -/* HFCD_MST_MODE */ -#define HFCD_MASTER 0x01 - -/* HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* HFCD_TEST */ -#define HFCD_AUTO_AWAKE 0x01 - -extern void main_irq_2bds0(struct BCState *bcs); -extern void init2bds0(struct IsdnCardState *cs); -extern void release2bds0(struct IsdnCardState *cs); -extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val); -extern void set_cs_func(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c deleted file mode 100644 index 34d59992839a..000000000000 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ /dev/null @@ -1,591 +0,0 @@ -/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $ - * - * specific routines for CCD's HFC 2BS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "hfc_2bs0.h" -#include "isac.h" -#include "isdnl1.h" -#include -#include - -static inline int -WaitForBusy(struct IsdnCardState *cs) -{ - int to = 130; - u_char val; - - while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { - val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 | - (cs->hw.hfc.cip & 3)); - udelay(1); - to--; - } - if (!to) { - printk(KERN_WARNING "HiSax: %s timeout\n", __func__); - return (0); - } else - return (to); -} - -static inline int -WaitNoBusy(struct IsdnCardState *cs) -{ - int to = 125; - - while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { - udelay(1); - to--; - } - if (!to) { - printk(KERN_WARNING "HiSax: waitforBusy timeout\n"); - return (0); - } else - return (to); -} - -static int -GetFreeFifoBytes(struct BCState *bcs) -{ - int s; - - if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2) - return (bcs->cs->hw.hfc.fifosize); - s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2]; - if (s <= 0) - s += bcs->cs->hw.hfc.fifosize; - s = bcs->cs->hw.hfc.fifosize - s; - return (s); -} - -static int -ReadZReg(struct BCState *bcs, u_char reg) -{ - int val; - - WaitNoBusy(bcs->cs); - val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH); - WaitNoBusy(bcs->cs); - val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW); - return (val); -} - -static void -hfc_clear_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int idx, cnt; - int rcnt, z1, z2; - u_char cip, f1, f2; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfc_clear_fifo"); - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); - if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); - } - WaitNoBusy(cs); - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - cnt = 32; - while (((f1 != f2) || (z1 != z2)) && cnt--) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc clear %d f1(%d) f2(%d)", - bcs->channel, f1, f2); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfc.fifosize; - if (rcnt) - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - idx = 0; - while ((idx < rcnt) && WaitNoBusy(cs)) { - cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - idx++; - } - if (f1 != f2) { - WaitNoBusy(cs); - cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - } - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - } - return; -} - - -static struct sk_buff -* -hfc_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct sk_buff *skb; - struct IsdnCardState *cs = bcs->cs; - int idx; - int chksum; - u_char stat, cip; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfc_empty_fifo"); - idx = 0; - if (count > HSCX_BUFMAX + 3) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too large"); - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx++ < count) && WaitNoBusy(cs)) - cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - return (NULL); - } - if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too small"); - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx++ < count) && WaitNoBusy(cs)) - cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - return (NULL); - } - if (bcs->mode == L1_MODE_TRANS) - count -= 1; - else - count -= 3; - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HFC: receive out of memory\n"); - else { - ptr = skb_put(skb, count); - idx = 0; - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx < count) && WaitNoBusy(cs)) { - *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - idx++; - } - if (idx != count) { - debugl1(cs, "RFIFO BUSY error"); - printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb_any(skb); - if (bcs->mode != L1_MODE_TRANS) { - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - } - return (NULL); - } - if (bcs->mode != L1_MODE_TRANS) { - WaitNoBusy(cs); - chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", - bcs->channel, chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb_any(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - } - } - return (skb); -} - -static void -hfc_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int idx, fcnt; - int count; - int z1, z2; - u_char cip; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel); - if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); - } - WaitNoBusy(cs); - if (bcs->mode != L1_MODE_TRANS) { - bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", - bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, - bcs->hw.hfc.send[bcs->hw.hfc.f1]); - fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; - if (fcnt < 0) - fcnt += 32; - if (fcnt > 30) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo more as 30 frames"); - return; - } - count = GetFreeFifoBytes(bcs); - } - else { - WaitForBusy(cs); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - count = z1 - z2; - if (count < 0) - count += cs->hw.hfc.fifosize; - } /* L1_MODE_TRANS */ - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d count(%u/%d)", - bcs->channel, bcs->tx_skb->len, - count); - if (count < bcs->tx_skb->len) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo no fifo mem"); - return; - } - cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel); - idx = 0; - while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs)) - cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); - if (idx != bcs->tx_skb->len) { - debugl1(cs, "FIFO Send BUSY error"); - printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); - } else { - count = bcs->tx_skb->len; - bcs->tx_cnt -= count; - if (PACKET_NOACK == bcs->tx_skb->pkt_type) - count = -1; - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - if (bcs->mode != L1_MODE_TRANS) { - WaitForBusy(cs); - WaitNoBusy(cs); - cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); - } - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (count >= 0)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - return; -} - -void -main_irq_hfc(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int z1, z2, rcnt; - u_char f1, f2, cip; - int receive, transmit, count = 5; - struct sk_buff *skb; - -Begin: - count--; - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); - if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); - } - WaitNoBusy(cs); - receive = 0; - if (bcs->mode == L1_MODE_HDLC) { - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d f1(%d) f2(%d)", - bcs->channel, f1, f2); - receive = 1; - } - } - if (receive || (bcs->mode == L1_MODE_TRANS)) { - WaitForBusy(cs); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfc.fifosize; - if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) { - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); - /* sti(); */ - if ((skb = hfc_empty_fifo(bcs, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - } - receive = 1; - } - if (bcs->tx_skb) { - transmit = 1; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hfc_fill_fifo(bcs); - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) - transmit = 0; - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - transmit = 1; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hfc_fill_fifo(bcs); - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) - transmit = 0; - } else { - transmit = 0; - schedule_event(bcs, B_XMTBUFREADY); - } - } - if ((receive || transmit) && count) - goto Begin; - return; -} - -static void -mode_hfc(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfc.ctmt &= ~1; - cs->hw.hfc.isac_spcr &= ~0x03; - } - else { - cs->hw.hfc.ctmt &= ~2; - cs->hw.hfc.isac_spcr &= ~0x0c; - } - break; - case (L1_MODE_TRANS): - cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */ - cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); - hfc_clear_fifo(bcs); /* complete fifo clear */ - if (bc) { - cs->hw.hfc.ctmt |= 1; - cs->hw.hfc.isac_spcr &= ~0x03; - cs->hw.hfc.isac_spcr |= 0x02; - } else { - cs->hw.hfc.ctmt |= 2; - cs->hw.hfc.isac_spcr &= ~0x0c; - cs->hw.hfc.isac_spcr |= 0x08; - } - break; - case (L1_MODE_HDLC): - if (bc) { - cs->hw.hfc.ctmt &= ~1; - cs->hw.hfc.isac_spcr &= ~0x03; - cs->hw.hfc.isac_spcr |= 0x02; - } else { - cs->hw.hfc.ctmt &= ~2; - cs->hw.hfc.isac_spcr &= ~0x0c; - cs->hw.hfc.isac_spcr |= 0x08; - } - break; - } - cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); - cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr); - if (mode == L1_MODE_HDLC) - hfc_clear_fifo(bcs); -} - -static void -hfc_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_hfc(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_hfc(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - - -static void -close_hfcstate(struct BCState *bcs) -{ - mode_hfc(bcs, 0, bcs->channel); - if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); -} - -static int -open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_hfc(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfc_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void -init_send(struct BCState *bcs) -{ - int i; - - bcs->hw.hfc.send = kmalloc_array(32, sizeof(unsigned int), GFP_ATOMIC); - if (!bcs->hw.hfc.send) { - printk(KERN_WARNING - "HiSax: No memory for hfc.send\n"); - return; - } - for (i = 0; i < 32; i++) - bcs->hw.hfc.send[i] = 0x1fff; -} - -void -inithfc(struct IsdnCardState *cs) -{ - init_send(&cs->bcs[0]); - init_send(&cs->bcs[1]); - cs->BC_Send_Data = &hfc_fill_fifo; - cs->bcs[0].BC_SetStack = setstack_hfc; - cs->bcs[1].BC_SetStack = setstack_hfc; - cs->bcs[0].BC_Close = close_hfcstate; - cs->bcs[1].BC_Close = close_hfcstate; - mode_hfc(cs->bcs, 0, 0); - mode_hfc(cs->bcs + 1, 0, 0); -} - -void -releasehfc(struct IsdnCardState *cs) -{ - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; -} diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h deleted file mode 100644 index 1510096363dc..000000000000 --- a/drivers/isdn/hisax/hfc_2bs0.h +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $ - * - * specific defines for CCD's HFC 2BS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define HFC_CTMT 0xe0 -#define HFC_CIRM 0xc0 -#define HFC_CIP 0x80 -#define HFC_Z1 0x00 -#define HFC_Z2 0x08 -#define HFC_Z_LOW 0x00 -#define HFC_Z_HIGH 0x04 -#define HFC_F1_INC 0x28 -#define HFC_FIFO_IN 0x2c -#define HFC_F1 0x30 -#define HFC_F2 0x34 -#define HFC_F2_INC 0x38 -#define HFC_FIFO_OUT 0x3c -#define HFC_B1 0x00 -#define HFC_B2 0x02 -#define HFC_REC 0x01 -#define HFC_SEND 0x00 -#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1) - -#define HFC_STATUS 0 -#define HFC_DATA 1 -#define HFC_DATA_NODEB 2 - -/* Status (READ) */ -#define HFC_BUSY 0x01 -#define HFC_TIMINT 0x02 -#define HFC_EXTINT 0x04 - -/* CTMT (Write) */ -#define HFC_CLTIMER 0x10 -#define HFC_TIM50MS 0x08 -#define HFC_TIMIRQE 0x04 -#define HFC_TRANSB2 0x02 -#define HFC_TRANSB1 0x01 - -/* CIRM (Write) */ -#define HFC_RESET 0x08 -#define HFC_MEM8K 0x10 -#define HFC_INTA 0x01 -#define HFC_INTB 0x02 -#define HFC_INTC 0x03 -#define HFC_INTD 0x04 -#define HFC_INTE 0x05 -#define HFC_INTF 0x06 - -extern void main_irq_hfc(struct BCState *bcs); -extern void inithfc(struct IsdnCardState *cs); -extern void releasehfc(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c deleted file mode 100644 index 71a8312592d6..000000000000 --- a/drivers/isdn/hisax/hfc_pci.c +++ /dev/null @@ -1,1755 +0,0 @@ -/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $ - * - * low level driver for CCD's hfc-pci based cards - * - * Author Werner Cornelius - * based on existing driver for CCD hfc ISA cards - * Copyright by Werner Cornelius - * by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - */ - -#include -#include "hisax.h" -#include "hfc_pci.h" -#include "isdnl1.h" -#include -#include -#include - -static const char *hfcpci_revision = "$Revision: 1.48.2.4 $"; - -/* table entry in the PCI devices list */ -typedef struct { - int vendor_id; - int device_id; - char *vendor_name; - char *card_name; -} PCI_ENTRY; - -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ -#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ -#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ - -static const PCI_ENTRY id_list[] = -{ - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, "Primux II S0", "B700"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, "Primux II S0 NT", "B701"}, - {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"}, - {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"}, - {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"}, - {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"}, - {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"}, - {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, "Digi International", "Digi DataFire Micro V IOM2 (Europe)"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, "Digi International", "Digi DataFire Micro V (Europe)"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, "Digi International", "Digi DataFire Micro V IOM2 (North America)"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, "Digi International", "Digi DataFire Micro V (North America)"}, - {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, "Sitecom Europe", "DC-105 ISDN PCI"}, - {0, 0, NULL, NULL}, -}; - - -/******************************************/ -/* free hardware resources used by driver */ -/******************************************/ -static void -release_io_hfcpci(struct IsdnCardState *cs) -{ - printk(KERN_INFO "HiSax: release hfcpci at %p\n", - cs->hw.hfcpci.pci_io); - cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ - mdelay(10); - Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - mdelay(10); - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ - del_timer(&cs->hw.hfcpci.timer); - pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, - cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); - cs->hw.hfcpci.fifos = NULL; - iounmap(cs->hw.hfcpci.pci_io); -} - -/********************************************************************************/ -/* function called to reset the HFC PCI chip. A complete software reset of chip */ -/* and fifos is done. */ -/********************************************************************************/ -static void -reset_hfcpci(struct IsdnCardState *cs) -{ - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ - cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - - printk(KERN_INFO "HFC_PCI: resetting card\n"); - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ - Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ - mdelay(10); - Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - mdelay(10); - if (Read_hfc(cs, HFCPCI_STATUS) & 2) - printk(KERN_WARNING "HFC-PCI init bit busy\n"); - - cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */ - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - - cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ - Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - - Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */ - cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; - Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ - cs->hw.hfcpci.bswapped = 0; /* no exchange */ - cs->hw.hfcpci.nt_mode = 0; /* we are in TE mode */ - cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); - - cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | - HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - - /* Clear already pending ints */ - Read_hfc(cs, HFCPCI_INT_S1); - - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - Write_hfc(cs, HFCPCI_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */ - - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); - cs->hw.hfcpci.sctrl_r = 0; - Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); - - /* Init GCI/IOM2 in master mode */ - /* Slots 0 and 1 are set for B-chan 1 and 2 */ - /* D- and monitor/CI channel are not enabled */ - /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ - /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continuous 1s */ - /* The IOM slots are always enabled */ - cs->hw.hfcpci.conn = 0x36; /* set data flow directions */ - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ - Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ - Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ - Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ - - /* Finally enable IRQ output */ - cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE; - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - Read_hfc(cs, HFCPCI_INT_S1); -} - -/***************************************************/ -/* Timer function called when kernel timer expires */ -/***************************************************/ -static void -hfcpci_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfcpci.timer); - cs->hw.hfcpci.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80); - add_timer(&cs->hw.hfcpci.timer); -*/ -} - - -/*********************************/ -/* schedule a new D-channel task */ -/*********************************/ -static void -sched_event_D_pci(struct IsdnCardState *cs, int event) -{ - test_and_set_bit(event, &cs->event); - schedule_work(&cs->tqueue); -} - -/*********************************/ -/* schedule a new b_channel task */ -/*********************************/ -static void -hfcpci_sched_event(struct BCState *bcs, int event) -{ - test_and_set_bit(event, &bcs->event); - schedule_work(&bcs->tqueue); -} - -/************************************************/ -/* select a b-channel entry matching and active */ -/************************************************/ -static -struct BCState * -Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -/***************************************/ -/* clear the desired B-channel rx fifo */ -/***************************************/ -static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo) -{ u_char fifo_state; - bzfifo_type *bzr; - - if (fifo) { - bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX; - } else { - bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX; - } - if (fifo_state) - cs->hw.hfcpci.fifo_en ^= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0; - bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; - bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; - bzr->f1 = MAX_B_FRAMES; - bzr->f2 = bzr->f1; /* init F pointers to remain constant */ - if (fifo_state) - cs->hw.hfcpci.fifo_en |= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); -} - -/***************************************/ -/* clear the desired B-channel tx fifo */ -/***************************************/ -static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo) -{ u_char fifo_state; - bzfifo_type *bzt; - - if (fifo) { - bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX; - } else { - bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX; - } - if (fifo_state) - cs->hw.hfcpci.fifo_en ^= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; - bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; - bzt->f1 = MAX_B_FRAMES; - bzt->f2 = bzt->f1; /* init F pointers to remain constant */ - if (fifo_state) - cs->hw.hfcpci.fifo_en |= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); -} - -/*********************************************/ -/* read a complete B-frame out of the buffer */ -/*********************************************/ -static struct sk_buff -* -hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type *bz, u_char *bdata, int count) -{ - u_char *ptr, *ptr1, new_f2; - struct sk_buff *skb; - struct IsdnCardState *cs = bcs->cs; - int maxlen, new_z2; - z_type *zp; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfcpci_empty_fifo"); - zp = &bz->za[bz->f2]; /* point to Z-Regs */ - new_z2 = zp->z2 + count; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; - if ((count > HSCX_BUFMAX + 3) || (count < 4) || - (*(bdata + (zp->z1 - B_SUB_VAL)))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - skb = NULL; - } else if (!(skb = dev_alloc_skb(count - 3))) - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - else { - count -= 3; - ptr = skb_put(skb, count); - - if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = count; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ - - ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - count -= maxlen; - - if (count) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, count); /* rest */ - } - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - - } - return (skb); -} - -/*******************************/ -/* D-channel receive procedure */ -/*******************************/ -static -int -receive_dmsg(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int maxlen; - int rcnt, total; - int count = 5; - u_char *ptr, *ptr1; - dfifo_type *df; - z_type *zp; - - df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_dmsg blocked"); - return (1); - } - while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { - zp = &df->za[df->f2 & D_FREG_MASK]; - rcnt = zp->z1 - zp->z2; - if (rcnt < 0) - rcnt += D_FIFO_SIZE; - rcnt++; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", - df->f1, df->f2, zp->z1, zp->z2, rcnt); - - if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || - (df->data[zp->z1])) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo hfcpci packet inv. len %d or crc %d", rcnt, df->data[zp->z1]); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); - } else if ((skb = dev_alloc_skb(rcnt - 3))) { - total = rcnt; - rcnt -= 3; - ptr = skb_put(skb, rcnt); - - if (zp->z2 + rcnt <= D_FIFO_SIZE) - maxlen = rcnt; /* complete transfer */ - else - maxlen = D_FIFO_SIZE - zp->z2; /* maximum */ - - ptr1 = df->data + zp->z2; /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - rcnt -= maxlen; - - if (rcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = df->data; /* start of buffer */ - memcpy(ptr, ptr1, rcnt); /* rest */ - } - df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1); - - skb_queue_tail(&cs->rq, skb); - sched_event_D_pci(cs, D_RCVBUFREADY); - } else - printk(KERN_WARNING "HFC-PCI: D receive out of memory\n"); - } - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return (1); -} - -/*******************************************************************************/ -/* check for transparent receive data and read max one threshold size if avail */ -/*******************************************************************************/ -static int -hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata) -{ - unsigned short *z1r, *z2r; - int new_z2, fcnt, maxlen; - struct sk_buff *skb; - u_char *ptr, *ptr1; - - z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ - z2r = z1r + 1; - - if (!(fcnt = *z1r - *z2r)) - return (0); /* no data avail */ - - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; /* bytes actually buffered */ - if (fcnt > HFCPCI_BTRANS_THRESHOLD) - fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ - - new_z2 = *z2r + fcnt; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - - if (!(skb = dev_alloc_skb(fcnt))) - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - else { - ptr = skb_put(skb, fcnt); - if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = fcnt; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */ - - ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - fcnt -= maxlen; - - if (fcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, fcnt); /* rest */ - } - skb_queue_tail(&bcs->rqueue, skb); - hfcpci_sched_event(bcs, B_RCVBUFREADY); - } - - *z2r = new_z2; /* new position */ - return (1); -} /* hfcpci_empty_fifo_trans */ - -/**********************************/ -/* B-channel main receive routine */ -/**********************************/ -static void -main_rec_hfcpci(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int rcnt, real_fifo; - int receive, count = 5; - struct sk_buff *skb; - bzfifo_type *bz; - u_char *bdata; - z_type *zp; - - - if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; - real_fifo = 1; - } else { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1; - real_fifo = 0; - } -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_data %d blocked", bcs->channel); - return; - } - if (bz->f1 != bz->f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)", - bcs->channel, bz->f1, bz->f2); - zp = &bz->za[bz->f2]; - - rcnt = zp->z1 - zp->z2; - if (rcnt < 0) - rcnt += B_FIFO_SIZE; - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, zp->z1, zp->z2, rcnt); - if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - hfcpci_sched_event(bcs, B_RCVBUFREADY); - } - rcnt = bz->f1 - bz->f2; - if (rcnt < 0) - rcnt += MAX_B_FRAMES + 1; - if (cs->hw.hfcpci.last_bfifo_cnt[real_fifo] > rcnt + 1) { - rcnt = 0; - hfcpci_clear_fifo_rx(cs, real_fifo); - } - cs->hw.hfcpci.last_bfifo_cnt[real_fifo] = rcnt; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else if (bcs->mode == L1_MODE_TRANS) - receive = hfcpci_empty_fifo_trans(bcs, bz, bdata); - else - receive = 0; - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && receive) - goto Begin; -} - -/**************************/ -/* D-channel send routine */ -/**************************/ -static void -hfcpci_fill_dfifo(struct IsdnCardState *cs) -{ - int fcnt; - int count, new_z1, maxlen; - dfifo_type *df; - u_char *src, *dst, new_f1; - - if (!cs->tx_skb) - return; - if (cs->tx_skb->len <= 0) - return; - - df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_tx; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)", - df->f1, df->f2, - df->za[df->f1 & D_FREG_MASK].z1); - fcnt = df->f1 - df->f2; /* frame count actually buffered */ - if (fcnt < 0) - fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ - if (fcnt > (MAX_D_FRAMES - 1)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - return; - } - /* now determine free bytes in FIFO buffer */ - count = df->za[df->f2 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1 - 1; - if (count <= 0) - count += D_FIFO_SIZE; /* count now contains available bytes */ - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo count(%u/%d)", - cs->tx_skb->len, count); - if (count < cs->tx_skb->len) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo no fifo mem"); - return; - } - count = cs->tx_skb->len; /* get frame len */ - new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1); - new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); - src = cs->tx_skb->data; /* source pointer */ - dst = df->data + df->za[df->f1 & D_FREG_MASK].z1; - maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = df->data; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */ - df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */ - df->f1 = new_f1; /* next frame */ - - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; -} - -/**************************/ -/* B-channel send routine */ -/**************************/ -static void -hfcpci_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int maxlen, fcnt; - int count, new_z1; - bzfifo_type *bz; - u_char *bdata; - u_char new_f1, *src, *dst; - unsigned short *z1t, *z2t; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b2; - } else { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1; - } - - if (bcs->mode == L1_MODE_TRANS) { - z1t = &bz->za[MAX_B_FRAMES].z1; - z2t = z1t + 1; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)", - bcs->channel, *z1t, *z2t); - fcnt = *z2t - *z1t; - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */ - fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */ - - while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) { - if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { - /* data is suitable for fifo */ - count = bcs->tx_skb->len; - - new_z1 = *z1t + count; /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - src = bcs->tx_skb->data; /* source pointer */ - dst = bdata + (*z1t - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - bcs->tx_cnt -= bcs->tx_skb->len; - fcnt += bcs->tx_skb->len; - *z1t = new_z1; /* now send data */ - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", - bcs->channel, bcs->tx_skb->len); - - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - - dev_consume_skb_any(bcs->tx_skb); - bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - return; - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)", - bcs->channel, bz->f1, bz->f2, - bz->za[bz->f1].z1); - - fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ - if (fcnt < 0) - fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ - if (fcnt > (MAX_B_FRAMES - 1)) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_Bfifo more as 14 frames"); - return; - } - /* now determine free bytes in FIFO buffer */ - count = bz->za[bz->f2].z2 - bz->za[bz->f1].z1 - 1; - if (count <= 0) - count += B_FIFO_SIZE; /* count now contains available bytes */ - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo %d count(%u/%d),%lx", - bcs->channel, bcs->tx_skb->len, - count, current->state); - - if (count < bcs->tx_skb->len) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo no fifo mem"); - return; - } - count = bcs->tx_skb->len; /* get frame len */ - new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - - new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); - src = bcs->tx_skb->data; /* source pointer */ - dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - bcs->tx_cnt -= bcs->tx_skb->len; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - - bz->za[new_f1].z1 = new_z1; /* for next buffer */ - bz->f1 = new_f1; /* next frame */ - - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); -} - -/**********************************************/ -/* D-channel l1 state call for leased NT-mode */ -/**********************************************/ -static void -dch_nt_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(cs, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (cs->debug) - debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); - break; - } -} - - - -/***********************/ -/* set/reset echo mode */ -/***********************/ -static int -hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) -{ - u_long flags; - int i = *(unsigned int *) ic->parm.num; - - if ((ic->arg == 98) && - (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ - udelay(10); - cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT; - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); /* set NT-mode */ - udelay(10); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* HFC ST G1 */ - udelay(10); - Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); - cs->dc.hfcpci.ph_state = 1; - cs->hw.hfcpci.nt_mode = 1; - cs->hw.hfcpci.nt_timer = 0; - cs->stlist->l2.l2l1 = dch_nt_l2l1; - spin_unlock_irqrestore(&cs->lock, flags); - debugl1(cs, "NT mode activated"); - return (0); - } - if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) || - (cs->hw.hfcpci.nt_mode) || (ic->arg != 12)) - return (-EINVAL); - - spin_lock_irqsave(&cs->lock, flags); - if (i) { - cs->logecho = 1; - cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */ - cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC; - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX; - } else { - cs->logecho = 0; - cs->hw.hfcpci.trm &= ~0x20; /* disable echo chan */ - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC; - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX; - } - cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */ - cs->hw.hfcpci.ctmt &= ~2; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); - Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); -} /* hfcpci_auxcmd */ - -/*****************************/ -/* E-channel receive routine */ -/*****************************/ -static void -receive_emsg(struct IsdnCardState *cs) -{ - int rcnt; - int receive, count = 5; - bzfifo_type *bz; - u_char *bdata; - z_type *zp; - u_char *ptr, *ptr1, new_f2; - int total, maxlen, new_z2; - u_char e_buffer[256]; - - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "echo_rec_data blocked"); - return; - } - if (bz->f1 != bz->f2) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)", - bz->f1, bz->f2); - zp = &bz->za[bz->f2]; - - rcnt = zp->z1 - zp->z2; - if (rcnt < 0) - rcnt += B_FIFO_SIZE; - rcnt++; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)", - zp->z1, zp->z2, rcnt); - new_z2 = zp->z2 + rcnt; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; - if ((rcnt > 256 + 3) || (count < 4) || - (*(bdata + (zp->z1 - B_SUB_VAL)))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt); - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - } else { - total = rcnt; - rcnt -= 3; - ptr = e_buffer; - - if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = rcnt; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ - - ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - rcnt -= maxlen; - - if (rcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, rcnt); /* rest */ - } - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - if (cs->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += QuickHex(ptr, e_buffer, total - 3); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3); - } - } - - rcnt = bz->f1 - bz->f2; - if (rcnt < 0) - rcnt += MAX_B_FRAMES + 1; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else - receive = 0; - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && receive) - goto Begin; -} /* receive_emsg */ - -/*********************/ -/* Interrupt handler */ -/*********************/ -static irqreturn_t -hfcpci_interrupt(int intno, void *dev_id) -{ - u_long flags; - struct IsdnCardState *cs = dev_id; - u_char exval; - struct BCState *bcs; - int count = 15; - u_char val, stat; - - if (!(cs->hw.hfcpci.int_m2 & 0x08)) { - debugl1(cs, "HFC-PCI: int_m2 %x not initialised", cs->hw.hfcpci.int_m2); - return IRQ_NONE; /* not initialised */ - } - spin_lock_irqsave(&cs->lock, flags); - if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) { - val = Read_hfc(cs, HFCPCI_INT_S1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val); - } else { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI irq %x %s", val, - test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? - "locked" : "unlocked"); - val &= cs->hw.hfcpci.int_m1; - if (val & 0x40) { /* state machine irq */ - exval = Read_hfc(cs, HFCPCI_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state, - exval); - cs->dc.hfcpci.ph_state = exval; - sched_event_D_pci(cs, D_L1STATECHANGE); - val &= ~0x40; - } - if (val & 0x80) { /* timer irq */ - if (cs->hw.hfcpci.nt_mode) { - if ((--cs->hw.hfcpci.nt_timer) < 0) - sched_event_D_pci(cs, D_L1STATECHANGE); - } - val &= ~0x80; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); - } - while (val) { - if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - cs->hw.hfcpci.int_s1 |= val; - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - if (cs->hw.hfcpci.int_s1 & 0x18) { - exval = val; - val = cs->hw.hfcpci.int_s1; - cs->hw.hfcpci.int_s1 = exval; - } - if (val & 0x08) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x08 IRQ"); - } else - main_rec_hfcpci(bcs); - } - if (val & 0x10) { - if (cs->logecho) - receive_emsg(cs); - else if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x10 IRQ"); - } else - main_rec_hfcpci(bcs); - } - if (val & 0x01) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x01 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - hfcpci_sched_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x02) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x02 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - hfcpci_sched_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x20) { /* receive dframe */ - receive_dmsg(cs); - } - if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_event_D_pci(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcpci_fill_dfifo irq blocked"); - } - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcpci_fill_dfifo irq blocked"); - } - } else - sched_event_D_pci(cs, D_XMTBUFREADY); - } - afterXPR: - if (cs->hw.hfcpci.int_s1 && count--) { - val = cs->hw.hfcpci.int_s1; - cs->hw.hfcpci.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI irq %x loop %d", val, 15 - count); - } else - val = 0; - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -/********************************************************************/ -/* timer callback for D-chan busy resolution. Currently no function */ -/********************************************************************/ -static void -hfcpci_dbusy_timer(struct timer_list *t) -{ -} - -/*************************************/ -/* Layer 1 D-channel hardware access */ -/*************************************/ -static void -HFCPCI_l1hw(struct PStack *st, int pr, void *arg) -{ - u_long flags; - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcpci_fill_dfifo blocked"); - - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcpci_fill_dfifo blocked"); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - spin_lock_irqsave(&cs->lock, flags); - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */ - cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER; - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - switch ((long) arg) { - case (1): - Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* tx slot */ - Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* rx slot */ - cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1; - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - break; - - case (2): - Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* tx slot */ - Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* rx slot */ - cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08; - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - break; - - default: - spin_unlock_irqrestore(&cs->lock, flags); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_l1hw loop invalid %4lx", (long) arg); - return; - } - cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */ - Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr); - break; - } -} - -/***********************************************/ -/* called during init setting l1 stack pointer */ -/***********************************************/ -static void -setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = HFCPCI_l1hw; -} - -/**************************************/ -/* send B-channel data if not blocked */ -/**************************************/ -static void -hfcpci_send_data(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "send_data %d blocked", bcs->channel); -} - -/***************************************************************/ -/* activate/deactivate hardware for selected channels and mode */ -/***************************************************************/ -static void -mode_hfcpci(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int fifo2; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - fifo2 = bc; - if (cs->chanlimit > 1) { - cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcpci.sctrl_e &= ~0x80; - } else { - if (bc) { - if (mode != L1_MODE_NULL) { - cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */ - cs->hw.hfcpci.sctrl_e |= 0x80; - } else { - cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcpci.sctrl_e &= ~0x80; - } - fifo2 = 0; - } else { - cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcpci.sctrl_e &= ~0x80; - } - } - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA; - } else { - cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - } else { - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - } - break; - case (L1_MODE_TRANS): - hfcpci_clear_fifo_rx(cs, fifo2); - hfcpci_clear_fifo_tx(cs, fifo2); - if (bc) { - cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - cs->hw.hfcpci.ctmt |= 2; - cs->hw.hfcpci.conn &= ~0x18; - } else { - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - cs->hw.hfcpci.ctmt |= 1; - cs->hw.hfcpci.conn &= ~0x03; - } - break; - case (L1_MODE_HDLC): - hfcpci_clear_fifo_rx(cs, fifo2); - hfcpci_clear_fifo_tx(cs, fifo2); - if (bc) { - cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcpci.last_bfifo_cnt[1] = 0; - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - cs->hw.hfcpci.ctmt &= ~2; - cs->hw.hfcpci.conn &= ~0x18; - } else { - cs->hw.hfcpci.last_bfifo_cnt[0] = 0; - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - cs->hw.hfcpci.ctmt &= ~1; - cs->hw.hfcpci.conn &= ~0x03; - } - break; - case (L1_MODE_EXTRN): - if (bc) { - cs->hw.hfcpci.conn |= 0x10; - cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - } else { - cs->hw.hfcpci.conn |= 0x02; - cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - } - break; - } - Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); - Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); -} - -/******************************/ -/* Layer2 -> Layer 1 Transfer */ -/******************************/ -static void -hfcpci_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - u_long flags; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - spin_unlock_irqrestore(&bcs->cs->lock, flags); - printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); - break; - } -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_hfcpci(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_hfcpci(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -/******************************************/ -/* deactivate B-channel access and queues */ -/******************************************/ -static void -close_hfcpci(struct BCState *bcs) -{ - mode_hfcpci(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -/*************************************/ -/* init B-channel queues and control */ -/*************************************/ -static int -open_hfcpcistate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -/*********************************/ -/* inits the stack for B-channel */ -/*********************************/ -static int -setstack_2b(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcpcistate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfcpci_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -/***************************/ -/* handle L1 state changes */ -/***************************/ -static void -hfcpci_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - u_long flags; -// struct PStack *stptr; - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (!cs->hw.hfcpci.nt_mode) - switch (cs->dc.hfcpci.ph_state) { - case (0): - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (7): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - default: - break; - } else { - spin_lock_irqsave(&cs->lock, flags); - switch (cs->dc.hfcpci.ph_state) { - case (2): - if (cs->hw.hfcpci.nt_timer < 0) { - cs->hw.hfcpci.nt_timer = 0; - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - /* Clear already pending ints */ - Read_hfc(cs, HFCPCI_INT_S1); - Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); - udelay(10); - Write_hfc(cs, HFCPCI_STATES, 4); - cs->dc.hfcpci.ph_state = 4; - } else { - cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER; - cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); - cs->hw.hfcpci.nt_timer = NT_T1_COUNT; - Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */ - } - break; - case (1): - case (3): - case (4): - cs->hw.hfcpci.nt_timer = 0; - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - break; - default: - break; - } - spin_unlock_irqrestore(&cs->lock, flags); - } - } - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -} - - -/********************************/ -/* called for card init message */ -/********************************/ -static void -inithfcpci(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_2b; - cs->bcs[1].BC_SetStack = setstack_2b; - cs->bcs[0].BC_Close = close_hfcpci; - cs->bcs[1].BC_Close = close_hfcpci; - timer_setup(&cs->dbusytimer, hfcpci_dbusy_timer, 0); - mode_hfcpci(cs->bcs, 0, 0); - mode_hfcpci(cs->bcs + 1, 0, 1); -} - - - -/*******************************************/ -/* handle card messages from control layer */ -/*******************************************/ -static int -hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCPCI: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_hfcpci(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_hfcpci(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithfcpci(cs); - reset_hfcpci(cs); - spin_unlock_irqrestore(&cs->lock, flags); - msleep(80); /* Timeout 80ms */ - /* now switch timer interrupt off */ - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - /* reinit mode reg */ - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - - -/* this variable is used as card index when more than one cards are present */ -static struct pci_dev *dev_hfcpci = NULL; - -int -setup_hfcpci(struct IsdnCard *card) -{ - u_long flags; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - int i; - struct pci_dev *tmp_hfcpci = NULL; - - strcpy(tmp, hfcpci_revision); - printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); - - cs->hw.hfcpci.int_s1 = 0; - cs->dc.hfcpci.ph_state = 0; - cs->hw.hfcpci.fifo = 255; - if (cs->typ != ISDN_CTYPE_HFC_PCI) - return (0); - - i = 0; - while (id_list[i].vendor_id) { - tmp_hfcpci = hisax_find_pci_device(id_list[i].vendor_id, - id_list[i].device_id, - dev_hfcpci); - i++; - if (tmp_hfcpci) { - dma_addr_t dma_mask = DMA_BIT_MASK(32) & ~0x7fffUL; - if (pci_enable_device(tmp_hfcpci)) - continue; - if (pci_set_dma_mask(tmp_hfcpci, dma_mask)) { - printk(KERN_WARNING - "HiSax hfc_pci: No suitable DMA available.\n"); - continue; - } - if (pci_set_consistent_dma_mask(tmp_hfcpci, dma_mask)) { - printk(KERN_WARNING - "HiSax hfc_pci: No suitable consistent DMA available.\n"); - continue; - } - pci_set_master(tmp_hfcpci); - if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[0].start & PCI_BASE_ADDRESS_IO_MASK))) - continue; - else - break; - } - } - - if (!tmp_hfcpci) { - printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); - return (0); - } - - i--; - dev_hfcpci = tmp_hfcpci; /* old device */ - cs->hw.hfcpci.dev = dev_hfcpci; - cs->irq = dev_hfcpci->irq; - if (!cs->irq) { - printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256); - printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name); - - if (!cs->hw.hfcpci.pci_io) { - printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); - return (0); - } - - /* Allocate memory for FIFOS */ - cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev, - 0x8000, &cs->hw.hfcpci.dma); - if (!cs->hw.hfcpci.fifos) { - printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n"); - return 0; - } - if (cs->hw.hfcpci.dma & 0x7fff) { - printk(KERN_WARNING - "HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n", - (u_long)cs->hw.hfcpci.dma); - pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, - cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); - return 0; - } - pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma); - printk(KERN_INFO - "HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n", - cs->hw.hfcpci.pci_io, - cs->hw.hfcpci.fifos, - (u_long)cs->hw.hfcpci.dma, - cs->irq, HZ); - - spin_lock_irqsave(&cs->lock, flags); - - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ - cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */ - cs->hw.hfcpci.int_m1 = 0; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - /* At this point the needed PCI config is done */ - /* fifos are still not enabled */ - - INIT_WORK(&cs->tqueue, hfcpci_bh); - cs->setstack_d = setstack_hfcpci; - cs->BC_Send_Data = &hfcpci_send_data; - cs->readisac = NULL; - cs->writeisac = NULL; - cs->readisacfifo = NULL; - cs->writeisacfifo = NULL; - cs->BC_Read_Reg = NULL; - cs->BC_Write_Reg = NULL; - cs->irq_func = &hfcpci_interrupt; - cs->irq_flags |= IRQF_SHARED; - timer_setup(&cs->hw.hfcpci.timer, hfcpci_Timer, 0); - cs->cardmsg = &hfcpci_card_msg; - cs->auxcmd = &hfcpci_auxcmd; - - spin_unlock_irqrestore(&cs->lock, flags); - - return (1); -} diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h deleted file mode 100644 index 4c3b3ba35726..000000000000 --- a/drivers/isdn/hisax/hfc_pci.h +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $ - * - * specific defines for CCD's HFC 2BDS0 PCI chips - * - * Author Werner Cornelius - * Copyright by Werner Cornelius - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/*********************************************/ -/* thresholds for transparent B-channel mode */ -/* change mask and threshold simultaneously */ -/*********************************************/ -#define HFCPCI_BTRANS_THRESHOLD 128 -#define HFCPCI_BTRANS_THRESMASK 0x00 - - - -/* defines for PCI config */ - -#define PCI_ENA_MEMIO 0x02 -#define PCI_ENA_MASTER 0x04 - - -/* GCI/IOM bus monitor registers */ - -#define HCFPCI_C_I 0x08 -#define HFCPCI_TRxR 0x0C -#define HFCPCI_MON1_D 0x28 -#define HFCPCI_MON2_D 0x2C - - -/* GCI/IOM bus timeslot registers */ - -#define HFCPCI_B1_SSL 0x80 -#define HFCPCI_B2_SSL 0x84 -#define HFCPCI_AUX1_SSL 0x88 -#define HFCPCI_AUX2_SSL 0x8C -#define HFCPCI_B1_RSL 0x90 -#define HFCPCI_B2_RSL 0x94 -#define HFCPCI_AUX1_RSL 0x98 -#define HFCPCI_AUX2_RSL 0x9C - -/* GCI/IOM bus data registers */ - -#define HFCPCI_B1_D 0xA0 -#define HFCPCI_B2_D 0xA4 -#define HFCPCI_AUX1_D 0xA8 -#define HFCPCI_AUX2_D 0xAC - -/* GCI/IOM bus configuration registers */ - -#define HFCPCI_MST_EMOD 0xB4 -#define HFCPCI_MST_MODE 0xB8 -#define HFCPCI_CONNECT 0xBC - - -/* Interrupt and status registers */ - -#define HFCPCI_FIFO_EN 0x44 -#define HFCPCI_TRM 0x48 -#define HFCPCI_B_MODE 0x4C -#define HFCPCI_CHIP_ID 0x58 -#define HFCPCI_CIRM 0x60 -#define HFCPCI_CTMT 0x64 -#define HFCPCI_INT_M1 0x68 -#define HFCPCI_INT_M2 0x6C -#define HFCPCI_INT_S1 0x78 -#define HFCPCI_INT_S2 0x7C -#define HFCPCI_STATUS 0x70 - -/* S/T section registers */ - -#define HFCPCI_STATES 0xC0 -#define HFCPCI_SCTRL 0xC4 -#define HFCPCI_SCTRL_E 0xC8 -#define HFCPCI_SCTRL_R 0xCC -#define HFCPCI_SQ 0xD0 -#define HFCPCI_CLKDEL 0xDC -#define HFCPCI_B1_REC 0xF0 -#define HFCPCI_B1_SEND 0xF0 -#define HFCPCI_B2_REC 0xF4 -#define HFCPCI_B2_SEND 0xF4 -#define HFCPCI_D_REC 0xF8 -#define HFCPCI_D_SEND 0xF8 -#define HFCPCI_E_REC 0xFC - - -/* bits in status register (READ) */ -#define HFCPCI_PCI_PROC 0x02 -#define HFCPCI_NBUSY 0x04 -#define HFCPCI_TIMER_ELAP 0x10 -#define HFCPCI_STATINT 0x20 -#define HFCPCI_FRAMEINT 0x40 -#define HFCPCI_ANYINT 0x80 - -/* bits in CTMT (Write) */ -#define HFCPCI_CLTIMER 0x80 -#define HFCPCI_TIM3_125 0x04 -#define HFCPCI_TIM25 0x10 -#define HFCPCI_TIM50 0x14 -#define HFCPCI_TIM400 0x18 -#define HFCPCI_TIM800 0x1C -#define HFCPCI_AUTO_TIMER 0x20 -#define HFCPCI_TRANSB2 0x02 -#define HFCPCI_TRANSB1 0x01 - -/* bits in CIRM (Write) */ -#define HFCPCI_AUX_MSK 0x07 -#define HFCPCI_RESET 0x08 -#define HFCPCI_B1_REV 0x40 -#define HFCPCI_B2_REV 0x80 - -/* bits in INT_M1 and INT_S1 */ -#define HFCPCI_INTS_B1TRANS 0x01 -#define HFCPCI_INTS_B2TRANS 0x02 -#define HFCPCI_INTS_DTRANS 0x04 -#define HFCPCI_INTS_B1REC 0x08 -#define HFCPCI_INTS_B2REC 0x10 -#define HFCPCI_INTS_DREC 0x20 -#define HFCPCI_INTS_L1STATE 0x40 -#define HFCPCI_INTS_TIMER 0x80 - -/* bits in INT_M2 */ -#define HFCPCI_PROC_TRANS 0x01 -#define HFCPCI_GCI_I_CHG 0x02 -#define HFCPCI_GCI_MON_REC 0x04 -#define HFCPCI_IRQ_ENABLE 0x08 -#define HFCPCI_PMESEL 0x80 - -/* bits in STATES */ -#define HFCPCI_STATE_MSK 0x0F -#define HFCPCI_LOAD_STATE 0x10 -#define HFCPCI_ACTIVATE 0x20 -#define HFCPCI_DO_ACTION 0x40 -#define HFCPCI_NT_G2_G3 0x80 - -/* bits in HFCD_MST_MODE */ -#define HFCPCI_MASTER 0x01 -#define HFCPCI_SLAVE 0x00 -/* remaining bits are for codecs control */ - -/* bits in HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_MODE_TE 0x00 -#define SCTRL_MODE_NT 0x04 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* bits in SCTRL_E */ -#define HFCPCI_AUTO_AWAKE 0x01 -#define HFCPCI_DBIT_1 0x04 -#define HFCPCI_IGNORE_COL 0x08 -#define HFCPCI_CHG_B1_B2 0x80 - -/****************************/ -/* bits in FIFO_EN register */ -/****************************/ -#define HFCPCI_FIFOEN_B1 0x03 -#define HFCPCI_FIFOEN_B2 0x0C -#define HFCPCI_FIFOEN_DTX 0x10 -#define HFCPCI_FIFOEN_B1TX 0x01 -#define HFCPCI_FIFOEN_B1RX 0x02 -#define HFCPCI_FIFOEN_B2TX 0x04 -#define HFCPCI_FIFOEN_B2RX 0x08 - - -/***********************************/ -/* definitions of fifo memory area */ -/***********************************/ -#define MAX_D_FRAMES 15 -#define MAX_B_FRAMES 31 -#define B_SUB_VAL 0x200 -#define B_FIFO_SIZE (0x2000 - B_SUB_VAL) -#define D_FIFO_SIZE 512 -#define D_FREG_MASK 0xF - -typedef struct { - unsigned short z1; /* Z1 pointer 16 Bit */ - unsigned short z2; /* Z2 pointer 16 Bit */ -} z_type; - -typedef struct { - u_char data[D_FIFO_SIZE]; /* FIFO data space */ - u_char fill1[0x20A0 - D_FIFO_SIZE]; /* reserved, do not use */ - u_char f1, f2; /* f pointers */ - u_char fill2[0x20C0 - 0x20A2]; /* reserved, do not use */ - z_type za[MAX_D_FRAMES + 1]; /* mask index with D_FREG_MASK for access */ - u_char fill3[0x4000 - 0x2100]; /* align 16K */ -} dfifo_type; - -typedef struct { - z_type za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */ - u_char f1, f2; /* f pointers */ - u_char fill[0x2100 - 0x2082]; /* alignment */ -} bzfifo_type; - - -typedef union { - struct { - dfifo_type d_tx; /* D-send channel */ - dfifo_type d_rx; /* D-receive channel */ - } d_chan; - struct { - u_char fill1[0x200]; - u_char txdat_b1[B_FIFO_SIZE]; - bzfifo_type txbz_b1; - - bzfifo_type txbz_b2; - u_char txdat_b2[B_FIFO_SIZE]; - - u_char fill2[D_FIFO_SIZE]; - - u_char rxdat_b1[B_FIFO_SIZE]; - bzfifo_type rxbz_b1; - - bzfifo_type rxbz_b2; - u_char rxdat_b2[B_FIFO_SIZE]; - } b_chans; - u_char fill[32768]; -} fifo_area; - - -#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b)) -#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b)) - -extern void main_irq_hcpci(struct BCState *bcs); -extern void releasehfcpci(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c deleted file mode 100644 index 12af628d9b2c..000000000000 --- a/drivers/isdn/hisax/hfc_sx.c +++ /dev/null @@ -1,1517 +0,0 @@ -/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $ - * - * level driver for Cologne Chip Designs hfc-s+/sp based cards - * - * Author Werner Cornelius - * based on existing driver for CCD HFC PCI cards - * Copyright by Werner Cornelius - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "hfc_sx.h" -#include "isdnl1.h" -#include -#include -#include - -static const char *hfcsx_revision = "$Revision: 1.12.2.5 $"; - -/***************************************/ -/* IRQ-table for CCDs demo board */ -/* IRQs 6,5,10,11,12,15 are supported */ -/***************************************/ - -/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1 - * - * Thanks to Uwe Wisniewski - * - * ISA-SLOT Signal PIN - * B25 IRQ3 92 IRQ_G - * B23 IRQ5 94 IRQ_A - * B4 IRQ2/9 95 IRQ_B - * D3 IRQ10 96 IRQ_C - * D4 IRQ11 97 IRQ_D - * D5 IRQ12 98 IRQ_E - * D6 IRQ15 99 IRQ_F - */ - -#undef CCD_DEMO_BOARD -#ifdef CCD_DEMO_BOARD -static u_char ccd_sp_irqtab[16] = { - 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 3, 4, 5, 0, 0, 6 -}; -#else /* Teles 16.3c */ -static u_char ccd_sp_irqtab[16] = { - 0, 0, 0, 7, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 0, 6 -}; -#endif -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -/******************************/ -/* In/Out access to registers */ -/******************************/ -static inline void -Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val) -{ - byteout(cs->hw.hfcsx.base + 1, regnum); - byteout(cs->hw.hfcsx.base, val); -} - -static inline u_char -Read_hfc(struct IsdnCardState *cs, u_char regnum) -{ - u_char ret; - - byteout(cs->hw.hfcsx.base + 1, regnum); - ret = bytein(cs->hw.hfcsx.base); - return (ret); -} - - -/**************************************************/ -/* select a fifo and remember which one for reuse */ -/**************************************************/ -static void -fifo_select(struct IsdnCardState *cs, u_char fifo) -{ - if (fifo == cs->hw.hfcsx.last_fifo) - return; /* still valid */ - - byteout(cs->hw.hfcsx.base + 1, HFCSX_FIF_SEL); - byteout(cs->hw.hfcsx.base, fifo); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ - udelay(4); - byteout(cs->hw.hfcsx.base, fifo); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ -} - -/******************************************/ -/* reset the specified fifo to defaults. */ -/* If its a send fifo init needed markers */ -/******************************************/ -static void -reset_fifo(struct IsdnCardState *cs, u_char fifo) -{ - fifo_select(cs, fifo); /* first select the fifo */ - byteout(cs->hw.hfcsx.base + 1, HFCSX_CIRM); - byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */ - udelay(1); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ -} - - -/*************************************************************/ -/* write_fifo writes the skb contents to the desired fifo */ -/* if no space is available or an error occurs 0 is returned */ -/* the skb is not released in any way. */ -/*************************************************************/ -static int -write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max) -{ - unsigned short *msp; - int fifo_size, count, z1, z2; - u_char f_msk, f1, f2, *src; - - if (skb->len <= 0) return (0); - if (fifo & 1) return (0); /* no write fifo */ - - fifo_select(cs, fifo); - if (fifo & 4) { - fifo_size = D_FIFO_SIZE; /* D-channel */ - f_msk = MAX_D_FRAMES; - if (trans_max) return (0); /* only HDLC */ - } - else { - fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ - f_msk = MAX_B_FRAMES; - } - - z1 = Read_hfc(cs, HFCSX_FIF_Z1H); - z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); - - /* Check for transparent mode */ - if (trans_max) { - z2 = Read_hfc(cs, HFCSX_FIF_Z2H); - z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); - count = z2 - z1; - if (count <= 0) - count += fifo_size; /* free bytes */ - if (count < skb->len + 1) return (0); /* no room */ - count = fifo_size - count; /* bytes still not send */ - if (count > 2 * trans_max) return (0); /* delay to long */ - count = skb->len; - src = skb->data; - while (count--) - Write_hfc(cs, HFCSX_FIF_DWR, *src++); - return (1); /* success */ - } - - msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker; - msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES + 1)); - f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; - f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; - - count = f1 - f2; /* frame count actually buffered */ - if (count < 0) - count += (f_msk + 1); /* if wrap around */ - if (count > f_msk - 1) { - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d more as %d frames", fifo, f_msk - 1); - return (0); - } - - *(msp + f1) = z1; /* remember marker */ - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)", - fifo, f1, f2, z1); - /* now determine free bytes in FIFO buffer */ - count = *(msp + f2) - z1; - if (count <= 0) - count += fifo_size; /* count now contains available bytes */ - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d count(%u/%d)", - fifo, skb->len, count); - if (count < skb->len) { - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo); - return (0); - } - - count = skb->len; /* get frame len */ - src = skb->data; /* source pointer */ - while (count--) - Write_hfc(cs, HFCSX_FIF_DWR, *src++); - - Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */ - udelay(1); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ - return (1); -} - -/***************************************************************/ -/* read_fifo reads data to an skb from the desired fifo */ -/* if no data is available or an error occurs NULL is returned */ -/* the skb is not released in any way. */ -/***************************************************************/ -static struct sk_buff * -read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) -{ int fifo_size, count, z1, z2; - u_char f_msk, f1, f2, *dst; - struct sk_buff *skb; - - if (!(fifo & 1)) return (NULL); /* no read fifo */ - fifo_select(cs, fifo); - if (fifo & 4) { - fifo_size = D_FIFO_SIZE; /* D-channel */ - f_msk = MAX_D_FRAMES; - if (trans_max) return (NULL); /* only hdlc */ - } - else { - fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ - f_msk = MAX_B_FRAMES; - } - - /* transparent mode */ - if (trans_max) { - z1 = Read_hfc(cs, HFCSX_FIF_Z1H); - z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); - z2 = Read_hfc(cs, HFCSX_FIF_Z2H); - z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); - /* now determine bytes in actual FIFO buffer */ - count = z1 - z2; - if (count <= 0) - count += fifo_size; /* count now contains buffered bytes */ - count++; - if (count > trans_max) - count = trans_max; /* limit length */ - skb = dev_alloc_skb(count); - if (skb) { - dst = skb_put(skb, count); - while (count--) - *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); - return skb; - } else - return NULL; /* no memory */ - } - - do { - f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; - f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; - - if (f1 == f2) return (NULL); /* no frame available */ - - z1 = Read_hfc(cs, HFCSX_FIF_Z1H); - z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); - z2 = Read_hfc(cs, HFCSX_FIF_Z2H); - z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)", - fifo, f1, f2, z1, z2); - /* now determine bytes in actual FIFO buffer */ - count = z1 - z2; - if (count <= 0) - count += fifo_size; /* count now contains buffered bytes */ - count++; - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_read_fifo %d count %u)", - fifo, count); - - if ((count > fifo_size) || (count < 4)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcsx_read_fifo %d packet inv. len %d ", fifo , count); - while (count) { - count--; /* empty fifo */ - Read_hfc(cs, HFCSX_FIF_DRD); - } - skb = NULL; - } else - if ((skb = dev_alloc_skb(count - 3))) { - count -= 3; - dst = skb_put(skb, count); - - while (count--) - *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); - - Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ - Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ - if (Read_hfc(cs, HFCSX_FIF_DRD)) { - dev_kfree_skb_irq(skb); - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); - skb = NULL; - } - } else { - printk(KERN_WARNING "HFC-SX: receive out of memory\n"); - return (NULL); - } - - Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */ - udelay(1); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ - udelay(1); - } while (!skb); /* retry in case of crc error */ - return (skb); -} - -/******************************************/ -/* free hardware resources used by driver */ -/******************************************/ -static void -release_io_hfcsx(struct IsdnCardState *cs) -{ - cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */ - msleep(30); /* Timeout 30ms */ - Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ - del_timer(&cs->hw.hfcsx.timer); - release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */ - kfree(cs->hw.hfcsx.extra); - cs->hw.hfcsx.extra = NULL; -} - -/**********************************************************/ -/* set_fifo_size determines the size of the RAM and FIFOs */ -/* returning 0 -> need to reset the chip again. */ -/**********************************************************/ -static int set_fifo_size(struct IsdnCardState *cs) -{ - - if (cs->hw.hfcsx.b_fifo_size) return (1); /* already determined */ - - if ((cs->hw.hfcsx.chip >> 4) == 9) { - cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K; - return (1); - } - - cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K; - cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */ - return (0); - -} - -/********************************************************************************/ -/* function called to reset the HFC SX chip. A complete software reset of chip */ -/* and fifos is done. */ -/********************************************************************************/ -static void -reset_hfcsx(struct IsdnCardState *cs) -{ - cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - - printk(KERN_INFO "HFC_SX: resetting card\n"); - while (1) { - Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm); /* Reset */ - mdelay(30); - Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ - mdelay(20); - if (Read_hfc(cs, HFCSX_STATUS) & 2) - printk(KERN_WARNING "HFC-SX init bit busy\n"); - cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */ - if (!set_fifo_size(cs)) continue; - break; - } - - cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */ - Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); - - Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ - cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE; - Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */ - cs->hw.hfcsx.bswapped = 0; /* no exchange */ - cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */ - cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER; - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); - - cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC | - HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - - /* Clear already pending ints */ - Read_hfc(cs, HFCSX_INT_S1); - - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */ - - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); - cs->hw.hfcsx.sctrl_r = 0; - Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); - - /* Init GCI/IOM2 in master mode */ - /* Slots 0 and 1 are set for B-chan 1 and 2 */ - /* D- and monitor/CI channel are not enabled */ - /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ - /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continuous 1s */ - /* The IOM slots are always enabled */ - cs->hw.hfcsx.conn = 0x36; /* set data flow directions */ - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ - Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ - Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ - Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ - - /* Finally enable IRQ output */ - cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE; - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - Read_hfc(cs, HFCSX_INT_S2); -} - -/***************************************************/ -/* Timer function called when kernel timer expires */ -/***************************************************/ -static void -hfcsx_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfcsx.timer); - cs->hw.hfcsx.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80); - add_timer(&cs->hw.hfcsx.timer); -*/ -} - -/************************************************/ -/* select a b-channel entry matching and active */ -/************************************************/ -static -struct BCState * -Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -/*******************************/ -/* D-channel receive procedure */ -/*******************************/ -static -int -receive_dmsg(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int count = 5; - - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_dmsg blocked"); - return (1); - } - - do { - skb = read_fifo(cs, HFCSX_SEL_D_RX, 0); - if (skb) { - skb_queue_tail(&cs->rq, skb); - schedule_event(cs, D_RCVBUFREADY); - } - } while (--count && skb); - - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return (1); -} - -/**********************************/ -/* B-channel main receive routine */ -/**********************************/ -static void -main_rec_hfcsx(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int count = 5; - struct sk_buff *skb; - -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_data %d blocked", bcs->channel); - return; - } - skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? - HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX, - (bcs->mode == L1_MODE_TRANS) ? - HFCSX_BTRANS_THRESHOLD : 0); - - if (skb) { - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && skb) - goto Begin; - return; -} - -/**************************/ -/* D-channel send routine */ -/**************************/ -static void -hfcsx_fill_dfifo(struct IsdnCardState *cs) -{ - if (!cs->tx_skb) - return; - if (cs->tx_skb->len <= 0) - return; - - if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - return; -} - -/**************************/ -/* B-channel send routine */ -/**************************/ -static void -hfcsx_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - if (write_fifo(cs, bcs->tx_skb, - ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? - HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX, - (bcs->mode == L1_MODE_TRANS) ? - HFCSX_BTRANS_THRESHOLD : 0)) { - - bcs->tx_cnt -= bcs->tx_skb->len; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } -} - -/**********************************************/ -/* D-channel l1 state call for leased NT-mode */ -/**********************************************/ -static void -dch_nt_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(cs, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (cs->debug) - debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); - break; - } -} - - - -/***********************/ -/* set/reset echo mode */ -/***********************/ -static int -hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) -{ - unsigned long flags; - int i = *(unsigned int *) ic->parm.num; - - if ((ic->arg == 98) && - (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) { - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */ - udelay(10); - cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT; - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */ - udelay(10); - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */ - udelay(10); - Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION); - cs->dc.hfcsx.ph_state = 1; - cs->hw.hfcsx.nt_mode = 1; - cs->hw.hfcsx.nt_timer = 0; - spin_unlock_irqrestore(&cs->lock, flags); - cs->stlist->l2.l2l1 = dch_nt_l2l1; - debugl1(cs, "NT mode activated"); - return (0); - } - if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) || - (cs->hw.hfcsx.nt_mode) || (ic->arg != 12)) - return (-EINVAL); - - if (i) { - cs->logecho = 1; - cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */ - cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC; - /* reset Channel !!!!! */ - } else { - cs->logecho = 0; - cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */ - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC; - } - cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */ - cs->hw.hfcsx.ctmt &= ~2; - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); - Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); -} /* hfcsx_auxcmd */ - -/*****************************/ -/* E-channel receive routine */ -/*****************************/ -static void -receive_emsg(struct IsdnCardState *cs) -{ - int count = 5; - u_char *ptr; - struct sk_buff *skb; - - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "echo_rec_data blocked"); - return; - } - do { - skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0); - if (skb) { - if (cs->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += QuickHex(ptr, skb->data, skb->len); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); - } - dev_kfree_skb_any(skb); - } - } while (--count && skb); - - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return; -} /* receive_emsg */ - - -/*********************/ -/* Interrupt handler */ -/*********************/ -static irqreturn_t -hfcsx_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char exval; - struct BCState *bcs; - int count = 15; - u_long flags; - u_char val, stat; - - if (!(cs->hw.hfcsx.int_m2 & 0x08)) - return IRQ_NONE; /* not initialised */ - - spin_lock_irqsave(&cs->lock, flags); - if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) { - val = Read_hfc(cs, HFCSX_INT_S1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val); - } else { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX irq %x %s", val, - test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? - "locked" : "unlocked"); - val &= cs->hw.hfcsx.int_m1; - if (val & 0x40) { /* state machine irq */ - exval = Read_hfc(cs, HFCSX_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state, - exval); - cs->dc.hfcsx.ph_state = exval; - schedule_event(cs, D_L1STATECHANGE); - val &= ~0x40; - } - if (val & 0x80) { /* timer irq */ - if (cs->hw.hfcsx.nt_mode) { - if ((--cs->hw.hfcsx.nt_timer) < 0) - schedule_event(cs, D_L1STATECHANGE); - } - val &= ~0x80; - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); - } - while (val) { - if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - cs->hw.hfcsx.int_s1 |= val; - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - if (cs->hw.hfcsx.int_s1 & 0x18) { - exval = val; - val = cs->hw.hfcsx.int_s1; - cs->hw.hfcsx.int_s1 = exval; - } - if (val & 0x08) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x08 IRQ"); - } else - main_rec_hfcsx(bcs); - } - if (val & 0x10) { - if (cs->logecho) - receive_emsg(cs); - else if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x10 IRQ"); - } else - main_rec_hfcsx(bcs); - } - if (val & 0x01) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x01 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x02) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x02 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x20) { /* receive dframe */ - receive_dmsg(cs); - } - if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcsx_fill_dfifo irq blocked"); - } - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcsx_fill_dfifo irq blocked"); - } - } else - schedule_event(cs, D_XMTBUFREADY); - } - afterXPR: - if (cs->hw.hfcsx.int_s1 && count--) { - val = cs->hw.hfcsx.int_s1; - cs->hw.hfcsx.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count); - } else - val = 0; - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -/********************************************************************/ -/* timer callback for D-chan busy resolution. Currently no function */ -/********************************************************************/ -static void -hfcsx_dbusy_timer(struct timer_list *t) -{ -} - -/*************************************/ -/* Layer 1 D-channel hardware access */ -/*************************************/ -static void -HFCSX_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcsx_fill_dfifo blocked"); - - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcsx_fill_dfifo blocked"); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */ - cs->hw.hfcsx.mst_m |= HFCSX_MASTER; - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER; - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.mst_m |= HFCSX_MASTER; - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - switch ((long) arg) { - case (1): - Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */ - Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */ - cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1; - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - break; - case (2): - Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */ - Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */ - cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08; - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - break; - default: - spin_unlock_irqrestore(&cs->lock, flags); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcsx_l1hw loop invalid %4lx", (unsigned long)arg); - return; - } - cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */ - Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr); - break; - } -} - -/***********************************************/ -/* called during init setting l1 stack pointer */ -/***********************************************/ -static void -setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = HFCSX_l1hw; -} - -/**************************************/ -/* send B-channel data if not blocked */ -/**************************************/ -static void -hfcsx_send_data(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "send_data %d blocked", bcs->channel); -} - -/***************************************************************/ -/* activate/deactivate hardware for selected channels and mode */ -/***************************************************************/ -static void -mode_hfcsx(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int fifo2; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - fifo2 = bc; - if (cs->chanlimit > 1) { - cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcsx.sctrl_e &= ~0x80; - } else { - if (bc) { - if (mode != L1_MODE_NULL) { - cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */ - cs->hw.hfcsx.sctrl_e |= 0x80; - } else { - cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcsx.sctrl_e &= ~0x80; - } - fifo2 = 0; - } else { - cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcsx.sctrl_e &= ~0x80; - } - } - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; - } else { - cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - } else { - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - } - break; - case (L1_MODE_TRANS): - if (bc) { - cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - cs->hw.hfcsx.ctmt |= 2; - cs->hw.hfcsx.conn &= ~0x18; - } else { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - cs->hw.hfcsx.ctmt |= 1; - cs->hw.hfcsx.conn &= ~0x03; - } - break; - case (L1_MODE_HDLC): - if (bc) { - cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - cs->hw.hfcsx.ctmt &= ~2; - cs->hw.hfcsx.conn &= ~0x18; - } else { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - cs->hw.hfcsx.ctmt &= ~1; - cs->hw.hfcsx.conn &= ~0x03; - } - break; - case (L1_MODE_EXTRN): - if (bc) { - cs->hw.hfcsx.conn |= 0x10; - cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - } else { - cs->hw.hfcsx.conn |= 0x02; - cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - } - break; - } - Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); - Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - if (mode != L1_MODE_EXTRN) { - reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX); - reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX); - } -} - -/******************************/ -/* Layer2 -> Layer 1 Transfer */ -/******************************/ -static void -hfcsx_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "%s: this shouldn't happen\n", - __func__); - } else { -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_hfcsx(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_hfcsx(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -/******************************************/ -/* deactivate B-channel access and queues */ -/******************************************/ -static void -close_hfcsx(struct BCState *bcs) -{ - mode_hfcsx(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -/*************************************/ -/* init B-channel queues and control */ -/*************************************/ -static int -open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -/*********************************/ -/* inits the stack for B-channel */ -/*********************************/ -static int -setstack_2b(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcsxstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfcsx_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -/***************************/ -/* handle L1 state changes */ -/***************************/ -static void -hfcsx_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - u_long flags; - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (!cs->hw.hfcsx.nt_mode) - switch (cs->dc.hfcsx.ph_state) { - case (0): - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (7): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - default: - break; - } else { - switch (cs->dc.hfcsx.ph_state) { - case (2): - spin_lock_irqsave(&cs->lock, flags); - if (cs->hw.hfcsx.nt_timer < 0) { - cs->hw.hfcsx.nt_timer = 0; - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - /* Clear already pending ints */ - Read_hfc(cs, HFCSX_INT_S1); - - Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE); - udelay(10); - Write_hfc(cs, HFCSX_STATES, 4); - cs->dc.hfcsx.ph_state = 4; - } else { - cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER; - cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125; - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); - cs->hw.hfcsx.nt_timer = NT_T1_COUNT; - Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */ - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (1): - case (3): - case (4): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.nt_timer = 0; - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - break; - } - } - } - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -} - - -/********************************/ -/* called for card init message */ -/********************************/ -static void inithfcsx(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_hfcsx; - cs->BC_Send_Data = &hfcsx_send_data; - cs->bcs[0].BC_SetStack = setstack_2b; - cs->bcs[1].BC_SetStack = setstack_2b; - cs->bcs[0].BC_Close = close_hfcsx; - cs->bcs[1].BC_Close = close_hfcsx; - mode_hfcsx(cs->bcs, 0, 0); - mode_hfcsx(cs->bcs + 1, 0, 1); -} - - - -/*******************************************/ -/* handle card messages from control layer */ -/*******************************************/ -static int -hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCSX: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_hfcsx(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_hfcsx(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithfcsx(cs); - spin_unlock_irqrestore(&cs->lock, flags); - msleep(80); /* Timeout 80ms */ - /* now switch timer interrupt off */ - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - /* reinit mode reg */ - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id hfc_ids[] = { - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), - (unsigned long) "Teles 16.3c2" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &hfc_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_hfcsx(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, hfcsx_revision); - printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp)); -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - cs->hw.hfcsx.base = card->para[1] & 0xfffe; - cs->irq = card->para[0]; - cs->hw.hfcsx.int_s1 = 0; - cs->dc.hfcsx.ph_state = 0; - cs->hw.hfcsx.fifo = 255; - if ((cs->typ == ISDN_CTYPE_HFC_SX) || - (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) { - if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) { - printk(KERN_WARNING - "HiSax: HFC-SX io-base %#lx already in use\n", - cs->hw.hfcsx.base); - return (0); - } - byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF); - byteout(cs->hw.hfcsx.base + 1, - ((cs->hw.hfcsx.base >> 8) & 3) | 0x54); - udelay(10); - cs->hw.hfcsx.chip = Read_hfc(cs, HFCSX_CHIP_ID); - switch (cs->hw.hfcsx.chip >> 4) { - case 1: - tmp[0] = '+'; - break; - case 9: - tmp[0] = 'P'; - break; - default: - printk(KERN_WARNING - "HFC-SX: invalid chip id 0x%x\n", - cs->hw.hfcsx.chip >> 4); - release_region(cs->hw.hfcsx.base, 2); - return (0); - } - if (!ccd_sp_irqtab[cs->irq & 0xF]) { - printk(KERN_WARNING - "HFC_SX: invalid irq %d specified\n", cs->irq & 0xF); - release_region(cs->hw.hfcsx.base, 2); - return (0); - } - if (!(cs->hw.hfcsx.extra = - kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) { - release_region(cs->hw.hfcsx.base, 2); - printk(KERN_WARNING "HFC-SX: unable to allocate memory\n"); - return (0); - } - printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n", - tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ); - cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */ - cs->hw.hfcsx.int_m1 = 0; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - } else - return (0); /* no valid card type */ - - timer_setup(&cs->dbusytimer, hfcsx_dbusy_timer, 0); - INIT_WORK(&cs->tqueue, hfcsx_bh); - cs->readisac = NULL; - cs->writeisac = NULL; - cs->readisacfifo = NULL; - cs->writeisacfifo = NULL; - cs->BC_Read_Reg = NULL; - cs->BC_Write_Reg = NULL; - cs->irq_func = &hfcsx_interrupt; - - cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */ - cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */ - timer_setup(&cs->hw.hfcsx.timer, hfcsx_Timer, 0); - - reset_hfcsx(cs); - cs->cardmsg = &hfcsx_card_msg; - cs->auxcmd = &hfcsx_auxcmd; - return (1); -} diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h deleted file mode 100644 index eee85dbb0883..000000000000 --- a/drivers/isdn/hisax/hfc_sx.h +++ /dev/null @@ -1,196 +0,0 @@ -/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $ - * - * specific defines for CCD's HFC 2BDS0 S+,SP chips - * - * Author Werner Cornelius - * based on existing driver for CCD HFC PCI cards - * Copyright by Werner Cornelius - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/*********************************************/ -/* thresholds for transparent B-channel mode */ -/* change mask and threshold simultaneously */ -/*********************************************/ -#define HFCSX_BTRANS_THRESHOLD 128 -#define HFCSX_BTRANS_THRESMASK 0x00 - -/* GCI/IOM bus monitor registers */ - -#define HFCSX_C_I 0x02 -#define HFCSX_TRxR 0x03 -#define HFCSX_MON1_D 0x0A -#define HFCSX_MON2_D 0x0B - - -/* GCI/IOM bus timeslot registers */ - -#define HFCSX_B1_SSL 0x20 -#define HFCSX_B2_SSL 0x21 -#define HFCSX_AUX1_SSL 0x22 -#define HFCSX_AUX2_SSL 0x23 -#define HFCSX_B1_RSL 0x24 -#define HFCSX_B2_RSL 0x25 -#define HFCSX_AUX1_RSL 0x26 -#define HFCSX_AUX2_RSL 0x27 - -/* GCI/IOM bus data registers */ - -#define HFCSX_B1_D 0x28 -#define HFCSX_B2_D 0x29 -#define HFCSX_AUX1_D 0x2A -#define HFCSX_AUX2_D 0x2B - -/* GCI/IOM bus configuration registers */ - -#define HFCSX_MST_EMOD 0x2D -#define HFCSX_MST_MODE 0x2E -#define HFCSX_CONNECT 0x2F - - -/* Interrupt and status registers */ - -#define HFCSX_TRM 0x12 -#define HFCSX_B_MODE 0x13 -#define HFCSX_CHIP_ID 0x16 -#define HFCSX_CIRM 0x18 -#define HFCSX_CTMT 0x19 -#define HFCSX_INT_M1 0x1A -#define HFCSX_INT_M2 0x1B -#define HFCSX_INT_S1 0x1E -#define HFCSX_INT_S2 0x1F -#define HFCSX_STATUS 0x1C - -/* S/T section registers */ - -#define HFCSX_STATES 0x30 -#define HFCSX_SCTRL 0x31 -#define HFCSX_SCTRL_E 0x32 -#define HFCSX_SCTRL_R 0x33 -#define HFCSX_SQ 0x34 -#define HFCSX_CLKDEL 0x37 -#define HFCSX_B1_REC 0x3C -#define HFCSX_B1_SEND 0x3C -#define HFCSX_B2_REC 0x3D -#define HFCSX_B2_SEND 0x3D -#define HFCSX_D_REC 0x3E -#define HFCSX_D_SEND 0x3E -#define HFCSX_E_REC 0x3F - -/****************/ -/* FIFO section */ -/****************/ -#define HFCSX_FIF_SEL 0x10 -#define HFCSX_FIF_Z1L 0x80 -#define HFCSX_FIF_Z1H 0x84 -#define HFCSX_FIF_Z2L 0x88 -#define HFCSX_FIF_Z2H 0x8C -#define HFCSX_FIF_INCF1 0xA8 -#define HFCSX_FIF_DWR 0xAC -#define HFCSX_FIF_F1 0xB0 -#define HFCSX_FIF_F2 0xB4 -#define HFCSX_FIF_INCF2 0xB8 -#define HFCSX_FIF_DRD 0xBC - -/* bits in status register (READ) */ -#define HFCSX_SX_PROC 0x02 -#define HFCSX_NBUSY 0x04 -#define HFCSX_TIMER_ELAP 0x10 -#define HFCSX_STATINT 0x20 -#define HFCSX_FRAMEINT 0x40 -#define HFCSX_ANYINT 0x80 - -/* bits in CTMT (Write) */ -#define HFCSX_CLTIMER 0x80 -#define HFCSX_TIM3_125 0x04 -#define HFCSX_TIM25 0x10 -#define HFCSX_TIM50 0x14 -#define HFCSX_TIM400 0x18 -#define HFCSX_TIM800 0x1C -#define HFCSX_AUTO_TIMER 0x20 -#define HFCSX_TRANSB2 0x02 -#define HFCSX_TRANSB1 0x01 - -/* bits in CIRM (Write) */ -#define HFCSX_IRQ_SELMSK 0x07 -#define HFCSX_IRQ_SELDIS 0x00 -#define HFCSX_RESET 0x08 -#define HFCSX_FIFO_RESET 0x80 - - -/* bits in INT_M1 and INT_S1 */ -#define HFCSX_INTS_B1TRANS 0x01 -#define HFCSX_INTS_B2TRANS 0x02 -#define HFCSX_INTS_DTRANS 0x04 -#define HFCSX_INTS_B1REC 0x08 -#define HFCSX_INTS_B2REC 0x10 -#define HFCSX_INTS_DREC 0x20 -#define HFCSX_INTS_L1STATE 0x40 -#define HFCSX_INTS_TIMER 0x80 - -/* bits in INT_M2 */ -#define HFCSX_PROC_TRANS 0x01 -#define HFCSX_GCI_I_CHG 0x02 -#define HFCSX_GCI_MON_REC 0x04 -#define HFCSX_IRQ_ENABLE 0x08 - -/* bits in STATES */ -#define HFCSX_STATE_MSK 0x0F -#define HFCSX_LOAD_STATE 0x10 -#define HFCSX_ACTIVATE 0x20 -#define HFCSX_DO_ACTION 0x40 -#define HFCSX_NT_G2_G3 0x80 - -/* bits in HFCD_MST_MODE */ -#define HFCSX_MASTER 0x01 -#define HFCSX_SLAVE 0x00 -/* remaining bits are for codecs control */ - -/* bits in HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_MODE_TE 0x00 -#define SCTRL_MODE_NT 0x04 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* bits in SCTRL_E */ -#define HFCSX_AUTO_AWAKE 0x01 -#define HFCSX_DBIT_1 0x04 -#define HFCSX_IGNORE_COL 0x08 -#define HFCSX_CHG_B1_B2 0x80 - -/**********************************/ -/* definitions for FIFO selection */ -/**********************************/ -#define HFCSX_SEL_D_RX 5 -#define HFCSX_SEL_D_TX 4 -#define HFCSX_SEL_B1_RX 1 -#define HFCSX_SEL_B1_TX 0 -#define HFCSX_SEL_B2_RX 3 -#define HFCSX_SEL_B2_TX 2 - -#define MAX_D_FRAMES 15 -#define MAX_B_FRAMES 31 -#define B_SUB_VAL_32K 0x0200 -#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K) -#define B_SUB_VAL_8K 0x1A00 -#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K) -#define D_FIFO_SIZE 512 -#define D_FREG_MASK 0xF - -/************************************************************/ -/* structure holding additional dynamic data -> send marker */ -/************************************************************/ -struct hfcsx_extra { - unsigned short marker[2 * (MAX_B_FRAMES + 1) + (MAX_D_FRAMES + 1)]; -}; - -extern void main_irq_hfcsx(struct BCState *bcs); -extern void releasehfcsx(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c deleted file mode 100644 index 1d4cd01d4685..000000000000 --- a/drivers/isdn/hisax/hfc_usb.c +++ /dev/null @@ -1,1608 +0,0 @@ -/* - * hfc_usb.c - * - * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $ - * - * modular HiSax ISDN driver for Colognechip HFC-S USB chip - * - * Authors : Peter Sprenger (sprenger@moving-bytes.de) - * Martin Bachem (m.bachem@gmx.de, info@colognechip.com) - * - * based on the first hfc_usb driver of - * Werner Cornelius (werner@isdn-development.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * See Version Histroy at the bottom of this file - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hisax.h" -#include "hisax_if.h" -#include "hfc_usb.h" - -static const char *hfcusb_revision = - "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ "; - -/* Hisax debug support - * debug flags defined in hfc_usb.h as HFCUSB_DBG_[*] - */ -#define __debug_variable hfc_debug -#include "hisax_debug.h" -static u_int debug; -module_param(debug, uint, 0); -static int hfc_debug; - - -/* private vendor specific data */ -typedef struct { - __u8 led_scheme; // led display scheme - signed short led_bits[8]; // array of 8 possible LED bitmask settings - char *vend_name; // device name -} hfcsusb_vdata; - -/* VID/PID device list */ -static const struct usb_device_id hfcusb_idtab[] = { - { - USB_DEVICE(0x0959, 0x2bd0), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_OFF, {4, 0, 2, 1}, - "ISDN USB TA (Cologne Chip HFC-S USB based)"}), - }, - { - USB_DEVICE(0x0675, 0x1688), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {1, 2, 0, 0}, - "DrayTek miniVigor 128 USB ISDN TA"}), - }, - { - USB_DEVICE(0x07b0, 0x0007), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Billion tiny USB ISDN TA 128"}), - }, - { - USB_DEVICE(0x0742, 0x2008), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "Stollmann USB TA"}), - }, - { - USB_DEVICE(0x0742, 0x2009), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "Aceex USB ISDN TA"}), - }, - { - USB_DEVICE(0x0742, 0x200A), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "OEM USB ISDN TA"}), - }, - { - USB_DEVICE(0x08e3, 0x0301), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {2, 0, 1, 4}, - "Olitec USB RNIS"}), - }, - { - USB_DEVICE(0x07fa, 0x0846), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Bewan Modem RNIS USB"}), - }, - { - USB_DEVICE(0x07fa, 0x0847), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Djinn Numeris USB"}), - }, - { - USB_DEVICE(0x07b0, 0x0006), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Twister ISDN TA"}), - }, - { - USB_DEVICE(0x071d, 0x1005), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x02, 0, 0x01, 0x04}, - "Eicon DIVA USB 4.0"}), - }, - { } -}; - -/* structure defining input+output fifos (interrupt/bulk mode) */ -struct usb_fifo; /* forward definition */ -typedef struct iso_urb_struct { - struct urb *purb; - __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */ - struct usb_fifo *owner_fifo; /* pointer to owner fifo */ -} iso_urb_struct; - -struct hfcusb_data; /* forward definition */ - -typedef struct usb_fifo { - int fifonum; /* fifo index attached to this structure */ - int active; /* fifo is currently active */ - struct hfcusb_data *hfc; /* pointer to main structure */ - int pipe; /* address of endpoint */ - __u8 usb_packet_maxlen; /* maximum length for usb transfer */ - unsigned int max_size; /* maximum size of receive/send packet */ - __u8 intervall; /* interrupt interval */ - struct sk_buff *skbuff; /* actual used buffer */ - struct urb *urb; /* transfer structure for usb routines */ - __u8 buffer[128]; /* buffer incoming/outgoing data */ - int bit_line; /* how much bits are in the fifo? */ - - volatile __u8 usb_transfer_mode; /* switched between ISO and INT */ - iso_urb_struct iso[2]; /* need two urbs to have one always for pending */ - struct hisax_if *hif; /* hisax interface */ - int delete_flg; /* only delete skbuff once */ - int last_urblen; /* remember length of last packet */ -} usb_fifo; - -/* structure holding all data for one device */ -typedef struct hfcusb_data { - /* HiSax Interface for loadable Layer1 drivers */ - struct hisax_d_if d_if; /* see hisax_if.h */ - struct hisax_b_if b_if[2]; /* see hisax_if.h */ - int protocol; - - struct usb_device *dev; /* our device */ - int if_used; /* used interface number */ - int alt_used; /* used alternate config */ - int ctrl_paksize; /* control pipe packet size */ - int ctrl_in_pipe, /* handles for control pipe */ - ctrl_out_pipe; - int cfg_used; /* configuration index used */ - int vend_idx; /* vendor found */ - int b_mode[2]; /* B-channel mode */ - int l1_activated; /* layer 1 activated */ - int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */ - int packet_size, iso_packet_size; - - /* control pipe background handling */ - ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */ - volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */ - struct urb *ctrl_urb; /* transfer structure for control channel */ - - struct usb_ctrlrequest ctrl_write; /* buffer for control write request */ - struct usb_ctrlrequest ctrl_read; /* same for read request */ - - __u8 old_led_state, led_state; - - volatile __u8 threshold_mask; /* threshold actually reported */ - volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */ - - usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */ - - volatile __u8 l1_state; /* actual l1 state */ - struct timer_list t3_timer; /* timer 3 for activation/deactivation */ - struct timer_list t4_timer; /* timer 4 for activation/deactivation */ -} hfcusb_data; - - -static void collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, - int finish); - -static inline const char * -symbolic(struct hfcusb_symbolic_list list[], const int num) -{ - int i; - for (i = 0; list[i].name != NULL; i++) - if (list[i].num == num) - return (list[i].name); - return ""; -} - -static void -ctrl_start_transfer(hfcusb_data *hfc) -{ - if (hfc->ctrl_cnt) { - hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe; - hfc->ctrl_urb->setup_packet = (u_char *)&hfc->ctrl_write; - hfc->ctrl_urb->transfer_buffer = NULL; - hfc->ctrl_urb->transfer_buffer_length = 0; - hfc->ctrl_write.wIndex = - cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg); - hfc->ctrl_write.wValue = - cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val); - - usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */ - } -} /* ctrl_start_transfer */ - -static int -queue_control_request(hfcusb_data *hfc, __u8 reg, __u8 val, int action) -{ - ctrl_buft *buf; - - if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE) - return (1); /* no space left */ - buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */ - buf->hfc_reg = reg; - buf->reg_val = val; - buf->action = action; - if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE) - hfc->ctrl_in_idx = 0; /* pointer wrap */ - if (++hfc->ctrl_cnt == 1) - ctrl_start_transfer(hfc); - return (0); -} - -static void -ctrl_complete(struct urb *urb) -{ - hfcusb_data *hfc = (hfcusb_data *) urb->context; - - urb->dev = hfc->dev; - if (hfc->ctrl_cnt) { - hfc->ctrl_cnt--; /* decrement actual count */ - if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) - hfc->ctrl_out_idx = 0; /* pointer wrap */ - - ctrl_start_transfer(hfc); /* start next transfer */ - } -} - -/* write led data to auxport & invert if necessary */ -static void -write_led(hfcusb_data *hfc, __u8 led_state) -{ - if (led_state != hfc->old_led_state) { - hfc->old_led_state = led_state; - queue_control_request(hfc, HFCUSB_P_DATA, led_state, 1); - } -} - -static void -set_led_bit(hfcusb_data *hfc, signed short led_bits, int on) -{ - if (on) { - if (led_bits < 0) - hfc->led_state &= ~abs(led_bits); - else - hfc->led_state |= led_bits; - } else { - if (led_bits < 0) - hfc->led_state |= abs(led_bits); - else - hfc->led_state &= ~led_bits; - } -} - -/* handle LED requests */ -static void -handle_led(hfcusb_data *hfc, int event) -{ - hfcsusb_vdata *driver_info = - (hfcsusb_vdata *) hfcusb_idtab[hfc->vend_idx].driver_info; - - /* if no scheme -> no LED action */ - if (driver_info->led_scheme == LED_OFF) - return; - - switch (event) { - case LED_POWER_ON: - set_led_bit(hfc, driver_info->led_bits[0], 1); - set_led_bit(hfc, driver_info->led_bits[1], 0); - set_led_bit(hfc, driver_info->led_bits[2], 0); - set_led_bit(hfc, driver_info->led_bits[3], 0); - break; - case LED_POWER_OFF: - set_led_bit(hfc, driver_info->led_bits[0], 0); - set_led_bit(hfc, driver_info->led_bits[1], 0); - set_led_bit(hfc, driver_info->led_bits[2], 0); - set_led_bit(hfc, driver_info->led_bits[3], 0); - break; - case LED_S0_ON: - set_led_bit(hfc, driver_info->led_bits[1], 1); - break; - case LED_S0_OFF: - set_led_bit(hfc, driver_info->led_bits[1], 0); - break; - case LED_B1_ON: - set_led_bit(hfc, driver_info->led_bits[2], 1); - break; - case LED_B1_OFF: - set_led_bit(hfc, driver_info->led_bits[2], 0); - break; - case LED_B2_ON: - set_led_bit(hfc, driver_info->led_bits[3], 1); - break; - case LED_B2_OFF: - set_led_bit(hfc, driver_info->led_bits[3], 0); - break; - } - write_led(hfc, hfc->led_state); -} - -/* ISDN l1 timer T3 expires */ -static void -l1_timer_expire_t3(struct timer_list *t) -{ - hfcusb_data *hfc = from_timer(hfc, t, t3_timer); - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION, - NULL); - - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)"); - - hfc->l1_activated = 0; - handle_led(hfc, LED_S0_OFF); - /* deactivate : */ - queue_control_request(hfc, HFCUSB_STATES, 0x10, 1); - queue_control_request(hfc, HFCUSB_STATES, 3, 1); -} - -/* ISDN l1 timer T4 expires */ -static void -l1_timer_expire_t4(struct timer_list *t) -{ - hfcusb_data *hfc = from_timer(hfc, t, t4_timer); - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION, - NULL); - - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)"); - - hfc->l1_activated = 0; - handle_led(hfc, LED_S0_OFF); -} - -/* S0 state changed */ -static void -s0_state_handler(hfcusb_data *hfc, __u8 state) -{ - __u8 old_state; - - old_state = hfc->l1_state; - if (state == old_state || state < 1 || state > 8) - return; - - DBG(HFCUSB_DBG_STATES, "HFC-S USB: S0 statechange(%d -> %d)", - old_state, state); - - if (state < 4 || state == 7 || state == 8) { - if (timer_pending(&hfc->t3_timer)) - del_timer(&hfc->t3_timer); - DBG(HFCUSB_DBG_STATES, "HFC-S USB: T3 deactivated"); - } - if (state >= 7) { - if (timer_pending(&hfc->t4_timer)) - del_timer(&hfc->t4_timer); - DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 deactivated"); - } - - if (state == 7 && !hfc->l1_activated) { - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, - PH_ACTIVATE | INDICATION, NULL); - DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent"); - hfc->l1_activated = 1; - handle_led(hfc, LED_S0_ON); - } else if (state <= 3 /* && activated */) { - if (old_state == 7 || old_state == 8) { - DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 activated"); - if (!timer_pending(&hfc->t4_timer)) { - hfc->t4_timer.expires = - jiffies + (HFC_TIMER_T4 * HZ) / 1000; - add_timer(&hfc->t4_timer); - } - } else { - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, - PH_DEACTIVATE | INDICATION, - NULL); - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent"); - hfc->l1_activated = 0; - handle_led(hfc, LED_S0_OFF); - } - } - hfc->l1_state = state; -} - -static void -fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, - void *buf, int num_packets, int packet_size, int interval, - usb_complete_t complete, void *context) -{ - int k; - - usb_fill_int_urb(urb, dev, pipe, buf, packet_size * num_packets, - complete, context, interval); - - urb->number_of_packets = num_packets; - urb->transfer_flags = URB_ISO_ASAP; - urb->actual_length = 0; - for (k = 0; k < num_packets; k++) { - urb->iso_frame_desc[k].offset = packet_size * k; - urb->iso_frame_desc[k].length = packet_size; - urb->iso_frame_desc[k].actual_length = 0; - } -} - -/* allocs urbs and start isoc transfer with two pending urbs to avoid - * gaps in the transfer chain - */ -static int -start_isoc_chain(usb_fifo *fifo, int num_packets_per_urb, - usb_complete_t complete, int packet_size) -{ - int i, k, errcode; - - DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting ISO-URBs for fifo:%d\n", - fifo->fifonum); - - /* allocate Memory for Iso out Urbs */ - for (i = 0; i < 2; i++) { - if (!(fifo->iso[i].purb)) { - fifo->iso[i].purb = - usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); - if (!(fifo->iso[i].purb)) { - printk(KERN_INFO - "alloc urb for fifo %i failed!!!", - fifo->fifonum); - } - fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; - - /* Init the first iso */ - if (ISO_BUFFER_SIZE >= - (fifo->usb_packet_maxlen * - num_packets_per_urb)) { - fill_isoc_urb(fifo->iso[i].purb, - fifo->hfc->dev, fifo->pipe, - fifo->iso[i].buffer, - num_packets_per_urb, - fifo->usb_packet_maxlen, - fifo->intervall, complete, - &fifo->iso[i]); - memset(fifo->iso[i].buffer, 0, - sizeof(fifo->iso[i].buffer)); - /* defining packet delimeters in fifo->buffer */ - for (k = 0; k < num_packets_per_urb; k++) { - fifo->iso[i].purb-> - iso_frame_desc[k].offset = - k * packet_size; - fifo->iso[i].purb-> - iso_frame_desc[k].length = - packet_size; - } - } else { - printk(KERN_INFO - "HFC-S USB: ISO Buffer size to small!\n"); - } - } - fifo->bit_line = BITLINE_INF; - - errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL); - fifo->active = (errcode >= 0) ? 1 : 0; - if (errcode < 0) - printk(KERN_INFO "HFC-S USB: usb_submit_urb URB nr:%d, error(%i): '%s'\n", - i, errcode, symbolic(urb_errlist, errcode)); - } - return (fifo->active); -} - -/* stops running iso chain and frees their pending urbs */ -static void -stop_isoc_chain(usb_fifo *fifo) -{ - int i; - - for (i = 0; i < 2; i++) { - if (fifo->iso[i].purb) { - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: Stopping iso chain for fifo %i.%i", - fifo->fifonum, i); - usb_kill_urb(fifo->iso[i].purb); - usb_free_urb(fifo->iso[i].purb); - fifo->iso[i].purb = NULL; - } - } - - usb_kill_urb(fifo->urb); - usb_free_urb(fifo->urb); - fifo->urb = NULL; - fifo->active = 0; -} - -/* defines how much ISO packets are handled in one URB */ -static int iso_packets[8] = -{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, - ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D -}; - -static void -tx_iso_complete(struct urb *urb) -{ - iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; - usb_fifo *fifo = context_iso_urb->owner_fifo; - hfcusb_data *hfc = fifo->hfc; - int k, tx_offset, num_isoc_packets, sink, len, current_len, - errcode; - int frame_complete, transp_mode, fifon, status; - __u8 threshbit; - - fifon = fifo->fifonum; - status = urb->status; - - tx_offset = 0; - - /* ISO transfer only partially completed, - look at individual frame status for details */ - if (status == -EXDEV) { - DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV" - ", urb->status %d, fifonum %d\n", - status, fifon); - - for (k = 0; k < iso_packets[fifon]; ++k) { - errcode = urb->iso_frame_desc[k].status; - if (errcode) - DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete " - "packet %i, status: %i\n", - k, errcode); - } - - // clear status, so go on with ISO transfers - status = 0; - } - - if (fifo->active && !status) { - transp_mode = 0; - if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) - transp_mode = 1; - - /* is FifoFull-threshold set for our channel? */ - threshbit = (hfc->threshold_mask & (1 << fifon)); - num_isoc_packets = iso_packets[fifon]; - - /* predict dataflow to avoid fifo overflow */ - if (fifon >= HFCUSB_D_TX) { - sink = (threshbit) ? SINK_DMIN : SINK_DMAX; - } else { - sink = (threshbit) ? SINK_MIN : SINK_MAX; - } - fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe, - context_iso_urb->buffer, num_isoc_packets, - fifo->usb_packet_maxlen, fifo->intervall, - tx_iso_complete, urb->context); - memset(context_iso_urb->buffer, 0, - sizeof(context_iso_urb->buffer)); - frame_complete = 0; - - /* Generate next ISO Packets */ - for (k = 0; k < num_isoc_packets; ++k) { - if (fifo->skbuff) { - len = fifo->skbuff->len; - /* we lower data margin every msec */ - fifo->bit_line -= sink; - current_len = (0 - fifo->bit_line) / 8; - /* maximum 15 byte for every ISO packet makes our life easier */ - if (current_len > 14) - current_len = 14; - current_len = - (len <= - current_len) ? len : current_len; - /* how much bit do we put on the line? */ - fifo->bit_line += current_len * 8; - - context_iso_urb->buffer[tx_offset] = 0; - if (current_len == len) { - if (!transp_mode) { - /* here frame completion */ - context_iso_urb-> - buffer[tx_offset] = 1; - /* add 2 byte flags and 16bit CRC at end of ISDN frame */ - fifo->bit_line += 32; - } - frame_complete = 1; - } - - memcpy(context_iso_urb->buffer + - tx_offset + 1, fifo->skbuff->data, - current_len); - skb_pull(fifo->skbuff, current_len); - - /* define packet delimeters within the URB buffer */ - urb->iso_frame_desc[k].offset = tx_offset; - urb->iso_frame_desc[k].length = - current_len + 1; - - tx_offset += (current_len + 1); - } else { - urb->iso_frame_desc[k].offset = - tx_offset++; - - urb->iso_frame_desc[k].length = 1; - fifo->bit_line -= sink; /* we lower data margin every msec */ - - if (fifo->bit_line < BITLINE_INF) { - fifo->bit_line = BITLINE_INF; - } - } - - if (frame_complete) { - fifo->delete_flg = 1; - fifo->hif->l1l2(fifo->hif, - PH_DATA | CONFIRM, - (void *) (unsigned long) fifo->skbuff-> - truesize); - if (fifo->skbuff && fifo->delete_flg) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - fifo->delete_flg = 0; - } - frame_complete = 0; - } - } - errcode = usb_submit_urb(urb, GFP_ATOMIC); - if (errcode < 0) { - printk(KERN_INFO - "HFC-S USB: error submitting ISO URB: %d\n", - errcode); - } - } else { - if (status && !hfc->disc_flag) { - printk(KERN_INFO - "HFC-S USB: tx_iso_complete: error(%i): '%s', fifonum=%d\n", - status, symbolic(urb_errlist, status), fifon); - } - } -} - -static void -rx_iso_complete(struct urb *urb) -{ - iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; - usb_fifo *fifo = context_iso_urb->owner_fifo; - hfcusb_data *hfc = fifo->hfc; - int k, len, errcode, offset, num_isoc_packets, fifon, maxlen, - status; - unsigned int iso_status; - __u8 *buf; - static __u8 eof[8]; - - fifon = fifo->fifonum; - status = urb->status; - - if (urb->status == -EOVERFLOW) { - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon); - status = 0; - } - - /* ISO transfer only partially completed, - look at individual frame status for details */ - if (status == -EXDEV) { - DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV " - "urb->status %d, fifonum %d\n", - status, fifon); - status = 0; - } - - if (fifo->active && !status) { - num_isoc_packets = iso_packets[fifon]; - maxlen = fifo->usb_packet_maxlen; - for (k = 0; k < num_isoc_packets; ++k) { - len = urb->iso_frame_desc[k].actual_length; - offset = urb->iso_frame_desc[k].offset; - buf = context_iso_urb->buffer + offset; - iso_status = urb->iso_frame_desc[k].status; - - if (iso_status && !hfc->disc_flag) - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-S USB: rx_iso_complete " - "ISO packet %i, status: %i\n", - k, iso_status); - - if (fifon == HFCUSB_D_RX) { - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-S USB: ISO-D-RX lst_urblen:%2d " - "act_urblen:%2d max-urblen:%2d EOF:0x%0x", - fifo->last_urblen, len, maxlen, - eof[5]); - - DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len); - } - - if (fifo->last_urblen != maxlen) { - /* the threshold mask is in the 2nd status byte */ - hfc->threshold_mask = buf[1]; - /* care for L1 state only for D-Channel - to avoid overlapped iso completions */ - if (fifon == HFCUSB_D_RX) { - /* the S0 state is in the upper half - of the 1st status byte */ - s0_state_handler(hfc, buf[0] >> 4); - } - eof[fifon] = buf[0] & 1; - if (len > 2) - collect_rx_frame(fifo, buf + 2, - len - 2, - (len < maxlen) ? - eof[fifon] : 0); - } else { - collect_rx_frame(fifo, buf, len, - (len < - maxlen) ? eof[fifon] : - 0); - } - fifo->last_urblen = len; - } - - fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe, - context_iso_urb->buffer, num_isoc_packets, - fifo->usb_packet_maxlen, fifo->intervall, - rx_iso_complete, urb->context); - errcode = usb_submit_urb(urb, GFP_ATOMIC); - if (errcode < 0) { - printk(KERN_ERR - "HFC-S USB: error submitting ISO URB: %d\n", - errcode); - } - } else { - if (status && !hfc->disc_flag) { - printk(KERN_ERR - "HFC-S USB: rx_iso_complete : " - "urb->status %d, fifonum %d\n", - status, fifon); - } - } -} - -/* collect rx data from INT- and ISO-URBs */ -static void -collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, int finish) -{ - hfcusb_data *hfc = fifo->hfc; - int transp_mode, fifon; - - fifon = fifo->fifonum; - transp_mode = 0; - if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) - transp_mode = 1; - - if (!fifo->skbuff) { - fifo->skbuff = dev_alloc_skb(fifo->max_size + 3); - if (!fifo->skbuff) { - printk(KERN_ERR - "HFC-S USB: cannot allocate buffer for fifo(%d)\n", - fifon); - return; - } - } - if (len) { - if (fifo->skbuff->len + len < fifo->max_size) { - skb_put_data(fifo->skbuff, data, len); - } else { - DBG(HFCUSB_DBG_FIFO_ERR, - "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)", - fifo->max_size, fifon); - DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff); - skb_trim(fifo->skbuff, 0); - } - } - if (transp_mode && fifo->skbuff->len >= 128) { - fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION, - fifo->skbuff); - fifo->skbuff = NULL; - return; - } - /* we have a complete hdlc packet */ - if (finish) { - if (fifo->skbuff->len > 3 && - !fifo->skbuff->data[fifo->skbuff->len - 1]) { - - if (fifon == HFCUSB_D_RX) { - DBG(HFCUSB_DBG_DCHANNEL, - "HFC-S USB: D-RX len(%d)", fifo->skbuff->len); - DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff); - } - - /* remove CRC & status */ - skb_trim(fifo->skbuff, fifo->skbuff->len - 3); - if (fifon == HFCUSB_PCM_RX) { - fifo->hif->l1l2(fifo->hif, - PH_DATA_E | INDICATION, - fifo->skbuff); - } else - fifo->hif->l1l2(fifo->hif, - PH_DATA | INDICATION, - fifo->skbuff); - fifo->skbuff = NULL; /* buffer was freed from upper layer */ - } else { - DBG(HFCUSB_DBG_FIFO_ERR, - "HFC-S USB: ERROR frame len(%d) fifo(%d)", - fifo->skbuff->len, fifon); - DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff); - skb_trim(fifo->skbuff, 0); - } - } -} - -static void -rx_int_complete(struct urb *urb) -{ - int len; - int status; - __u8 *buf, maxlen, fifon; - usb_fifo *fifo = (usb_fifo *) urb->context; - hfcusb_data *hfc = fifo->hfc; - static __u8 eof[8]; - - urb->dev = hfc->dev; /* security init */ - - fifon = fifo->fifonum; - if ((!fifo->active) || (urb->status)) { - DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)", - fifon, urb->status); - - fifo->urb->interval = 0; /* cancel automatic rescheduling */ - if (fifo->skbuff) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - } - return; - } - len = urb->actual_length; - buf = fifo->buffer; - maxlen = fifo->usb_packet_maxlen; - - if (fifon == HFCUSB_D_RX) { - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-S USB: INT-D-RX lst_urblen:%2d " - "act_urblen:%2d max-urblen:%2d EOF:0x%0x", - fifo->last_urblen, len, maxlen, - eof[5]); - DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len); - } - - if (fifo->last_urblen != fifo->usb_packet_maxlen) { - /* the threshold mask is in the 2nd status byte */ - hfc->threshold_mask = buf[1]; - /* the S0 state is in the upper half of the 1st status byte */ - s0_state_handler(hfc, buf[0] >> 4); - eof[fifon] = buf[0] & 1; - /* if we have more than the 2 status bytes -> collect data */ - if (len > 2) - collect_rx_frame(fifo, buf + 2, - urb->actual_length - 2, - (len < maxlen) ? eof[fifon] : 0); - } else { - collect_rx_frame(fifo, buf, urb->actual_length, - (len < maxlen) ? eof[fifon] : 0); - } - fifo->last_urblen = urb->actual_length; - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - printk(KERN_INFO - "HFC-S USB: %s error resubmitting URB fifo(%d)\n", - __func__, fifon); - } -} - -/* start initial INT-URB for certain fifo */ -static void -start_int_fifo(usb_fifo *fifo) -{ - int errcode; - - DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n", - fifo->fifonum); - - if (!fifo->urb) { - fifo->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!fifo->urb) - return; - } - usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, - fifo->buffer, fifo->usb_packet_maxlen, - rx_int_complete, fifo, fifo->intervall); - fifo->active = 1; /* must be marked active */ - errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); - if (errcode) { - printk(KERN_ERR "HFC-S USB: submit URB error(%s): status:%i\n", - __func__, errcode); - fifo->active = 0; - fifo->skbuff = NULL; - } -} - -static void -setup_bchannel(hfcusb_data *hfc, int channel, int mode) -{ - __u8 val, idx_table[2] = { 0, 2 }; - - if (hfc->disc_flag) { - return; - } - DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d", - channel, mode); - hfc->b_mode[channel] = mode; - - /* setup CON_HDLC */ - val = 0; - if (mode != L1_MODE_NULL) - val = 8; /* enable fifo? */ - if (mode == L1_MODE_TRANS) - val |= 2; /* set transparent bit */ - - /* set FIFO to transmit register */ - queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1); - queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1); - /* reset fifo */ - queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1); - /* set FIFO to receive register */ - queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1); - queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1); - /* reset fifo */ - queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1); - - val = 0x40; - if (hfc->b_mode[0]) - val |= 1; - if (hfc->b_mode[1]) - val |= 2; - queue_control_request(hfc, HFCUSB_SCTRL, val, 1); - - val = 0; - if (hfc->b_mode[0]) - val |= 1; - if (hfc->b_mode[1]) - val |= 2; - queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1); - - if (mode == L1_MODE_NULL) { - if (channel) - handle_led(hfc, LED_B2_OFF); - else - handle_led(hfc, LED_B1_OFF); - } else { - if (channel) - handle_led(hfc, LED_B2_ON); - else - handle_led(hfc, LED_B1_ON); - } -} - -static void -hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg) -{ - usb_fifo *fifo = my_hisax_if->priv; - hfcusb_data *hfc = fifo->hfc; - - switch (pr) { - case PH_ACTIVATE | REQUEST: - if (fifo->fifonum == HFCUSB_D_TX) { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST"); - - if (hfc->l1_state != 3 - && hfc->l1_state != 7) { - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, - PH_DEACTIVATE | - INDICATION, - NULL); - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)"); - } else { - if (hfc->l1_state == 7) { /* l1 already active */ - hfc->d_if.ifc.l1l2(&hfc-> - d_if. - ifc, - PH_ACTIVATE - | - INDICATION, - NULL); - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)"); - } else { - /* force sending sending INFO1 */ - queue_control_request(hfc, - HFCUSB_STATES, - 0x14, - 1); - mdelay(1); - /* start l1 activation */ - queue_control_request(hfc, - HFCUSB_STATES, - 0x04, - 1); - if (!timer_pending - (&hfc->t3_timer)) { - hfc->t3_timer. - expires = - jiffies + - (HFC_TIMER_T3 * - HZ) / 1000; - add_timer(&hfc-> - t3_timer); - } - } - } - } else { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST"); - setup_bchannel(hfc, - (fifo->fifonum == - HFCUSB_B1_TX) ? 0 : 1, - (long) arg); - fifo->hif->l1l2(fifo->hif, - PH_ACTIVATE | INDICATION, - NULL); - } - break; - case PH_DEACTIVATE | REQUEST: - if (fifo->fifonum == HFCUSB_D_TX) { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST"); - } else { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST"); - setup_bchannel(hfc, - (fifo->fifonum == - HFCUSB_B1_TX) ? 0 : 1, - (int) L1_MODE_NULL); - fifo->hif->l1l2(fifo->hif, - PH_DEACTIVATE | INDICATION, - NULL); - } - break; - case PH_DATA | REQUEST: - if (fifo->skbuff && fifo->delete_flg) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - fifo->delete_flg = 0; - } - fifo->skbuff = arg; /* we have a new buffer */ - break; - default: - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1: unknown state : %#x", pr); - break; - } -} - -/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */ -static int -hfc_usb_init(hfcusb_data *hfc) -{ - usb_fifo *fifo; - int i; - u_char b; - struct hisax_b_if *p_b_if[2]; - - /* check the chip id */ - if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) { - printk(KERN_INFO "HFC-USB: cannot read chip id\n"); - return (1); - } - if (b != HFCUSB_CHIPID) { - printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b); - return (1); - } - - /* first set the needed config, interface and alternate */ - usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); - - /* do Chip reset */ - write_usb(hfc, HFCUSB_CIRM, 8); - /* aux = output, reset off */ - write_usb(hfc, HFCUSB_CIRM, 0x10); - - /* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */ - write_usb(hfc, HFCUSB_USB_SIZE, - (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4)); - - /* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */ - write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size); - - /* enable PCM/GCI master mode */ - write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */ - write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */ - - /* init the fifos */ - write_usb(hfc, HFCUSB_F_THRES, - (HFCUSB_TX_THRESHOLD / - 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4)); - - fifo = hfc->fifos; - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */ - fifo[i].skbuff = NULL; /* init buffer pointer */ - fifo[i].max_size = - (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; - fifo[i].last_urblen = 0; - /* set 2 bit for D- & E-channel */ - write_usb(hfc, HFCUSB_HDLC_PAR, - ((i <= HFCUSB_B2_RX) ? 0 : 2)); - /* rx hdlc, enable IFF for D-channel */ - write_usb(hfc, HFCUSB_CON_HDLC, - ((i == HFCUSB_D_TX) ? 0x09 : 0x08)); - write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */ - } - - write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */ - write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */ - write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */ - - write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ - write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */ - - /* set both B-channel to not connected */ - hfc->b_mode[0] = L1_MODE_NULL; - hfc->b_mode[1] = L1_MODE_NULL; - - hfc->l1_activated = 0; - hfc->disc_flag = 0; - hfc->led_state = 0; - hfc->old_led_state = 0; - - /* init the t3 timer */ - timer_setup(&hfc->t3_timer, l1_timer_expire_t3, 0); - - /* init the t4 timer */ - timer_setup(&hfc->t4_timer, l1_timer_expire_t4, 0); - - /* init the background machinery for control requests */ - hfc->ctrl_read.bRequestType = 0xc0; - hfc->ctrl_read.bRequest = 1; - hfc->ctrl_read.wLength = cpu_to_le16(1); - hfc->ctrl_write.bRequestType = 0x40; - hfc->ctrl_write.bRequest = 0; - hfc->ctrl_write.wLength = 0; - usb_fill_control_urb(hfc->ctrl_urb, - hfc->dev, - hfc->ctrl_out_pipe, - (u_char *)&hfc->ctrl_write, - NULL, 0, ctrl_complete, hfc); - /* Init All Fifos */ - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - hfc->fifos[i].iso[0].purb = NULL; - hfc->fifos[i].iso[1].purb = NULL; - hfc->fifos[i].active = 0; - } - /* register Modul to upper Hisax Layers */ - hfc->d_if.owner = THIS_MODULE; - hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX]; - hfc->d_if.ifc.l2l1 = hfc_usb_l2l1; - for (i = 0; i < 2; i++) { - hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2]; - hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1; - p_b_if[i] = &hfc->b_if[i]; - } - /* default Prot: EURO ISDN, should be a module_param */ - hfc->protocol = 2; - i = hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol); - if (i) { - printk(KERN_INFO "HFC-S USB: hisax_register -> %d\n", i); - return i; - } - -#ifdef CONFIG_HISAX_DEBUG - hfc_debug = debug; -#endif - - for (i = 0; i < 4; i++) - hfc->fifos[i].hif = &p_b_if[i / 2]->ifc; - for (i = 4; i < 8; i++) - hfc->fifos[i].hif = &hfc->d_if.ifc; - - /* 3 (+1) INT IN + 3 ISO OUT */ - if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) { - start_int_fifo(hfc->fifos + HFCUSB_D_RX); - if (hfc->fifos[HFCUSB_PCM_RX].pipe) - start_int_fifo(hfc->fifos + HFCUSB_PCM_RX); - start_int_fifo(hfc->fifos + HFCUSB_B1_RX); - start_int_fifo(hfc->fifos + HFCUSB_B2_RX); - } - /* 3 (+1) ISO IN + 3 ISO OUT */ - if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) { - start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D, - rx_iso_complete, 16); - if (hfc->fifos[HFCUSB_PCM_RX].pipe) - start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX, - ISOC_PACKETS_D, rx_iso_complete, - 16); - start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B, - rx_iso_complete, 16); - start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B, - rx_iso_complete, 16); - } - - start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, - tx_iso_complete, 1); - start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, - tx_iso_complete, 1); - start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B, - tx_iso_complete, 1); - - handle_led(hfc, LED_POWER_ON); - - return (0); -} - -/* initial callback for each plugged USB device */ -static int -hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - hfcusb_data *context; - struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_host_interface *iface_used = NULL; - struct usb_host_endpoint *ep; - int ifnum = iface->desc.bInterfaceNumber; - int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, - attr, cfg_found, cidx, ep_addr; - int cmptbl[16], small_match, iso_packet_size, packet_size, - alt_used = 0; - hfcsusb_vdata *driver_info; - - vend_idx = 0xffff; - for (i = 0; hfcusb_idtab[i].idVendor; i++) { - if ((le16_to_cpu(dev->descriptor.idVendor) == hfcusb_idtab[i].idVendor) - && (le16_to_cpu(dev->descriptor.idProduct) == hfcusb_idtab[i].idProduct)) { - vend_idx = i; - continue; - } - } - - printk(KERN_INFO - "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n", - ifnum, iface->desc.bAlternateSetting, intf->minor); - - if (vend_idx != 0xffff) { - /* if vendor and product ID is OK, start probing alternate settings */ - alt_idx = 0; - small_match = 0xffff; - - /* default settings */ - iso_packet_size = 16; - packet_size = 64; - - while (alt_idx < intf->num_altsetting) { - iface = intf->altsetting + alt_idx; - probe_alt_setting = iface->desc.bAlternateSetting; - cfg_used = 0; - - /* check for config EOL element */ - while (validconf[cfg_used][0]) { - cfg_found = 1; - vcf = validconf[cfg_used]; - /* first endpoint descriptor */ - ep = iface->endpoint; - - memcpy(cmptbl, vcf, 16 * sizeof(int)); - - /* check for all endpoints in this alternate setting */ - for (i = 0; i < iface->desc.bNumEndpoints; - i++) { - ep_addr = - ep->desc.bEndpointAddress; - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (ep_addr & 0x80) - idx++; - attr = ep->desc.bmAttributes; - if (cmptbl[idx] == EP_NUL) { - cfg_found = 0; - } - if (attr == USB_ENDPOINT_XFER_INT - && cmptbl[idx] == EP_INT) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_BULK - && cmptbl[idx] == EP_BLK) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_ISOC - && cmptbl[idx] == EP_ISO) - cmptbl[idx] = EP_NUL; - - /* check if all INT endpoints match minimum interval */ - if ((attr == USB_ENDPOINT_XFER_INT) - && (ep->desc.bInterval < vcf[17])) { - cfg_found = 0; - } - ep++; - } - for (i = 0; i < 16; i++) { - /* all entries must be EP_NOP or EP_NUL for a valid config */ - if (cmptbl[i] != EP_NOP - && cmptbl[i] != EP_NUL) - cfg_found = 0; - } - if (cfg_found) { - if (cfg_used < small_match) { - small_match = cfg_used; - alt_used = - probe_alt_setting; - iface_used = iface; - } - } - cfg_used++; - } - alt_idx++; - } /* (alt_idx < intf->num_altsetting) */ - - /* found a valid USB Ta Endpint config */ - if (small_match != 0xffff) { - iface = iface_used; - if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL))) - return (-ENOMEM); /* got no mem */ - - ep = iface->endpoint; - vcf = validconf[small_match]; - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - ep_addr = ep->desc.bEndpointAddress; - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (ep_addr & 0x80) - idx++; - cidx = idx & 7; - attr = ep->desc.bmAttributes; - - /* init Endpoints */ - if (vcf[idx] != EP_NOP - && vcf[idx] != EP_NUL) { - switch (attr) { - case USB_ENDPOINT_XFER_INT: - context-> - fifos[cidx]. - pipe = - usb_rcvintpipe - (dev, - ep->desc. - bEndpointAddress); - context-> - fifos[cidx]. - usb_transfer_mode - = USB_INT; - packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - break; - case USB_ENDPOINT_XFER_BULK: - if (ep_addr & 0x80) - context-> - fifos - [cidx]. - pipe = - usb_rcvbulkpipe - (dev, - ep-> - desc. - bEndpointAddress); - else - context-> - fifos - [cidx]. - pipe = - usb_sndbulkpipe - (dev, - ep-> - desc. - bEndpointAddress); - context-> - fifos[cidx]. - usb_transfer_mode - = USB_BULK; - packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - break; - case USB_ENDPOINT_XFER_ISOC: - if (ep_addr & 0x80) - context-> - fifos - [cidx]. - pipe = - usb_rcvisocpipe - (dev, - ep-> - desc. - bEndpointAddress); - else - context-> - fifos - [cidx]. - pipe = - usb_sndisocpipe - (dev, - ep-> - desc. - bEndpointAddress); - context-> - fifos[cidx]. - usb_transfer_mode - = USB_ISOC; - iso_packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - break; - default: - context-> - fifos[cidx]. - pipe = 0; - } /* switch attribute */ - - if (context->fifos[cidx].pipe) { - context->fifos[cidx]. - fifonum = cidx; - context->fifos[cidx].hfc = - context; - context->fifos[cidx].usb_packet_maxlen = - le16_to_cpu(ep->desc.wMaxPacketSize); - context->fifos[cidx]. - intervall = - ep->desc.bInterval; - context->fifos[cidx]. - skbuff = NULL; - } - } - ep++; - } - context->dev = dev; /* save device */ - context->if_used = ifnum; /* save used interface */ - context->alt_used = alt_used; /* and alternate config */ - context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ - context->cfg_used = vcf[16]; /* store used config */ - context->vend_idx = vend_idx; /* store found vendor */ - context->packet_size = packet_size; - context->iso_packet_size = iso_packet_size; - - /* create the control pipes needed for register access */ - context->ctrl_in_pipe = - usb_rcvctrlpipe(context->dev, 0); - context->ctrl_out_pipe = - usb_sndctrlpipe(context->dev, 0); - - driver_info = (hfcsusb_vdata *) - hfcusb_idtab[vend_idx].driver_info; - - context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - - if (!context->ctrl_urb) { - pr_warn("%s: No memory for control urb\n", - driver_info->vend_name); - kfree(context); - return -ENOMEM; - } - - pr_info("HFC-S USB: detected \"%s\"\n", - driver_info->vend_name); - - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)", - conf_str[small_match], context->if_used, - context->alt_used, - validconf[small_match][18]); - - /* init the chip and register the driver */ - if (hfc_usb_init(context)) { - usb_kill_urb(context->ctrl_urb); - usb_free_urb(context->ctrl_urb); - context->ctrl_urb = NULL; - kfree(context); - return (-EIO); - } - usb_set_intfdata(intf, context); - return (0); - } - } else { - printk(KERN_INFO - "HFC-S USB: no valid vendor found in USB descriptor\n"); - } - return (-EIO); -} - -/* callback for unplugged USB device */ -static void -hfc_usb_disconnect(struct usb_interface *intf) -{ - hfcusb_data *context = usb_get_intfdata(intf); - int i; - - handle_led(context, LED_POWER_OFF); - schedule_timeout(HZ / 100); - - printk(KERN_INFO "HFC-S USB: device disconnect\n"); - context->disc_flag = 1; - usb_set_intfdata(intf, NULL); - - if (timer_pending(&context->t3_timer)) - del_timer(&context->t3_timer); - if (timer_pending(&context->t4_timer)) - del_timer(&context->t4_timer); - - /* tell all fifos to terminate */ - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - if (context->fifos[i].usb_transfer_mode == USB_ISOC) { - if (context->fifos[i].active > 0) { - stop_isoc_chain(&context->fifos[i]); - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: %s stopping ISOC chain Fifo(%i)", - __func__, i); - } - } else { - if (context->fifos[i].active > 0) { - context->fifos[i].active = 0; - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: %s unlinking URB for Fifo(%i)", - __func__, i); - } - usb_kill_urb(context->fifos[i].urb); - usb_free_urb(context->fifos[i].urb); - context->fifos[i].urb = NULL; - } - context->fifos[i].active = 0; - } - usb_kill_urb(context->ctrl_urb); - usb_free_urb(context->ctrl_urb); - context->ctrl_urb = NULL; - hisax_unregister(&context->d_if); - kfree(context); /* free our structure again */ -} - -static struct usb_driver hfc_drv = { - .name = "hfc_usb", - .id_table = hfcusb_idtab, - .probe = hfc_usb_probe, - .disconnect = hfc_usb_disconnect, - .disable_hub_initiated_lpm = 1, -}; - -static void __exit -hfc_usb_mod_exit(void) -{ - usb_deregister(&hfc_drv); /* release our driver */ - printk(KERN_INFO "HFC-S USB: module removed\n"); -} - -static int __init -hfc_usb_mod_init(void) -{ - char revstr[30], datestr[30], dummy[30]; -#ifndef CONFIG_HISAX_DEBUG - hfc_debug = debug; -#endif - sscanf(hfcusb_revision, - "%s %s $ %s %s %s $ ", dummy, revstr, - dummy, datestr, dummy); - printk(KERN_INFO - "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n", - revstr, datestr, debug); - if (usb_register(&hfc_drv)) { - printk(KERN_INFO - "HFC-S USB: Unable to register HFC-S USB module at usb stack\n"); - return (-1); /* unable to register */ - } - return (0); -} - -module_init(hfc_usb_mod_init); -module_exit(hfc_usb_mod_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, hfcusb_idtab); diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h deleted file mode 100644 index 9a212330e8a8..000000000000 --- a/drivers/isdn/hisax/hfc_usb.h +++ /dev/null @@ -1,208 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * hfc_usb.h - * - * $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $ - */ - -#ifndef __HFC_USB_H__ -#define __HFC_USB_H__ - -#define DRIVER_AUTHOR "Peter Sprenger (sprenger@moving-byters.de)" -#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver" - - -#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */ -#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */ -#define HFC_TIMER_T4 500 /* time for state change interval */ - -#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */ -#define HFCUSB_L1_DRX 1 /* D-frame received */ -#define HFCUSB_L1_ERX 2 /* E-frame received */ -#define HFCUSB_L1_DTX 4 /* D-frames completed */ - -#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */ - -#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */ -#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */ - -#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */ -#define HFCUSB_CIRM 0x00 /* cirm register index */ -#define HFCUSB_USB_SIZE 0x07 /* int length register */ -#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */ -#define HFCUSB_F_CROSS 0x0b /* bit order register */ -#define HFCUSB_CLKDEL 0x37 /* bit delay register */ -#define HFCUSB_CON_HDLC 0xfa /* channel connect register */ -#define HFCUSB_HDLC_PAR 0xfb -#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */ -#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */ -#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */ -#define HFCUSB_F_THRES 0x0c /* threshold register */ -#define HFCUSB_FIFO 0x0f /* fifo select register */ -#define HFCUSB_F_USAGE 0x1a /* fifo usage register */ -#define HFCUSB_MST_MODE0 0x14 -#define HFCUSB_MST_MODE1 0x15 -#define HFCUSB_P_DATA 0x1f -#define HFCUSB_INC_RES_F 0x0e -#define HFCUSB_STATES 0x30 - -#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */ - - -/* fifo registers */ -#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */ -#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */ -#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */ -#define HFCUSB_B2_TX 2 -#define HFCUSB_B2_RX 3 -#define HFCUSB_D_TX 4 -#define HFCUSB_D_RX 5 -#define HFCUSB_PCM_TX 6 -#define HFCUSB_PCM_RX 7 - -/* - * used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just - * supports ISO out, while the Cologne Chip EVAL TA just supports BULK out - */ -#define USB_INT 0 -#define USB_BULK 1 -#define USB_ISOC 2 - -#define ISOC_PACKETS_D 8 -#define ISOC_PACKETS_B 8 -#define ISO_BUFFER_SIZE 128 - -/* Fifo flow Control for TX ISO */ -#define SINK_MAX 68 -#define SINK_MIN 48 -#define SINK_DMIN 12 -#define SINK_DMAX 18 -#define BITLINE_INF (-64 * 8) - -/* HFC-S USB register access by Control-URSs */ -#define write_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), NULL, 0, HFC_CTRL_TIMEOUT) -#define read_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), 1, HFC_CTRL_TIMEOUT) -#define HFC_CTRL_BUFSIZE 32 - -/* entry and size of output/input control buffer */ -typedef struct { - __u8 hfc_reg; /* register number */ - __u8 reg_val; /* value to be written (or read) */ - int action; /* data for action handler */ -} ctrl_buft; - -/* Debugging Flags */ -#define HFCUSB_DBG_INIT 0x0001 -#define HFCUSB_DBG_STATES 0x0002 -#define HFCUSB_DBG_DCHANNEL 0x0080 -#define HFCUSB_DBG_FIFO_ERR 0x4000 -#define HFCUSB_DBG_VERBOSE_USB 0x8000 - -/* - * URB error codes: - * Used to represent a list of values and their respective symbolic names - */ -struct hfcusb_symbolic_list { - const int num; - const char *name; -}; - -static struct hfcusb_symbolic_list urb_errlist[] = { - {-ENOMEM, "No memory for allocation of internal structures"}, - {-ENOSPC, "The host controller's bandwidth is already consumed"}, - {-ENOENT, "URB was canceled by unlink_urb"}, - {-EXDEV, "ISO transfer only partially completed"}, - {-EAGAIN, "Too match scheduled for the future"}, - {-ENXIO, "URB already queued"}, - {-EFBIG, "Too much ISO frames requested"}, - {-ENOSR, "Buffer error (overrun)"}, - {-EPIPE, "Specified endpoint is stalled (device not responding)"}, - {-EOVERFLOW, "Babble (bad cable?)"}, - {-EPROTO, "Bit-stuff error (bad cable?)"}, - {-EILSEQ, "CRC/Timeout"}, - {-ETIMEDOUT, "NAK (device does not respond)"}, - {-ESHUTDOWN, "Device unplugged"}, - {-1, NULL} -}; - - -/* - * device dependent information to support different - * ISDN Ta's using the HFC-S USB chip - */ - -/* USB descriptor need to contain one of the following EndPoint combination: */ -#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT -#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT -#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT -#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT - -#define EP_NUL 1 // Endpoint at this position not allowed -#define EP_NOP 2 // all type of endpoints allowed at this position -#define EP_ISO 3 // Isochron endpoint mandatory at this position -#define EP_BLK 4 // Bulk endpoint mandatory at this position -#define EP_INT 5 // Interrupt endpoint mandatory at this position - -/* - * List of all supported endpoint configuration sets, used to find the - * best matching endpoint configuration within a devices' USB descriptor. - * We need at least 3 RX endpoints, and 3 TX endpoints, either - * INT-in and ISO-out, or ISO-in and ISO-out) - * with 4 RX endpoints even E-Channel logging is possible - */ -static int validconf[][19] = { - // INT in, ISO out config - {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT, - EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, - CNF_4INT3ISO, 2, 1}, - {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL, - EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, - CNF_3INT3ISO, 2, 0}, - // ISO in, ISO out config - {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, - EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO, - CNF_4ISO3ISO, 2, 1}, - {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, - EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL, - CNF_3ISO3ISO, 2, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element -}; - -#ifdef CONFIG_HISAX_DEBUG -// string description of chosen config -static char *conf_str[] = { - "4 Interrupt IN + 3 Isochron OUT", - "3 Interrupt IN + 3 Isochron OUT", - "4 Isochron IN + 3 Isochron OUT", - "3 Isochron IN + 3 Isochron OUT" -}; -#endif - -typedef struct { - int vendor; // vendor id - int prod_id; // product id - char *vend_name; // vendor string - __u8 led_scheme; // led display scheme - signed short led_bits[8]; // array of 8 possible LED bitmask settings -} vendor_data; - -#define LED_OFF 0 // no LED support -#define LED_SCHEME1 1 // LED standard scheme -#define LED_SCHEME2 2 // not used yet... - -#define LED_POWER_ON 1 -#define LED_POWER_OFF 2 -#define LED_S0_ON 3 -#define LED_S0_OFF 4 -#define LED_B1_ON 5 -#define LED_B1_OFF 6 -#define LED_B1_DATA 7 -#define LED_B2_ON 8 -#define LED_B2_OFF 9 -#define LED_B2_DATA 10 - -#define LED_NORMAL 0 // LEDs are normal -#define LED_INVERTED 1 // LEDs are inverted - - -#endif // __HFC_USB_H__ diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c deleted file mode 100644 index 91b5219499ca..000000000000 --- a/drivers/isdn/hisax/hfcscard.c +++ /dev/null @@ -1,261 +0,0 @@ -/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $ - * - * low level stuff for hfcs based cards (Teles3c, ACER P10) - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include "hisax.h" -#include "hfc_2bds0.h" -#include "isdnl1.h" - -static const char *hfcs_revision = "$Revision: 1.10.2.4 $"; - -static irqreturn_t -hfcs_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, stat; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & - (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { - val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val); - hfc2bds0_interrupt(cs, val); - } else { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -hfcs_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfcD.timer); - cs->hw.hfcD.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80); - add_timer(&cs->hw.hfcD.timer); -*/ -} - -static void -release_io_hfcs(struct IsdnCardState *cs) -{ - release2bds0(cs); - del_timer(&cs->hw.hfcD.timer); - if (cs->hw.hfcD.addr) - release_region(cs->hw.hfcD.addr, 2); -} - -static void -reset_hfcs(struct IsdnCardState *cs) -{ - printk(KERN_INFO "HFCS: resetting card\n"); - cs->hw.hfcD.cirm = HFCD_RESET; - if (cs->typ == ISDN_CTYPE_TELES3C) - cs->hw.hfcD.cirm |= HFCD_MEM8K; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ - mdelay(10); - cs->hw.hfcD.cirm = 0; - if (cs->typ == ISDN_CTYPE_TELES3C) - cs->hw.hfcD.cirm |= HFCD_MEM8K; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ - mdelay(10); - if (cs->typ == ISDN_CTYPE_TELES3C) - cs->hw.hfcD.cirm |= HFCD_INTB; - else if (cs->typ == ISDN_CTYPE_ACERP10) - cs->hw.hfcD.cirm |= HFCD_INTA; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ - cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; - cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | - HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | - HFCD_INTS_DREC | HFCD_INTS_L1STATE; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcD.mst_m = HFCD_MASTER; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */ - cs->hw.hfcD.sctrl = 0; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); -} - -static int -hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - int delay; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCS: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_hfcs(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_hfcs(cs); - return (0); - case CARD_INIT: - delay = (75 * HZ) / 100 + 1; - mod_timer(&cs->hw.hfcD.timer, jiffies + delay); - spin_lock_irqsave(&cs->lock, flags); - reset_hfcs(cs); - init2bds0(cs); - spin_unlock_irqrestore(&cs->lock, flags); - delay = (80 * HZ) / 1000 + 1; - msleep(80); - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcD.ctmt |= HFCD_TIM800; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id hfc_ids[] = { - { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), - ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), - (unsigned long) "Acer P10" }, - { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), - ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), - (unsigned long) "Billion 2" }, - { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), - ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), - (unsigned long) "Billion 1" }, - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), - (unsigned long) "IStar PnP" }, - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), - (unsigned long) "Teles 16.3c" }, - { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), - ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), - (unsigned long) "Tornado Tipa C" }, - { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), - ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), - (unsigned long) "Genius Speed Surfer" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &hfc_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_hfcs(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, hfcs_revision); - printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp)); - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - cs->hw.hfcD.addr = card->para[1] & 0xfffe; - cs->irq = card->para[0]; - cs->hw.hfcD.cip = 0; - cs->hw.hfcD.int_s1 = 0; - cs->hw.hfcD.send = NULL; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; - cs->hw.hfcD.dfifosize = 512; - cs->dc.hfcd.ph_state = 0; - cs->hw.hfcD.fifo = 255; - if (cs->typ == ISDN_CTYPE_TELES3C) { - cs->hw.hfcD.bfifosize = 1024 + 512; - } else if (cs->typ == ISDN_CTYPE_ACERP10) { - cs->hw.hfcD.bfifosize = 7 * 1024 + 512; - } else - return (0); - if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.hfcD.addr, - cs->hw.hfcD.addr + 2); - return (0); - } - printk(KERN_INFO - "HFCS: defined at 0x%x IRQ %d HZ %d\n", - cs->hw.hfcD.addr, - cs->irq, HZ); - if (cs->typ == ISDN_CTYPE_TELES3C) { - /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x56, cs->hw.hfcD.addr | 1); - } else if (cs->typ == ISDN_CTYPE_ACERP10) { - /* Acer P10 IO ADR is 0x300 */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x57, cs->hw.hfcD.addr | 1); - } - set_cs_func(cs); - timer_setup(&cs->hw.hfcD.timer, hfcs_Timer, 0); - cs->cardmsg = &hfcs_card_msg; - cs->irq_func = &hfcs_interrupt; - return (1); -} diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h deleted file mode 100644 index 40080e06421c..000000000000 --- a/drivers/isdn/hisax/hisax.h +++ /dev/null @@ -1,1352 +0,0 @@ -/* $Id: hisax.h,v 2.64.2.4 2004/02/11 13:21:33 keil Exp $ - * - * Basic declarations, defines and prototypes - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ERROR_STATISTIC - -#define REQUEST 0 -#define CONFIRM 1 -#define INDICATION 2 -#define RESPONSE 3 - -#define HW_ENABLE 0x0000 -#define HW_RESET 0x0004 -#define HW_POWERUP 0x0008 -#define HW_ACTIVATE 0x0010 -#define HW_DEACTIVATE 0x0018 - -#define HW_INFO1 0x0010 -#define HW_INFO2 0x0020 -#define HW_INFO3 0x0030 -#define HW_INFO4 0x0040 -#define HW_INFO4_P8 0x0040 -#define HW_INFO4_P10 0x0048 -#define HW_RSYNC 0x0060 -#define HW_TESTLOOP 0x0070 -#define CARD_RESET 0x00F0 -#define CARD_INIT 0x00F2 -#define CARD_RELEASE 0x00F3 -#define CARD_TEST 0x00F4 -#define CARD_AUX_IND 0x00F5 - -#define PH_ACTIVATE 0x0100 -#define PH_DEACTIVATE 0x0110 -#define PH_DATA 0x0120 -#define PH_PULL 0x0130 -#define PH_TESTLOOP 0x0140 -#define PH_PAUSE 0x0150 -#define MPH_ACTIVATE 0x0180 -#define MPH_DEACTIVATE 0x0190 -#define MPH_INFORMATION 0x01A0 - -#define DL_ESTABLISH 0x0200 -#define DL_RELEASE 0x0210 -#define DL_DATA 0x0220 -#define DL_FLUSH 0x0224 -#define DL_UNIT_DATA 0x0230 - -#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now -#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now -#define MDL_ASSIGN 0x0280 -#define MDL_REMOVE 0x0284 -#define MDL_ERROR 0x0288 -#define MDL_INFO_SETUP 0x02E0 -#define MDL_INFO_CONN 0x02E4 -#define MDL_INFO_REL 0x02E8 - -#define CC_SETUP 0x0300 -#define CC_RESUME 0x0304 -#define CC_MORE_INFO 0x0310 -#define CC_IGNORE 0x0320 -#define CC_REJECT 0x0324 -#define CC_SETUP_COMPL 0x0330 -#define CC_PROCEEDING 0x0340 -#define CC_ALERTING 0x0344 -#define CC_PROGRESS 0x0348 -#define CC_CONNECT 0x0350 -#define CC_CHARGE 0x0354 -#define CC_NOTIFY 0x0358 -#define CC_DISCONNECT 0x0360 -#define CC_RELEASE 0x0368 -#define CC_SUSPEND 0x0370 -#define CC_PROCEED_SEND 0x0374 -#define CC_REDIR 0x0378 -#define CC_T302 0x0382 -#define CC_T303 0x0383 -#define CC_T304 0x0384 -#define CC_T305 0x0385 -#define CC_T308_1 0x0388 -#define CC_T308_2 0x038A -#define CC_T309 0x0309 -#define CC_T310 0x0390 -#define CC_T313 0x0393 -#define CC_T318 0x0398 -#define CC_T319 0x0399 -#define CC_TSPID 0x03A0 -#define CC_NOSETUP_RSP 0x03E0 -#define CC_SETUP_ERR 0x03E1 -#define CC_SUSPEND_ERR 0x03E2 -#define CC_RESUME_ERR 0x03E3 -#define CC_CONNECT_ERR 0x03E4 -#define CC_RELEASE_ERR 0x03E5 -#define CC_RESTART 0x03F4 -#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ -#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */ - -/* define maximum number of possible waiting incoming calls */ -#define MAX_WAITING_CALLS 2 - - -#ifdef __KERNEL__ - -extern const char *CardType[]; -extern int nrcards; - -extern const char *l1_revision; -extern const char *l2_revision; -extern const char *l3_revision; -extern const char *lli_revision; -extern const char *tei_revision; - -/* include l3dss1 & ni1 specific process structures, but no other defines */ -#ifdef CONFIG_HISAX_EURO -#define l3dss1_process -#include "l3dss1.h" -#undef l3dss1_process -#endif /* CONFIG_HISAX_EURO */ - -#ifdef CONFIG_HISAX_NI1 -#define l3ni1_process -#include "l3ni1.h" -#undef l3ni1_process -#endif /* CONFIG_HISAX_NI1 */ - -#define MAX_DFRAME_LEN 260 -#define MAX_DFRAME_LEN_L1 300 -#define HSCX_BUFMAX 4096 -#define MAX_DATA_SIZE (HSCX_BUFMAX - 4) -#define MAX_DATA_MEM (HSCX_BUFMAX + 64) -#define RAW_BUFMAX (((HSCX_BUFMAX * 6) / 5) + 5) -#define MAX_HEADER_LEN 4 -#define MAX_WINDOW 8 -#define MAX_MON_FRAME 32 -#define MAX_DLOG_SPACE 2048 -#define MAX_BLOG_SPACE 256 - -/* #define I4L_IRQ_FLAG SA_INTERRUPT */ -#define I4L_IRQ_FLAG 0 - -/* - * Statemachine - */ - -struct FsmInst; - -typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); - -struct Fsm { - FSMFNPTR *jumpmatrix; - int state_count, event_count; - char **strEvent, **strState; -}; - -struct FsmInst { - struct Fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct FsmInst *, char *, ...); -}; - -struct FsmNode { - int state, event; - void (*routine) (struct FsmInst *, int, void *); -}; - -struct FsmTimer { - struct FsmInst *fi; - struct timer_list tl; - int event; - void *arg; -}; - -struct L3Timer { - struct l3_process *pc; - struct timer_list tl; - int event; -}; - -#define FLG_L1_ACTIVATING 1 -#define FLG_L1_ACTIVATED 2 -#define FLG_L1_DEACTTIMER 3 -#define FLG_L1_ACTTIMER 4 -#define FLG_L1_T3RUN 5 -#define FLG_L1_PULL_REQ 6 -#define FLG_L1_UINT 7 - -struct Layer1 { - void *hardware; - struct BCState *bcs; - struct PStack **stlistp; - unsigned long Flags; - struct FsmInst l1m; - struct FsmTimer timer; - void (*l1l2) (struct PStack *, int, void *); - void (*l1hw) (struct PStack *, int, void *); - void (*l1tei) (struct PStack *, int, void *); - int mode, bc; - int delay; -}; - -#define GROUP_TEI 127 -#define TEI_SAPI 63 -#define CTRL_SAPI 0 -#define PACKET_NOACK 7 - -/* Layer2 Flags */ - -#define FLG_LAPB 0 -#define FLG_LAPD 1 -#define FLG_ORIG 2 -#define FLG_MOD128 3 -#define FLG_PEND_REL 4 -#define FLG_L3_INIT 5 -#define FLG_T200_RUN 6 -#define FLG_ACK_PEND 7 -#define FLG_REJEXC 8 -#define FLG_OWN_BUSY 9 -#define FLG_PEER_BUSY 10 -#define FLG_DCHAN_BUSY 11 -#define FLG_L1_ACTIV 12 -#define FLG_ESTAB_PEND 13 -#define FLG_PTP 14 -#define FLG_FIXED_TEI 15 -#define FLG_L2BLOCK 16 - -struct Layer2 { - int tei; - int sap; - int maxlen; - u_long flag; - spinlock_t lock; - u_int vs, va, vr; - int rc; - unsigned int window; - unsigned int sow; - struct sk_buff *windowar[MAX_WINDOW]; - struct sk_buff_head i_queue; - struct sk_buff_head ui_queue; - void (*l2l1) (struct PStack *, int, void *); - void (*l2l3) (struct PStack *, int, void *); - void (*l2tei) (struct PStack *, int, void *); - struct FsmInst l2m; - struct FsmTimer t200, t203; - int T200, N200, T203; - int debug; - char debug_id[16]; -}; - -struct Layer3 { - void (*l3l4) (struct PStack *, int, void *); - void (*l3ml3) (struct PStack *, int, void *); - void (*l3l2) (struct PStack *, int, void *); - struct FsmInst l3m; - struct FsmTimer l3m_timer; - struct sk_buff_head squeue; - struct l3_process *proc; - struct l3_process *global; - int N303; - int debug; - char debug_id[8]; -}; - -struct LLInterface { - void (*l4l3) (struct PStack *, int, void *); - int (*l4l3_proto) (struct PStack *, isdn_ctrl *); - void *userdata; - u_long flag; -}; - -#define FLG_LLI_L1WAKEUP 1 -#define FLG_LLI_L2WAKEUP 2 - -struct Management { - int ri; - struct FsmInst tei_m; - struct FsmTimer t202; - int T202, N202, debug; - void (*layer) (struct PStack *, int, void *); -}; - -#define NO_CAUSE 254 - -struct Param { - u_char cause; - u_char loc; - u_char diag[6]; - int bchannel; - int chargeinfo; - int spv; /* SPV Flag */ - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - u_char moderate; /* transfer mode and rate (bearer octet 4) */ -}; - - -struct PStack { - struct PStack *next; - struct Layer1 l1; - struct Layer2 l2; - struct Layer3 l3; - struct LLInterface lli; - struct Management ma; - int protocol; /* EDSS1, 1TR6 or NI1 */ - - /* protocol specific data fields */ - union - { u_char uuuu; /* only as dummy */ -#ifdef CONFIG_HISAX_EURO - dss1_stk_priv dss1; /* private dss1 data */ -#endif /* CONFIG_HISAX_EURO */ -#ifdef CONFIG_HISAX_NI1 - ni1_stk_priv ni1; /* private ni1 data */ -#endif /* CONFIG_HISAX_NI1 */ - } prot; -}; - -struct l3_process { - int callref; - int state; - struct L3Timer timer; - int N303; - int debug; - struct Param para; - struct Channel *chan; - struct PStack *st; - struct l3_process *next; - ulong redir_result; - - /* protocol specific data fields */ - union - { u_char uuuu; /* only when euro not defined, avoiding empty union */ -#ifdef CONFIG_HISAX_EURO - dss1_proc_priv dss1; /* private dss1 data */ -#endif /* CONFIG_HISAX_EURO */ -#ifdef CONFIG_HISAX_NI1 - ni1_proc_priv ni1; /* private ni1 data */ -#endif /* CONFIG_HISAX_NI1 */ - } prot; -}; - -struct hscx_hw { - int hscx; - int rcvidx; - int count; /* Current skb sent count */ - u_char *rcvbuf; /* B-Channel receive Buffer */ - u_char tsaxr0; - u_char tsaxr1; -}; - -struct w6692B_hw { - int bchan; - int rcvidx; - int count; /* Current skb sent count */ - u_char *rcvbuf; /* B-Channel receive Buffer */ -}; - -struct isar_reg { - unsigned long Flags; - volatile u_char bstat; - volatile u_char iis; - volatile u_char cmsb; - volatile u_char clsb; - volatile u_char par[8]; -}; - -struct isar_hw { - int dpath; - int rcvidx; - int txcnt; - int mml; - u_char state; - u_char cmd; - u_char mod; - u_char newcmd; - u_char newmod; - char try_mod; - struct timer_list ftimer; - u_char *rcvbuf; /* B-Channel receive Buffer */ - u_char conmsg[16]; - struct isar_reg *reg; -}; - -struct hdlc_stat_reg { -#ifdef __BIG_ENDIAN - u_char fill; - u_char mode; - u_char xml; - u_char cmd; -#else - u_char cmd; - u_char xml; - u_char mode; - u_char fill; -#endif -} __attribute__((packed)); - -struct hdlc_hw { - union { - u_int ctrl; - struct hdlc_stat_reg sr; - } ctrl; - u_int stat; - int rcvidx; - int count; /* Current skb sent count */ - u_char *rcvbuf; /* B-Channel receive Buffer */ -}; - -struct hfcB_hw { - unsigned int *send; - int f1; - int f2; -}; - -struct tiger_hw { - u_int *send; - u_int *s_irq; - u_int *s_end; - u_int *sendp; - u_int *rec; - int free; - u_char *rcvbuf; - u_char *sendbuf; - u_char *sp; - int sendcnt; - u_int s_tot; - u_int r_bitcnt; - u_int r_tot; - u_int r_err; - u_int r_fcs; - u_char r_state; - u_char r_one; - u_char r_val; - u_char s_state; -}; - -struct amd7930_hw { - u_char *tx_buff; - u_char *rv_buff; - int rv_buff_in; - int rv_buff_out; - struct sk_buff *rv_skb; - struct hdlc_state *hdlc_state; - struct work_struct tq_rcv; - struct work_struct tq_xmt; -}; - -#define BC_FLG_INIT 1 -#define BC_FLG_ACTIV 2 -#define BC_FLG_BUSY 3 -#define BC_FLG_NOFRAME 4 -#define BC_FLG_HALF 5 -#define BC_FLG_EMPTY 6 -#define BC_FLG_ORIG 7 -#define BC_FLG_DLEETX 8 -#define BC_FLG_LASTDLE 9 -#define BC_FLG_FIRST 10 -#define BC_FLG_LASTDATA 11 -#define BC_FLG_NMD_DATA 12 -#define BC_FLG_FTI_RUN 13 -#define BC_FLG_LL_OK 14 -#define BC_FLG_LL_CONN 15 -#define BC_FLG_FTI_FTS 16 -#define BC_FLG_FRH_WAIT 17 - -#define L1_MODE_NULL 0 -#define L1_MODE_TRANS 1 -#define L1_MODE_HDLC 2 -#define L1_MODE_EXTRN 3 -#define L1_MODE_HDLC_56K 4 -#define L1_MODE_MODEM 7 -#define L1_MODE_V32 8 -#define L1_MODE_FAX 9 - -struct BCState { - int channel; - int mode; - u_long Flag; - struct IsdnCardState *cs; - int tx_cnt; /* B-Channel transmit counter */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ - struct sk_buff_head rqueue; /* B-Channel receive Queue */ - struct sk_buff_head squeue; /* B-Channel send Queue */ - int ackcnt; - spinlock_t aclock; - struct PStack *st; - u_char *blog; - u_char *conmsg; - struct timer_list transbusy; - struct work_struct tqueue; - u_long event; - int (*BC_SetStack) (struct PStack *, struct BCState *); - void (*BC_Close) (struct BCState *); -#ifdef ERROR_STATISTIC - int err_crc; - int err_tx; - int err_rdo; - int err_inv; -#endif - union { - struct hscx_hw hscx; - struct hdlc_hw hdlc; - struct isar_hw isar; - struct hfcB_hw hfc; - struct tiger_hw tiger; - struct amd7930_hw amd7930; - struct w6692B_hw w6692; - struct hisax_b_if *b_if; - } hw; -}; - -struct Channel { - struct PStack *b_st, *d_st; - struct IsdnCardState *cs; - struct BCState *bcs; - int chan; - int incoming; - struct FsmInst fi; - struct FsmTimer drel_timer, dial_timer; - int debug; - int l2_protocol, l2_active_protocol; - int l3_protocol; - int data_open; - struct l3_process *proc; - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - u_long Flags; /* for remembering action done in l4 */ - int leased; -}; - -struct elsa_hw { - struct pci_dev *dev; - unsigned long base; - unsigned int cfg; - unsigned int ctrl; - unsigned int ale; - unsigned int isac; - unsigned int itac; - unsigned int hscx; - unsigned int trig; - unsigned int timer; - unsigned int counter; - unsigned int status; - struct timer_list tl; - unsigned int MFlag; - struct BCState *bcs; - u_char *transbuf; - u_char *rcvbuf; - unsigned int transp; - unsigned int rcvp; - unsigned int transcnt; - unsigned int rcvcnt; - u_char IER; - u_char FCR; - u_char LCR; - u_char MCR; - u_char ctrl_reg; -}; - -struct teles3_hw { - unsigned int cfg_reg; - signed int isac; - signed int hscx[2]; - signed int isacfifo; - signed int hscxfifo[2]; -}; - -struct teles0_hw { - unsigned int cfg_reg; - void __iomem *membase; - unsigned long phymem; -}; - -struct avm_hw { - unsigned int cfg_reg; - unsigned int isac; - unsigned int hscx[2]; - unsigned int isacfifo; - unsigned int hscxfifo[2]; - unsigned int counter; - struct pci_dev *dev; -}; - -struct ix1_hw { - unsigned int cfg_reg; - unsigned int isac_ale; - unsigned int isac; - unsigned int hscx_ale; - unsigned int hscx; -}; - -struct diva_hw { - unsigned long cfg_reg; - unsigned long pci_cfg; - unsigned int ctrl; - unsigned long isac_adr; - unsigned int isac; - unsigned long hscx_adr; - unsigned int hscx; - unsigned int status; - struct timer_list tl; - u_char ctrl_reg; - struct pci_dev *dev; -}; - -struct asus_hw { - unsigned int cfg_reg; - unsigned int adr; - unsigned int isac; - unsigned int hscx; - unsigned int u7; - unsigned int pots; -}; - - -struct hfc_hw { - unsigned int addr; - unsigned int fifosize; - unsigned char cirm; - unsigned char ctmt; - unsigned char cip; - u_char isac_spcr; - struct timer_list timer; -}; - -struct sedl_hw { - unsigned int cfg_reg; - unsigned int adr; - unsigned int isac; - unsigned int hscx; - unsigned int reset_on; - unsigned int reset_off; - struct isar_reg isar; - unsigned int chip; - unsigned int bus; - struct pci_dev *dev; -}; - -struct spt_hw { - unsigned int cfg_reg; - unsigned int isac; - unsigned int hscx[2]; - unsigned char res_irq; -}; - -struct mic_hw { - unsigned int cfg_reg; - unsigned int adr; - unsigned int isac; - unsigned int hscx; -}; - -struct njet_hw { - unsigned long base; - unsigned int isac; - unsigned int auxa; - unsigned char auxd; - unsigned char dmactrl; - unsigned char ctrl_reg; - unsigned char irqmask0; - unsigned char irqstat0; - unsigned char last_is0; - struct pci_dev *dev; -}; - -struct hfcPCI_hw { - unsigned char cirm; - unsigned char ctmt; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char int_s1; - unsigned char sctrl; - unsigned char sctrl_r; - unsigned char sctrl_e; - unsigned char trm; - unsigned char stat; - unsigned char fifo; - unsigned char fifo_en; - unsigned char bswapped; - unsigned char nt_mode; - int nt_timer; - struct pci_dev *dev; - void __iomem *pci_io; /* start of PCI IO memory */ - dma_addr_t dma; /* dma handle for Fifos */ - void *fifos; /* FIFO memory */ - int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ - struct timer_list timer; -}; - -struct hfcSX_hw { - unsigned long base; - unsigned char cirm; - unsigned char ctmt; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char int_s1; - unsigned char sctrl; - unsigned char sctrl_r; - unsigned char sctrl_e; - unsigned char trm; - unsigned char stat; - unsigned char fifo; - unsigned char bswapped; - unsigned char nt_mode; - unsigned char chip; - int b_fifo_size; - unsigned char last_fifo; - void *extra; - int nt_timer; - struct timer_list timer; -}; - -struct hfcD_hw { - unsigned int addr; - unsigned int bfifosize; - unsigned int dfifosize; - unsigned char cirm; - unsigned char ctmt; - unsigned char cip; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char int_s1; - unsigned char sctrl; - unsigned char stat; - unsigned char fifo; - unsigned char f1; - unsigned char f2; - unsigned int *send; - struct timer_list timer; -}; - -struct isurf_hw { - unsigned int reset; - unsigned long phymem; - void __iomem *isac; - void __iomem *isar; - struct isar_reg isar_r; -}; - -struct saphir_hw { - struct pci_dev *dev; - unsigned int cfg_reg; - unsigned int ale; - unsigned int isac; - unsigned int hscx; - struct timer_list timer; -}; - -struct bkm_hw { - struct pci_dev *dev; - unsigned long base; - /* A4T stuff */ - unsigned long isac_adr; - unsigned int isac_ale; - unsigned long jade_adr; - unsigned int jade_ale; - /* Scitel Quadro stuff */ - unsigned long plx_adr; - unsigned long data_adr; -}; - -struct gazel_hw { - struct pci_dev *dev; - unsigned int cfg_reg; - unsigned int pciaddr[2]; - signed int ipac; - signed int isac; - signed int hscx[2]; - signed int isacfifo; - signed int hscxfifo[2]; - unsigned char timeslot; - unsigned char iom2; -}; - -struct w6692_hw { - struct pci_dev *dev; - unsigned int iobase; - struct timer_list timer; -}; - -struct arcofi_msg { - struct arcofi_msg *next; - u_char receive; - u_char len; - u_char msg[10]; -}; - -struct isac_chip { - int ph_state; - u_char *mon_tx; - u_char *mon_rx; - int mon_txp; - int mon_txc; - int mon_rxp; - struct arcofi_msg *arcofi_list; - struct timer_list arcofitimer; - wait_queue_head_t arcofi_wait; - u_char arcofi_bc; - u_char arcofi_state; - u_char mocr; - u_char adf2; -}; - -struct hfcd_chip { - int ph_state; -}; - -struct hfcpci_chip { - int ph_state; -}; - -struct hfcsx_chip { - int ph_state; -}; - -struct w6692_chip { - int ph_state; -}; - -struct amd7930_chip { - u_char lmr1; - u_char ph_state; - u_char old_state; - u_char flg_t3; - unsigned int tx_xmtlen; - struct timer_list timer3; - void (*ph_command) (struct IsdnCardState *, u_char, char *); - void (*setIrqMask) (struct IsdnCardState *, u_char); -}; - -struct icc_chip { - int ph_state; - u_char *mon_tx; - u_char *mon_rx; - int mon_txp; - int mon_txc; - int mon_rxp; - struct arcofi_msg *arcofi_list; - struct timer_list arcofitimer; - wait_queue_head_t arcofi_wait; - u_char arcofi_bc; - u_char arcofi_state; - u_char mocr; - u_char adf2; -}; - -#define HW_IOM1 0 -#define HW_IPAC 1 -#define HW_ISAR 2 -#define HW_ARCOFI 3 -#define FLG_TWO_DCHAN 4 -#define FLG_L1_DBUSY 5 -#define FLG_DBUSY_TIMER 6 -#define FLG_LOCK_ATOMIC 7 -#define FLG_ARCOFI_TIMER 8 -#define FLG_ARCOFI_ERROR 9 -#define FLG_HW_L1_UINT 10 - -struct IsdnCardState { - spinlock_t lock; - u_char typ; - u_char subtyp; - int protocol; - u_int irq; - u_long irq_flags; - u_long HW_Flags; - int *busy_flag; - int chanlimit; /* limited number of B-chans to use */ - int logecho; /* log echo if supported by card */ - union { - struct elsa_hw elsa; - struct teles0_hw teles0; - struct teles3_hw teles3; - struct avm_hw avm; - struct ix1_hw ix1; - struct diva_hw diva; - struct asus_hw asus; - struct hfc_hw hfc; - struct sedl_hw sedl; - struct spt_hw spt; - struct mic_hw mic; - struct njet_hw njet; - struct hfcD_hw hfcD; - struct hfcPCI_hw hfcpci; - struct hfcSX_hw hfcsx; - struct ix1_hw niccy; - struct isurf_hw isurf; - struct saphir_hw saphir; - struct bkm_hw ax; - struct gazel_hw gazel; - struct w6692_hw w6692; - struct hisax_d_if *hisax_d_if; - } hw; - int myid; - isdn_if iif; - spinlock_t statlock; - u_char *status_buf; - u_char *status_read; - u_char *status_write; - u_char *status_end; - u_char (*readisac) (struct IsdnCardState *, u_char); - void (*writeisac) (struct IsdnCardState *, u_char, u_char); - void (*readisacfifo) (struct IsdnCardState *, u_char *, int); - void (*writeisacfifo) (struct IsdnCardState *, u_char *, int); - u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char); - void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char); - void (*BC_Send_Data) (struct BCState *); - int (*cardmsg) (struct IsdnCardState *, int, void *); - void (*setstack_d) (struct PStack *, struct IsdnCardState *); - void (*DC_Close) (struct IsdnCardState *); - irq_handler_t irq_func; - int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); - struct Channel channel[2 + MAX_WAITING_CALLS]; - struct BCState bcs[2 + MAX_WAITING_CALLS]; - struct PStack *stlist; - struct sk_buff_head rq, sq; /* D-channel queues */ - int cardnr; - char *dlog; - int debug; - union { - struct isac_chip isac; - struct hfcd_chip hfcd; - struct hfcpci_chip hfcpci; - struct hfcsx_chip hfcsx; - struct w6692_chip w6692; - struct amd7930_chip amd7930; - struct icc_chip icc; - } dc; - u_char *rcvbuf; - int rcvidx; - struct sk_buff *tx_skb; - int tx_cnt; - u_long event; - struct work_struct tqueue; - struct timer_list dbusytimer; - unsigned int irq_cnt; -#ifdef ERROR_STATISTIC - int err_crc; - int err_tx; - int err_rx; -#endif -}; - - -#define schedule_event(s, ev) do { test_and_set_bit(ev, &s->event); schedule_work(&s->tqueue); } while (0) - -#define MON0_RX 1 -#define MON1_RX 2 -#define MON0_TX 4 -#define MON1_TX 8 - - -#ifdef ISDN_CHIP_ISAC -#undef ISDN_CHIP_ISAC -#endif - -#ifdef CONFIG_HISAX_16_0 -#define CARD_TELES0 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELES0 0 -#endif - -#ifdef CONFIG_HISAX_16_3 -#define CARD_TELES3 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELES3 0 -#endif - -#ifdef CONFIG_HISAX_TELESPCI -#define CARD_TELESPCI 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELESPCI 0 -#endif - -#ifdef CONFIG_HISAX_AVM_A1 -#define CARD_AVM_A1 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_AVM_A1 0 -#endif - -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA -#define CARD_AVM_A1_PCMCIA 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_AVM_A1_PCMCIA 0 -#endif - -#ifdef CONFIG_HISAX_FRITZPCI -#define CARD_FRITZPCI 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_FRITZPCI 0 -#endif - -#ifdef CONFIG_HISAX_ELSA -#define CARD_ELSA 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_ELSA 0 -#endif - -#ifdef CONFIG_HISAX_IX1MICROR2 -#define CARD_IX1MICROR2 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_IX1MICROR2 0 -#endif - -#ifdef CONFIG_HISAX_DIEHLDIVA -#define CARD_DIEHLDIVA 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_DIEHLDIVA 0 -#endif - -#ifdef CONFIG_HISAX_ASUSCOM -#define CARD_ASUSCOM 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_ASUSCOM 0 -#endif - -#ifdef CONFIG_HISAX_TELEINT -#define CARD_TELEINT 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELEINT 0 -#endif - -#ifdef CONFIG_HISAX_SEDLBAUER -#define CARD_SEDLBAUER 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_SEDLBAUER 0 -#endif - -#ifdef CONFIG_HISAX_SPORTSTER -#define CARD_SPORTSTER 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_SPORTSTER 0 -#endif - -#ifdef CONFIG_HISAX_MIC -#define CARD_MIC 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_MIC 0 -#endif - -#ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET_S 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_NETJET_S 0 -#endif - -#ifdef CONFIG_HISAX_HFCS -#define CARD_HFCS 1 -#else -#define CARD_HFCS 0 -#endif - -#ifdef CONFIG_HISAX_HFC_PCI -#define CARD_HFC_PCI 1 -#else -#define CARD_HFC_PCI 0 -#endif - -#ifdef CONFIG_HISAX_HFC_SX -#define CARD_HFC_SX 1 -#else -#define CARD_HFC_SX 0 -#endif - -#ifdef CONFIG_HISAX_NICCY -#define CARD_NICCY 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_NICCY 0 -#endif - -#ifdef CONFIG_HISAX_ISURF -#define CARD_ISURF 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_ISURF 0 -#endif - -#ifdef CONFIG_HISAX_S0BOX -#define CARD_S0BOX 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_S0BOX 0 -#endif - -#ifdef CONFIG_HISAX_HSTSAPHIR -#define CARD_HSTSAPHIR 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_HSTSAPHIR 0 -#endif - -#ifdef CONFIG_HISAX_BKM_A4T -#define CARD_BKM_A4T 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_BKM_A4T 0 -#endif - -#ifdef CONFIG_HISAX_SCT_QUADRO -#define CARD_SCT_QUADRO 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_SCT_QUADRO 0 -#endif - -#ifdef CONFIG_HISAX_GAZEL -#define CARD_GAZEL 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_GAZEL 0 -#endif - -#ifdef CONFIG_HISAX_W6692 -#define CARD_W6692 1 -#ifndef ISDN_CHIP_W6692 -#define ISDN_CHIP_W6692 1 -#endif -#else -#define CARD_W6692 0 -#endif - -#ifdef CONFIG_HISAX_NETJET_U -#define CARD_NETJET_U 1 -#ifndef ISDN_CHIP_ICC -#define ISDN_CHIP_ICC 1 -#endif -#ifndef HISAX_UINTERFACE -#define HISAX_UINTERFACE 1 -#endif -#else -#define CARD_NETJET_U 0 -#endif - -#ifdef CONFIG_HISAX_ENTERNOW_PCI -#define CARD_FN_ENTERNOW_PCI 1 -#else -#define CARD_FN_ENTERNOW_PCI 0 -#endif - -#define TEI_PER_CARD 1 - -/* L1 Debug */ -#define L1_DEB_WARN 0x01 -#define L1_DEB_INTSTAT 0x02 -#define L1_DEB_ISAC 0x04 -#define L1_DEB_ISAC_FIFO 0x08 -#define L1_DEB_HSCX 0x10 -#define L1_DEB_HSCX_FIFO 0x20 -#define L1_DEB_LAPD 0x40 -#define L1_DEB_IPAC 0x80 -#define L1_DEB_RECEIVE_FRAME 0x100 -#define L1_DEB_MONITOR 0x200 -#define DEB_DLOG_HEX 0x400 -#define DEB_DLOG_VERBOSE 0x800 - -#define L2FRAME_DEBUG - -#ifdef L2FRAME_DEBUG -extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); -#endif - -#include "hisax_cfg.h" - -void init_bcstate(struct IsdnCardState *cs, int bc); - -void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs); -void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st); -void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); - -void setstack_l1_B(struct PStack *st); - -void setstack_tei(struct PStack *st); -void setstack_manager(struct PStack *st); - -void setstack_isdnl2(struct PStack *st, char *debug_id); -void releasestack_isdnl2(struct PStack *st); -void setstack_transl2(struct PStack *st); -void releasestack_transl2(struct PStack *st); -void lli_writewakeup(struct PStack *st, int len); - -void setstack_l3dc(struct PStack *st, struct Channel *chanp); -void setstack_l3bc(struct PStack *st, struct Channel *chanp); -void releasestack_isdnl3(struct PStack *st); - -u_char *findie(u_char *p, int size, u_char ie, int wanted_set); -int getcallref(u_char *p); -int newcallref(void); - -int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); -void FsmFree(struct Fsm *fsm); -int FsmEvent(struct FsmInst *fi, int event, void *arg); -void FsmChangeState(struct FsmInst *fi, int newstate); -void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft); -int FsmAddTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmDelTimer(struct FsmTimer *ft, int where); -int jiftime(char *s, long mark); - -int HiSax_command(isdn_ctrl *ic); -int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb); -__printf(3, 4) -void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...); -__printf(3, 0) -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args); -void HiSax_reportcard(int cardnr, int sel); -int QuickHex(char *txt, u_char *p, int cnt); -void LogFrame(struct IsdnCardState *cs, u_char *p, int size); -void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); -void iecpy(u_char *dest, u_char *iestart, int ieoffset); -#endif /* __KERNEL__ */ - -/* - * Busywait delay for `jiffs' jiffies - */ -#define HZDELAY(jiffs) do { \ - int tout = jiffs; \ - \ - while (tout--) { \ - int loops = USEC_PER_SEC / HZ; \ - while (loops--) \ - udelay(1); \ - } \ - } while (0) - -int ll_run(struct IsdnCardState *cs, int addfeatures); -int CallcNew(void); -void CallcFree(void); -int CallcNewChan(struct IsdnCardState *cs); -void CallcFreeChan(struct IsdnCardState *cs); -int Isdnl1New(void); -void Isdnl1Free(void); -int Isdnl2New(void); -void Isdnl2Free(void); -int Isdnl3New(void); -void Isdnl3Free(void); -void init_tei(struct IsdnCardState *cs, int protocol); -void release_tei(struct IsdnCardState *cs); -char *HiSax_getrev(const char *revision); -int TeiNew(void); -void TeiFree(void); - -#ifdef CONFIG_PCI - -#include - -/* adaptation wrapper for old usage - * WARNING! This is unfit for use in a PCI hotplug environment, - * as the returned PCI device can disappear at any moment in time. - * Callers should be converted to use pci_get_device() instead. - */ -static inline struct pci_dev *hisax_find_pci_device(unsigned int vendor, - unsigned int device, - struct pci_dev *from) -{ - struct pci_dev *pdev; - - pci_dev_get(from); - pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); - pci_dev_put(pdev); - return pdev; -} - -#endif diff --git a/drivers/isdn/hisax/hisax_cfg.h b/drivers/isdn/hisax/hisax_cfg.h deleted file mode 100644 index 487dcfe9e718..000000000000 --- a/drivers/isdn/hisax/hisax_cfg.h +++ /dev/null @@ -1,66 +0,0 @@ -/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $ - * define of the basic HiSax configuration structures - * and pcmcia interface - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define ISDN_CTYPE_16_0 1 -#define ISDN_CTYPE_8_0 2 -#define ISDN_CTYPE_16_3 3 -#define ISDN_CTYPE_PNP 4 -#define ISDN_CTYPE_A1 5 -#define ISDN_CTYPE_ELSA 6 -#define ISDN_CTYPE_ELSA_PNP 7 -#define ISDN_CTYPE_TELESPCMCIA 8 -#define ISDN_CTYPE_IX1MICROR2 9 -#define ISDN_CTYPE_ELSA_PCMCIA 10 -#define ISDN_CTYPE_DIEHLDIVA 11 -#define ISDN_CTYPE_ASUSCOM 12 -#define ISDN_CTYPE_TELEINT 13 -#define ISDN_CTYPE_TELES3C 14 -#define ISDN_CTYPE_SEDLBAUER 15 -#define ISDN_CTYPE_SPORTSTER 16 -#define ISDN_CTYPE_MIC 17 -#define ISDN_CTYPE_ELSA_PCI 18 -#define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET_S 20 -#define ISDN_CTYPE_TELESPCI 21 -#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 -#define ISDN_CTYPE_AMD7930 23 -#define ISDN_CTYPE_NICCY 24 -#define ISDN_CTYPE_S0BOX 25 -#define ISDN_CTYPE_A1_PCMCIA 26 -#define ISDN_CTYPE_FRITZPCI 27 -#define ISDN_CTYPE_SEDLBAUER_FAX 28 -#define ISDN_CTYPE_ISURF 29 -#define ISDN_CTYPE_ACERP10 30 -#define ISDN_CTYPE_HSTSAPHIR 31 -#define ISDN_CTYPE_BKM_A4T 32 -#define ISDN_CTYPE_SCT_QUADRO 33 -#define ISDN_CTYPE_GAZEL 34 -#define ISDN_CTYPE_HFC_PCI 35 -#define ISDN_CTYPE_W6692 36 -#define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_NETJET_U 38 -#define ISDN_CTYPE_HFC_SP_PCMCIA 39 -#define ISDN_CTYPE_DYNAMIC 40 -#define ISDN_CTYPE_ENTERNOW 41 -#define ISDN_CTYPE_COUNT 41 - -typedef struct IsdnCardState IsdnCardState_t; -typedef struct IsdnCard IsdnCard_t; - -struct IsdnCard { - int typ; - int protocol; /* EDSS1, 1TR6 or NI1 */ - unsigned long para[4]; - IsdnCardState_t *cs; -}; - -typedef int (*hisax_setup_func_t)(struct IsdnCard *card); - -extern void HiSax_closecard(int); -extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *); diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h deleted file mode 100644 index 7b3093d0856a..000000000000 --- a/drivers/isdn/hisax/hisax_debug.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Common debugging macros for use with the hisax driver - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen - * 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * How to use: - * - * Before including this file, you need to - * #define __debug_variable my_debug - * where my_debug is a variable in your code which - * determines the debug bitmask. - * - * If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing - * - */ - -#ifndef __HISAX_DEBUG_H__ -#define __HISAX_DEBUG_H__ - - -#ifdef CONFIG_HISAX_DEBUG - -#define DBG(level, format, arg...) do { \ - if (level & __debug_variable) \ - printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ - } while (0) - -#define DBG_PACKET(level, data, count) \ - if (level & __debug_variable) dump_packet(__func__, data, count) - -#define DBG_SKB(level, skb) \ - if ((level & __debug_variable) && skb) dump_packet(__func__, skb->data, skb->len) - - -static void __attribute__((unused)) -dump_packet(const char *name, const u_char *data, int pkt_len) -{ -#define DUMP_HDR_SIZE 20 -#define DUMP_TLR_SIZE 8 - if (pkt_len) { - int i, len1, len2; - - printk(KERN_DEBUG "%s: length=%d,data=", name, pkt_len); - - if (pkt_len > DUMP_HDR_SIZE + DUMP_TLR_SIZE) { - len1 = DUMP_HDR_SIZE; - len2 = DUMP_TLR_SIZE; - } else { - len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len; - len2 = 0; - } - for (i = 0; i < len1; ++i) { - printk("%.2x", data[i]); - } - if (len2) { - printk(".."); - for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) { - printk("%.2x", data[i]); - } - } - printk("\n"); - } -#undef DUMP_HDR_SIZE -#undef DUMP_TLR_SIZE -} - -#else - -#define DBG(level, format, arg...) do {} while (0) -#define DBG_PACKET(level, data, count) do {} while (0) -#define DBG_SKB(level, skb) do {} while (0) - -#endif - -#endif diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c deleted file mode 100644 index 7a7137d8664b..000000000000 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski - * 2001 by Karsten Keil - * - * based upon Karsten Keil's original avm_pci.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Wizard Computersysteme GmbH, Bremervoerde and - * SoHaNet Technology GmbH, Berlin - * for supporting the development of this driver - */ - - -/* TODO: - * - * o POWER PC - * o clean up debugging - * o tx_skb at PH_DEACTIVATE time - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "hisax_fcpcipnp.h" - -// debugging cruft -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 0; -/* static int hdlcfifosize = 32; */ -module_param(debug, int, 0); -/* module_param(hdlcfifosize, int, 0); */ -#endif - -MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); -MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver"); - -static const struct pci_device_id fcpci_ids[] = { - { .vendor = PCI_VENDOR_ID_AVM, - .device = PCI_DEVICE_ID_AVM_A1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) "Fritz!Card PCI", - }, - { .vendor = PCI_VENDOR_ID_AVM, - .device = PCI_DEVICE_ID_AVM_A1_V2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) "Fritz!Card PCI v2" }, - {} -}; - -MODULE_DEVICE_TABLE(pci, fcpci_ids); - -#ifdef CONFIG_PNP -static struct pnp_device_id fcpnp_ids[] = { - { - .id = "AVM0900", - .driver_data = (unsigned long) "Fritz!Card PnP", - }, - { .id = "" } -}; - -MODULE_DEVICE_TABLE(pnp, fcpnp_ids); -#endif - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); -MODULE_LICENSE("GPL"); - -// ---------------------------------------------------------------------- - -#define AVM_INDEX 0x04 -#define AVM_DATA 0x10 - -#define AVM_IDX_HDLC_1 0x00 -#define AVM_IDX_HDLC_2 0x01 -#define AVM_IDX_ISAC_FIFO 0x02 -#define AVM_IDX_ISAC_REG_LOW 0x04 -#define AVM_IDX_ISAC_REG_HIGH 0x06 - -#define AVM_STATUS0 0x02 - -#define AVM_STATUS0_IRQ_ISAC 0x01 -#define AVM_STATUS0_IRQ_HDLC 0x02 -#define AVM_STATUS0_IRQ_TIMER 0x04 -#define AVM_STATUS0_IRQ_MASK 0x07 - -#define AVM_STATUS0_RESET 0x01 -#define AVM_STATUS0_DIS_TIMER 0x02 -#define AVM_STATUS0_RES_TIMER 0x04 -#define AVM_STATUS0_ENA_IRQ 0x08 -#define AVM_STATUS0_TESTBIT 0x10 - -#define AVM_STATUS1 0x03 -#define AVM_STATUS1_ENA_IOM 0x80 - -#define HDLC_FIFO 0x0 -#define HDLC_STATUS 0x4 -#define HDLC_CTRL 0x4 - -#define HDLC_MODE_ITF_FLG 0x01 -#define HDLC_MODE_TRANS 0x02 -#define HDLC_MODE_CCR_7 0x04 -#define HDLC_MODE_CCR_16 0x08 -#define HDLC_MODE_TESTLOOP 0x80 - -#define HDLC_INT_XPR 0x80 -#define HDLC_INT_XDU 0x40 -#define HDLC_INT_RPR 0x20 -#define HDLC_INT_MASK 0xE0 - -#define HDLC_STAT_RME 0x01 -#define HDLC_STAT_RDO 0x10 -#define HDLC_STAT_CRCVFRRAB 0x0E -#define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK 0xff00 - -#define HDLC_CMD_XRS 0x80 -#define HDLC_CMD_XME 0x01 -#define HDLC_CMD_RRS 0x20 -#define HDLC_CMD_XML_MASK 0xff00 - -#define AVM_HDLC_FIFO_1 0x10 -#define AVM_HDLC_FIFO_2 0x18 - -#define AVM_HDLC_STATUS_1 0x14 -#define AVM_HDLC_STATUS_2 0x1c - -#define AVM_ISACSX_INDEX 0x04 -#define AVM_ISACSX_DATA 0x08 - -// ---------------------------------------------------------------------- -// Fritz!PCI - -static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char idx = (offset > 0x2f) ? - AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW; - unsigned char val; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(idx, adapter->io + AVM_INDEX); - val = inb(adapter->io + AVM_DATA + (offset & 0xf)); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - DBG(0x1000, " port %#x, value %#x", - offset, val); - return val; -} - -static void fcpci_write_isac(struct isac *isac, unsigned char offset, - unsigned char value) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char idx = (offset > 0x2f) ? - AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW; - unsigned long flags; - - DBG(0x1000, " port %#x, value %#x", - offset, value); - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(idx, adapter->io + AVM_INDEX); - outb(value, adapter->io + AVM_DATA + (offset & 0xf)); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci_read_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX); - insb(adapter->io + AVM_DATA, data, size); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci_write_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX); - outsb(adapter->io + AVM_DATA, data, size); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr) -{ - u32 val; - int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(idx, adapter->io + AVM_INDEX); - val = inl(adapter->io + AVM_DATA + HDLC_STATUS); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - return val; -} - -static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - - DBG(0x40, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->ctrl.ctrl); - - outl(idx, adapter->io + AVM_INDEX); - outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL); -} - -static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - __fcpci_write_ctrl(bcs, which); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -// ---------------------------------------------------------------------- -// Fritz!PCI v2 - -static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char val; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(offset, adapter->io + AVM_ISACSX_INDEX); - val = inl(adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - DBG(0x1000, " port %#x, value %#x", - offset, val); - - return val; -} - -static void fcpci2_write_isac(struct isac *isac, unsigned char offset, - unsigned char value) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned long flags; - - DBG(0x1000, " port %#x, value %#x", - offset, value); - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(offset, adapter->io + AVM_ISACSX_INDEX); - outl(value, adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - int i; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(0, adapter->io + AVM_ISACSX_INDEX); - for (i = 0; i < size; i++) - data[i] = inl(adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - int i; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(0, adapter->io + AVM_ISACSX_INDEX); - for (i = 0; i < size; i++) - outl(data[i], adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr) -{ - int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1; - - return inl(adapter->io + offset); -} - -static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1; - - DBG(0x40, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->ctrl.ctrl); - - outl(bcs->ctrl.ctrl, adapter->io + offset); -} - -// ---------------------------------------------------------------------- -// Fritz!PnP (ISAC access as for Fritz!PCI) - -static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr) -{ - unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - u32 val; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(idx, adapter->io + AVM_INDEX); - val = inb(adapter->io + AVM_DATA + HDLC_STATUS); - if (val & HDLC_INT_RPR) - val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8; - spin_unlock_irqrestore(&adapter->hw_lock, flags); - return val; -} - -static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - - DBG(0x40, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->ctrl.ctrl); - - outb(idx, adapter->io + AVM_INDEX); - if (which & 4) - outb(bcs->ctrl.sr.mode, - adapter->io + AVM_DATA + HDLC_STATUS + 2); - if (which & 2) - outb(bcs->ctrl.sr.xml, - adapter->io + AVM_DATA + HDLC_STATUS + 1); - if (which & 1) - outb(bcs->ctrl.sr.cmd, - adapter->io + AVM_DATA + HDLC_STATUS + 0); -} - -static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - __fcpnp_write_ctrl(bcs, which); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -// ---------------------------------------------------------------------- - -static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; - - DBG(2, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -static void hdlc_fill_fifo(struct fritz_bcs *bcs) -{ - struct fritz_adapter *adapter = bcs->adapter; - struct sk_buff *skb = bcs->tx_skb; - int count; - unsigned long flags; - unsigned char *p; - - DBG(0x40, "hdlc_fill_fifo"); - - BUG_ON(skb->len == 0); - - bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (bcs->tx_skb->len > bcs->fifo_size) { - count = bcs->fifo_size; - } else { - count = bcs->tx_skb->len; - if (bcs->mode != L1_MODE_TRANS) - bcs->ctrl.sr.cmd |= HDLC_CMD_XME; - } - DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len); - p = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt += count; - bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count); - - switch (adapter->type) { - case AVM_FRITZ_PCI: - spin_lock_irqsave(&adapter->hw_lock, flags); - // sets the correct AVM_INDEX, too - __fcpci_write_ctrl(bcs, 3); - outsl(adapter->io + AVM_DATA + HDLC_FIFO, - p, (count + 3) / 4); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - break; - case AVM_FRITZ_PCIV2: - fcpci2_write_ctrl(bcs, 3); - outsl(adapter->io + - (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1), - p, (count + 3) / 4); - break; - case AVM_FRITZ_PNP: - spin_lock_irqsave(&adapter->hw_lock, flags); - // sets the correct AVM_INDEX, too - __fcpnp_write_ctrl(bcs, 3); - outsb(adapter->io + AVM_DATA, p, count); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - break; - } -} - -static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned char *p; - unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - - DBG(0x10, "hdlc_empty_fifo %d", count); - if (bcs->rcvidx + count > HSCX_BUFMAX) { - DBG(0x10, "hdlc_empty_fifo: incoming packet too large"); - return; - } - p = bcs->rcvbuf + bcs->rcvidx; - bcs->rcvidx += count; - switch (adapter->type) { - case AVM_FRITZ_PCI: - spin_lock(&adapter->hw_lock); - outl(idx, adapter->io + AVM_INDEX); - insl(adapter->io + AVM_DATA + HDLC_FIFO, - p, (count + 3) / 4); - spin_unlock(&adapter->hw_lock); - break; - case AVM_FRITZ_PCIV2: - insl(adapter->io + - (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1), - p, (count + 3) / 4); - break; - case AVM_FRITZ_PNP: - spin_lock(&adapter->hw_lock); - outb(idx, adapter->io + AVM_INDEX); - insb(adapter->io + AVM_DATA, p, count); - spin_unlock(&adapter->hw_lock); - break; - } -} - -static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat) -{ - struct fritz_adapter *adapter = bcs->adapter; - struct sk_buff *skb; - int len; - - if (stat & HDLC_STAT_RDO) { - DBG(0x10, "RDO"); - bcs->ctrl.sr.xml = 0; - bcs->ctrl.sr.cmd |= HDLC_CMD_RRS; - adapter->write_ctrl(bcs, 1); - bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS; - adapter->write_ctrl(bcs, 1); - bcs->rcvidx = 0; - return; - } - - len = (stat & HDLC_STAT_RML_MASK) >> 8; - if (len == 0) - len = bcs->fifo_size; - - hdlc_empty_fifo(bcs, len); - - if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { - if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) || - (bcs->mode == L1_MODE_TRANS)) { - skb = dev_alloc_skb(bcs->rcvidx); - if (!skb) { - printk(KERN_WARNING "HDLC: receive out of memory\n"); - } else { - skb_put_data(skb, bcs->rcvbuf, bcs->rcvidx); - DBG_SKB(1, skb); - B_L1L2(bcs, PH_DATA | INDICATION, skb); - } - bcs->rcvidx = 0; - } else { - DBG(0x10, "ch%d invalid frame %#x", - bcs->channel, stat); - bcs->rcvidx = 0; - } - } -} - -static inline void hdlc_xdu_irq(struct fritz_bcs *bcs) -{ - struct fritz_adapter *adapter = bcs->adapter; - - - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - bcs->ctrl.sr.xml = 0; - bcs->ctrl.sr.cmd |= HDLC_CMD_XRS; - adapter->write_ctrl(bcs, 1); - bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS; - - if (!bcs->tx_skb) { - DBG(0x10, "XDU without skb"); - adapter->write_ctrl(bcs, 1); - return; - } - /* only hdlc restarts the frame, transparent mode must continue */ - if (bcs->mode == L1_MODE_HDLC) { - skb_push(bcs->tx_skb, bcs->tx_cnt); - bcs->tx_cnt = 0; - } -} - -static inline void hdlc_xpr_irq(struct fritz_bcs *bcs) -{ - struct sk_buff *skb; - - skb = bcs->tx_skb; - if (!skb) - return; - - if (skb->len) { - hdlc_fill_fifo(bcs); - return; - } - bcs->tx_cnt = 0; - bcs->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long)skb->truesize); - dev_kfree_skb_irq(skb); -} - -static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat) -{ - DBG(0x10, "ch%d stat %#x", bcs->channel, stat); - if (stat & HDLC_INT_RPR) { - DBG(0x10, "RPR"); - hdlc_rpr_irq(bcs, stat); - } - if (stat & HDLC_INT_XDU) { - DBG(0x10, "XDU"); - hdlc_xdu_irq(bcs); - hdlc_xpr_irq(bcs); - return; - } - if (stat & HDLC_INT_XPR) { - DBG(0x10, "XPR"); - hdlc_xpr_irq(bcs); - } -} - -static inline void hdlc_irq(struct fritz_adapter *adapter) -{ - int nr; - u32 stat; - - for (nr = 0; nr < 2; nr++) { - stat = adapter->read_hdlc_status(adapter, nr); - DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat); - if (stat & HDLC_INT_MASK) - hdlc_irq_one(&adapter->bcs[nr], stat); - } -} - -static void modehdlc(struct fritz_bcs *bcs, int mode) -{ - struct fritz_adapter *adapter = bcs->adapter; - - DBG(0x40, "hdlc %c mode %d --> %d", - 'A' + bcs->channel, bcs->mode, mode); - - if (bcs->mode == mode) - return; - - bcs->fifo_size = 32; - bcs->ctrl.ctrl = 0; - bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - switch (mode) { - case L1_MODE_NULL: - bcs->ctrl.sr.mode = HDLC_MODE_TRANS; - adapter->write_ctrl(bcs, 5); - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - bcs->rcvidx = 0; - bcs->tx_cnt = 0; - bcs->tx_skb = NULL; - if (mode == L1_MODE_TRANS) { - bcs->ctrl.sr.mode = HDLC_MODE_TRANS; - } else { - bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG; - } - adapter->write_ctrl(bcs, 5); - bcs->ctrl.sr.cmd = HDLC_CMD_XRS; - adapter->write_ctrl(bcs, 1); - bcs->ctrl.sr.cmd = 0; - break; - } - bcs->mode = mode; -} - -static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct fritz_bcs *bcs = ifc->priv; - struct sk_buff *skb = arg; - int mode; - - DBG(0x10, "pr %#x", pr); - - switch (pr) { - case PH_DATA | REQUEST: - BUG_ON(bcs->tx_skb); - bcs->tx_skb = skb; - DBG_SKB(1, skb); - hdlc_fill_fifo(bcs); - break; - case PH_ACTIVATE | REQUEST: - mode = (long) arg; - DBG(4, "B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); - modehdlc(bcs, mode); - B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); - break; - case PH_DEACTIVATE | REQUEST: - DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); - modehdlc(bcs, L1_MODE_NULL); - B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); - break; - } -} - -// ---------------------------------------------------------------------- - -static irqreturn_t -fcpci2_irq(int intno, void *dev) -{ - struct fritz_adapter *adapter = dev; - unsigned char val; - - val = inb(adapter->io + AVM_STATUS0); - if (!(val & AVM_STATUS0_IRQ_MASK)) - /* hopefully a shared IRQ reqest */ - return IRQ_NONE; - DBG(2, "STATUS0 %#x", val); - if (val & AVM_STATUS0_IRQ_ISAC) - isacsx_irq(&adapter->isac); - if (val & AVM_STATUS0_IRQ_HDLC) - hdlc_irq(adapter); - if (val & AVM_STATUS0_IRQ_ISAC) - isacsx_irq(&adapter->isac); - return IRQ_HANDLED; -} - -static irqreturn_t -fcpci_irq(int intno, void *dev) -{ - struct fritz_adapter *adapter = dev; - unsigned char sval; - - sval = inb(adapter->io + 2); - if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) - /* possibly a shared IRQ reqest */ - return IRQ_NONE; - DBG(2, "sval %#x", sval); - if (!(sval & AVM_STATUS0_IRQ_ISAC)) - isac_irq(&adapter->isac); - - if (!(sval & AVM_STATUS0_IRQ_HDLC)) - hdlc_irq(adapter); - return IRQ_HANDLED; -} - -// ---------------------------------------------------------------------- - -static inline void fcpci2_init(struct fritz_adapter *adapter) -{ - outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0); - outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0); - -} - -static inline void fcpci_init(struct fritz_adapter *adapter) -{ - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | - AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0); - - outb(AVM_STATUS1_ENA_IOM | adapter->irq, - adapter->io + AVM_STATUS1); - mdelay(10); -} - -// ---------------------------------------------------------------------- - -static int fcpcipnp_setup(struct fritz_adapter *adapter) -{ - u32 val = 0; - int retval; - - DBG(1, ""); - - isac_init(&adapter->isac); // FIXME is this okay now - - retval = -EBUSY; - if (!request_region(adapter->io, 32, "fcpcipnp")) - goto err; - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - case AVM_FRITZ_PCI: - val = inl(adapter->io); - break; - case AVM_FRITZ_PNP: - val = inb(adapter->io); - val |= inb(adapter->io + 1) << 8; - break; - } - - DBG(1, "stat %#x Class %X Rev %d", - val, val & 0xff, (val >> 8) & 0xff); - - spin_lock_init(&adapter->hw_lock); - adapter->isac.priv = adapter; - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - adapter->isac.read_isac = &fcpci2_read_isac; - adapter->isac.write_isac = &fcpci2_write_isac; - adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo; - - adapter->read_hdlc_status = &fcpci2_read_hdlc_status; - adapter->write_ctrl = &fcpci2_write_ctrl; - break; - case AVM_FRITZ_PCI: - adapter->isac.read_isac = &fcpci_read_isac; - adapter->isac.write_isac = &fcpci_write_isac; - adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; - - adapter->read_hdlc_status = &fcpci_read_hdlc_status; - adapter->write_ctrl = &fcpci_write_ctrl; - break; - case AVM_FRITZ_PNP: - adapter->isac.read_isac = &fcpci_read_isac; - adapter->isac.write_isac = &fcpci_write_isac; - adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; - - adapter->read_hdlc_status = &fcpnp_read_hdlc_status; - adapter->write_ctrl = &fcpnp_write_ctrl; - break; - } - - // Reset - outb(0, adapter->io + AVM_STATUS0); - mdelay(10); - outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0); - mdelay(10); - outb(0, adapter->io + AVM_STATUS0); - mdelay(10); - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED, - "fcpcipnp", adapter); - break; - case AVM_FRITZ_PCI: - retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED, - "fcpcipnp", adapter); - break; - case AVM_FRITZ_PNP: - retval = request_irq(adapter->irq, fcpci_irq, 0, - "fcpcipnp", adapter); - break; - } - if (retval) - goto err_region; - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - fcpci2_init(adapter); - isacsx_setup(&adapter->isac); - break; - case AVM_FRITZ_PCI: - case AVM_FRITZ_PNP: - fcpci_init(adapter); - isac_setup(&adapter->isac); - break; - } - val = adapter->read_hdlc_status(adapter, 0); - DBG(0x20, "HDLC A STA %x", val); - val = adapter->read_hdlc_status(adapter, 1); - DBG(0x20, "HDLC B STA %x", val); - - adapter->bcs[0].mode = -1; - adapter->bcs[1].mode = -1; - modehdlc(&adapter->bcs[0], L1_MODE_NULL); - modehdlc(&adapter->bcs[1], L1_MODE_NULL); - - return 0; - -err_region: - release_region(adapter->io, 32); -err: - return retval; -} - -static void fcpcipnp_release(struct fritz_adapter *adapter) -{ - DBG(1, ""); - - outb(0, adapter->io + AVM_STATUS0); - free_irq(adapter->irq, adapter); - release_region(adapter->io, 32); -} - -// ---------------------------------------------------------------------- - -static struct fritz_adapter *new_adapter(void) -{ - struct fritz_adapter *adapter; - struct hisax_b_if *b_if[2]; - int i; - - adapter = kzalloc(sizeof(struct fritz_adapter), GFP_KERNEL); - if (!adapter) - return NULL; - - adapter->isac.hisax_d_if.owner = THIS_MODULE; - adapter->isac.hisax_d_if.ifc.priv = &adapter->isac; - adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1; - - for (i = 0; i < 2; i++) { - adapter->bcs[i].adapter = adapter; - adapter->bcs[i].channel = i; - adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; - adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1; - } - - for (i = 0; i < 2; i++) - b_if[i] = &adapter->bcs[i].b_if; - - if (hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp", - protocol) != 0) { - kfree(adapter); - adapter = NULL; - } - - return adapter; -} - -static void delete_adapter(struct fritz_adapter *adapter) -{ - hisax_unregister(&adapter->isac.hisax_d_if); - kfree(adapter); -} - -static int fcpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct fritz_adapter *adapter; - int retval; - - retval = -ENOMEM; - adapter = new_adapter(); - if (!adapter) - goto err; - - pci_set_drvdata(pdev, adapter); - - if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) - adapter->type = AVM_FRITZ_PCIV2; - else - adapter->type = AVM_FRITZ_PCI; - - retval = pci_enable_device(pdev); - if (retval) - goto err_free; - - adapter->io = pci_resource_start(pdev, 1); - adapter->irq = pdev->irq; - - printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n", - (char *) ent->driver_data, pci_name(pdev)); - - retval = fcpcipnp_setup(adapter); - if (retval) - goto err_free; - - return 0; - -err_free: - delete_adapter(adapter); -err: - return retval; -} - -#ifdef CONFIG_PNP -static int fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) -{ - struct fritz_adapter *adapter; - int retval; - - if (!pdev) - return (-ENODEV); - - retval = -ENOMEM; - adapter = new_adapter(); - if (!adapter) - goto err; - - pnp_set_drvdata(pdev, adapter); - - adapter->type = AVM_FRITZ_PNP; - - pnp_disable_dev(pdev); - retval = pnp_activate_dev(pdev); - if (retval < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__, - (char *)dev_id->driver_data, retval); - goto err_free; - } - adapter->io = pnp_port_start(pdev, 0); - adapter->irq = pnp_irq(pdev, 0); - if (!adapter->io || adapter->irq == -1) - goto err_free; - - printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n", - (char *) dev_id->driver_data, adapter->io, adapter->irq); - - retval = fcpcipnp_setup(adapter); - if (retval) - goto err_free; - - return 0; - -err_free: - delete_adapter(adapter); -err: - return retval; -} - -static void fcpnp_remove(struct pnp_dev *pdev) -{ - struct fritz_adapter *adapter = pnp_get_drvdata(pdev); - - if (adapter) { - fcpcipnp_release(adapter); - delete_adapter(adapter); - } - pnp_disable_dev(pdev); -} - -static struct pnp_driver fcpnp_driver = { - .name = "fcpnp", - .probe = fcpnp_probe, - .remove = fcpnp_remove, - .id_table = fcpnp_ids, -}; -#endif - -static void fcpci_remove(struct pci_dev *pdev) -{ - struct fritz_adapter *adapter = pci_get_drvdata(pdev); - - fcpcipnp_release(adapter); - pci_disable_device(pdev); - delete_adapter(adapter); -} - -static struct pci_driver fcpci_driver = { - .name = "fcpci", - .probe = fcpci_probe, - .remove = fcpci_remove, - .id_table = fcpci_ids, -}; - -static int __init hisax_fcpcipnp_init(void) -{ - int retval; - - printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n"); - - retval = pci_register_driver(&fcpci_driver); - if (retval) - return retval; -#ifdef CONFIG_PNP - retval = pnp_register_driver(&fcpnp_driver); - if (retval < 0) { - pci_unregister_driver(&fcpci_driver); - return retval; - } -#endif - return 0; -} - -static void __exit hisax_fcpcipnp_exit(void) -{ -#ifdef CONFIG_PNP - pnp_unregister_driver(&fcpnp_driver); -#endif - pci_unregister_driver(&fcpci_driver); -} - -module_init(hisax_fcpcipnp_init); -module_exit(hisax_fcpcipnp_exit); diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h deleted file mode 100644 index 1f64e9937aa1..000000000000 --- a/drivers/isdn/hisax/hisax_fcpcipnp.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include "hisax_if.h" -#include "hisax_isac.h" -#include - -#define HSCX_BUFMAX 4096 - -enum { - AVM_FRITZ_PCI, - AVM_FRITZ_PNP, - AVM_FRITZ_PCIV2, -}; - -struct hdlc_stat_reg { -#ifdef __BIG_ENDIAN - u_char fill; - u_char mode; - u_char xml; - u_char cmd; -#else - u_char cmd; - u_char xml; - u_char mode; - u_char fill; -#endif -} __attribute__((packed)); - -struct fritz_bcs { - struct hisax_b_if b_if; - struct fritz_adapter *adapter; - int mode; - int channel; - - union { - u_int ctrl; - struct hdlc_stat_reg sr; - } ctrl; - u_int stat; - int rcvidx; - int fifo_size; - u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */ - - int tx_cnt; /* B-Channel transmit counter */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ -}; - -struct fritz_adapter { - int type; - spinlock_t hw_lock; - unsigned int io; - unsigned int irq; - struct isac isac; - - struct fritz_bcs bcs[2]; - - u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr); - void (*write_ctrl) (struct fritz_bcs *bcs, int which); -}; diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h deleted file mode 100644 index 7098d6bd5ff2..000000000000 --- a/drivers/isdn/hisax/hisax_if.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Interface between low level (hardware) drivers and - * HiSax protocol stack - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __HISAX_IF_H__ -#define __HISAX_IF_H__ - -#include - -#define REQUEST 0 -#define CONFIRM 1 -#define INDICATION 2 -#define RESPONSE 3 - -#define PH_ACTIVATE 0x0100 -#define PH_DEACTIVATE 0x0110 -#define PH_DATA 0x0120 -#define PH_PULL 0x0130 -#define PH_DATA_E 0x0140 - -#define L1_MODE_NULL 0 -#define L1_MODE_TRANS 1 -#define L1_MODE_HDLC 2 -#define L1_MODE_EXTRN 3 -#define L1_MODE_HDLC_56K 4 -#define L1_MODE_MODEM 7 -#define L1_MODE_V32 8 -#define L1_MODE_FAX 9 - -struct hisax_if { - void *priv; // private to driver - void (*l1l2)(struct hisax_if *, int pr, void *arg); - void (*l2l1)(struct hisax_if *, int pr, void *arg); -}; - -struct hisax_b_if { - struct hisax_if ifc; - - // private to hisax - struct BCState *bcs; -}; - -struct hisax_d_if { - struct hisax_if ifc; - - // private to hisax - struct module *owner; - struct IsdnCardState *cs; - struct hisax_b_if *b_if[2]; - struct sk_buff_head erq; - unsigned long ph_state; -}; - -int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[], - char *name, int protocol); -void hisax_unregister(struct hisax_d_if *hisax_if); - -#endif diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c deleted file mode 100644 index 0f36375478c5..000000000000 --- a/drivers/isdn/hisax/hisax_isac.c +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Driver for ISAC-S and ISAC-SX - * ISDN Subscriber Access Controller for Terminals - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski - * 2001 by Karsten Keil - * - * based upon Karsten Keil's original isac.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Wizard Computersysteme GmbH, Bremervoerde and - * SoHaNet Technology GmbH, Berlin - * for supporting the development of this driver - */ - -/* TODO: - * specifically handle level vs edge triggered? - */ - -#include -#include -#include -#include -#include "hisax_isac.h" - -// debugging cruft - -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 1; -module_param(debug, int, 0); - -static char *ISACVer[] = { - "2086/2186 V1.1", - "2085 B1", - "2085 B2", - "2085 V2.3" -}; -#endif - -MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); -MODULE_DESCRIPTION("ISAC/ISAC-SX driver"); -MODULE_LICENSE("GPL"); - -#define DBG_WARN 0x0001 -#define DBG_IRQ 0x0002 -#define DBG_L1M 0x0004 -#define DBG_PR 0x0008 -#define DBG_RFIFO 0x0100 -#define DBG_RPACKET 0x0200 -#define DBG_XFIFO 0x1000 -#define DBG_XPACKET 0x2000 - -// we need to distinguish ISAC-S and ISAC-SX -#define TYPE_ISAC 0x00 -#define TYPE_ISACSX 0x01 - -// registers etc. -#define ISAC_MASK 0x20 -#define ISAC_ISTA 0x20 -#define ISAC_ISTA_EXI 0x01 -#define ISAC_ISTA_SIN 0x02 -#define ISAC_ISTA_CISQ 0x04 -#define ISAC_ISTA_XPR 0x10 -#define ISAC_ISTA_RSC 0x20 -#define ISAC_ISTA_RPF 0x40 -#define ISAC_ISTA_RME 0x80 - -#define ISAC_STAR 0x21 -#define ISAC_CMDR 0x21 -#define ISAC_CMDR_XRES 0x01 -#define ISAC_CMDR_XME 0x02 -#define ISAC_CMDR_XTF 0x08 -#define ISAC_CMDR_RRES 0x40 -#define ISAC_CMDR_RMC 0x80 - -#define ISAC_EXIR 0x24 -#define ISAC_EXIR_MOS 0x04 -#define ISAC_EXIR_XDU 0x40 -#define ISAC_EXIR_XMR 0x80 - -#define ISAC_ADF2 0x39 -#define ISAC_SPCR 0x30 -#define ISAC_ADF1 0x38 - -#define ISAC_CIR0 0x31 -#define ISAC_CIX0 0x31 -#define ISAC_CIR0_CIC0 0x02 -#define ISAC_CIR0_CIC1 0x01 - -#define ISAC_CIR1 0x33 -#define ISAC_CIX1 0x33 -#define ISAC_STCR 0x37 -#define ISAC_MODE 0x22 - -#define ISAC_RSTA 0x27 -#define ISAC_RSTA_RDO 0x40 -#define ISAC_RSTA_CRC 0x20 -#define ISAC_RSTA_RAB 0x10 - -#define ISAC_RBCL 0x25 -#define ISAC_RBCH 0x2A -#define ISAC_TIMR 0x23 -#define ISAC_SQXR 0x3b -#define ISAC_MOSR 0x3a -#define ISAC_MOCR 0x3a -#define ISAC_MOR0 0x32 -#define ISAC_MOX0 0x32 -#define ISAC_MOR1 0x34 -#define ISAC_MOX1 0x34 - -#define ISAC_RBCH_XAC 0x80 - -#define ISAC_CMD_TIM 0x0 -#define ISAC_CMD_RES 0x1 -#define ISAC_CMD_SSP 0x2 -#define ISAC_CMD_SCP 0x3 -#define ISAC_CMD_AR8 0x8 -#define ISAC_CMD_AR10 0x9 -#define ISAC_CMD_ARL 0xa -#define ISAC_CMD_DI 0xf - -#define ISACSX_MASK 0x60 -#define ISACSX_ISTA 0x60 -#define ISACSX_ISTA_ICD 0x01 -#define ISACSX_ISTA_CIC 0x10 - -#define ISACSX_MASKD 0x20 -#define ISACSX_ISTAD 0x20 -#define ISACSX_ISTAD_XDU 0x04 -#define ISACSX_ISTAD_XMR 0x08 -#define ISACSX_ISTAD_XPR 0x10 -#define ISACSX_ISTAD_RFO 0x20 -#define ISACSX_ISTAD_RPF 0x40 -#define ISACSX_ISTAD_RME 0x80 - -#define ISACSX_CMDRD 0x21 -#define ISACSX_CMDRD_XRES 0x01 -#define ISACSX_CMDRD_XME 0x02 -#define ISACSX_CMDRD_XTF 0x08 -#define ISACSX_CMDRD_RRES 0x40 -#define ISACSX_CMDRD_RMC 0x80 - -#define ISACSX_MODED 0x22 - -#define ISACSX_RBCLD 0x26 - -#define ISACSX_RSTAD 0x28 -#define ISACSX_RSTAD_RAB 0x10 -#define ISACSX_RSTAD_CRC 0x20 -#define ISACSX_RSTAD_RDO 0x40 -#define ISACSX_RSTAD_VFR 0x80 - -#define ISACSX_CIR0 0x2e -#define ISACSX_CIR0_CIC0 0x08 -#define ISACSX_CIX0 0x2e - -#define ISACSX_TR_CONF0 0x30 - -#define ISACSX_TR_CONF2 0x32 - -static struct Fsm l1fsm; - -enum { - ST_L1_RESET, - ST_L1_F3_PDOWN, - ST_L1_F3_PUP, - ST_L1_F3_PEND_DEACT, - ST_L1_F4, - ST_L1_F5, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1_STATE_COUNT (ST_L1_F8 + 1) - -static char *strL1State[] = -{ - "ST_L1_RESET", - "ST_L1_F3_PDOWN", - "ST_L1_F3_PUP", - "ST_L1_F3_PEND_DEACT", - "ST_L1_F4", - "ST_L1_F5", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -enum { - EV_PH_DR, // 0000 - EV_PH_RES, // 0001 - EV_PH_TMA, // 0010 - EV_PH_SLD, // 0011 - EV_PH_RSY, // 0100 - EV_PH_DR6, // 0101 - EV_PH_EI, // 0110 - EV_PH_PU, // 0111 - EV_PH_AR, // 1000 - EV_PH_9, // 1001 - EV_PH_ARL, // 1010 - EV_PH_CVR, // 1011 - EV_PH_AI8, // 1100 - EV_PH_AI10, // 1101 - EV_PH_AIL, // 1110 - EV_PH_DC, // 1111 - EV_PH_ACTIVATE_REQ, - EV_PH_DEACTIVATE_REQ, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -static char *strL1Event[] = -{ - "EV_PH_DR", // 0000 - "EV_PH_RES", // 0001 - "EV_PH_TMA", // 0010 - "EV_PH_SLD", // 0011 - "EV_PH_RSY", // 0100 - "EV_PH_DR6", // 0101 - "EV_PH_EI", // 0110 - "EV_PH_PU", // 0111 - "EV_PH_AR", // 1000 - "EV_PH_9", // 1001 - "EV_PH_ARL", // 1010 - "EV_PH_CVR", // 1011 - "EV_PH_AI8", // 1100 - "EV_PH_AI10", // 1101 - "EV_PH_AIL", // 1110 - "EV_PH_DC", // 1111 - "EV_PH_ACTIVATE_REQ", - "EV_PH_DEACTIVATE_REQ", - "EV_TIMER3", -}; - -static inline void D_L1L2(struct isac *isac, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if; - - DBG(DBG_PR, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -static void ph_command(struct isac *isac, unsigned int command) -{ - DBG(DBG_L1M, "ph_command %#x", command); - switch (isac->type) { - case TYPE_ISAC: - isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3); - break; - case TYPE_ISACSX: - isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1)); - break; - } -} - -// ---------------------------------------------------------------------- - -static void l1_di(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_RESET); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_RESET); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3_PDOWN); -} - -static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F3_PEND_DEACT); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F3_PEND_DEACT); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_go_f4(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F4); -} - -static void l1_go_f5(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F5); -} - -static void l1_go_f6(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F6); -} - -static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F6); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmDelTimer(&isac->timer, 0); - FsmChangeState(fi, ST_L1_F7); - ph_command(isac, ISAC_CMD_AR8); - D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL); -} - -static void l1_go_f8(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F8); -} - -static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F8); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_ar8(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - ph_command(isac, ISAC_CMD_AR8); -} - -static void l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - ph_command(isac, ISAC_CMD_DI); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); -} - -// state machines according to data sheet PSB 2186 / 3186 - -static struct FsmNode L1FnList[] __initdata = -{ - {ST_L1_RESET, EV_PH_RES, l1_di}, - {ST_L1_RESET, EV_PH_EI, l1_di}, - {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown}, - {ST_L1_RESET, EV_PH_AR, l1_go_f6}, - {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind}, - - {ST_L1_F3_PDOWN, EV_PH_RES, l1_di}, - {ST_L1_F3_PDOWN, EV_PH_EI, l1_di}, - {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6}, - {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5}, - {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4}, - {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8}, - {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3}, - - {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di}, - {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di}, - {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown}, - {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5}, - {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6}, - {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind}, - - {ST_L1_F4, EV_PH_RES, l1_di}, - {ST_L1_F4, EV_PH_EI, l1_di}, - {ST_L1_F4, EV_PH_RSY, l1_go_f5}, - {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_PH_DC, l1_go_f3pdown}, - - {ST_L1_F5, EV_PH_RES, l1_di}, - {ST_L1_F5, EV_PH_EI, l1_di}, - {ST_L1_F5, EV_PH_AR, l1_go_f6}, - {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F5, EV_TIMER3, l1_timer3}, - {ST_L1_F5, EV_PH_DR, l1_go_f3pend}, - {ST_L1_F5, EV_PH_DC, l1_go_f3pdown}, - - {ST_L1_F6, EV_PH_RES, l1_di}, - {ST_L1_F6, EV_PH_EI, l1_di}, - {ST_L1_F6, EV_PH_RSY, l1_go_f8}, - {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F6, EV_PH_DR6, l1_go_f3pend}, - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_PH_DC, l1_go_f3pdown}, - - {ST_L1_F7, EV_PH_RES, l1_di_deact_ind}, - {ST_L1_F7, EV_PH_EI, l1_di_deact_ind}, - {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind}, - {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind}, - {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind}, - - {ST_L1_F8, EV_PH_RES, l1_di}, - {ST_L1_F8, EV_PH_EI, l1_di}, - {ST_L1_F8, EV_PH_AR, l1_go_f6}, - {ST_L1_F8, EV_PH_DR, l1_go_f3pend}, - {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_PH_DC, l1_go_f3pdown}, -}; - -static void l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - DBG(DBG_L1M, "%s", buf); - va_end(args); -} - -static void isac_version(struct isac *cs) -{ - int val; - - val = cs->read_isac(cs, ISAC_RBCH); - DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]); -} - -static void isac_empty_fifo(struct isac *isac, int count) -{ - // this also works for isacsx, since - // CMDR(D) register works the same - u_char *ptr; - - DBG(DBG_IRQ, "count %d", count); - - if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - DBG(DBG_WARN, "overrun %d", isac->rcvidx + count); - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); - isac->rcvidx = 0; - return; - } - ptr = isac->rcvbuf + isac->rcvidx; - isac->rcvidx += count; - isac->read_isac_fifo(isac, ptr, count); - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); - DBG_PACKET(DBG_RFIFO, ptr, count); -} - -static void isac_fill_fifo(struct isac *isac) -{ - // this also works for isacsx, since - // CMDR(D) register works the same - - int count; - unsigned char cmd; - u_char *ptr; - - BUG_ON(!isac->tx_skb); - - count = isac->tx_skb->len; - BUG_ON(count <= 0); - - DBG(DBG_IRQ, "count %d", count); - - if (count > 0x20) { - count = 0x20; - cmd = ISAC_CMDR_XTF; - } else { - cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; - } - - ptr = isac->tx_skb->data; - skb_pull(isac->tx_skb, count); - isac->tx_cnt += count; - DBG_PACKET(DBG_XFIFO, ptr, count); - isac->write_isac_fifo(isac, ptr, count); - isac->write_isac(isac, ISAC_CMDR, cmd); -} - -static void isac_retransmit(struct isac *isac) -{ - if (!isac->tx_skb) { - DBG(DBG_WARN, "no skb"); - return; - } - skb_push(isac->tx_skb, isac->tx_cnt); - isac->tx_cnt = 0; -} - - -static inline void isac_cisq_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISAC_CIR0); - DBG(DBG_IRQ, "CIR0 %#x", val); - if (val & ISAC_CIR0_CIC0) { - DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf); - FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL); - } - if (val & ISAC_CIR0_CIC1) { - val = isac->read_isac(isac, ISAC_CIR1); - DBG(DBG_WARN, "ISAC CIR1 %#x", val); - } -} - -static inline void isac_rme_interrupt(struct isac *isac) -{ - unsigned char val; - int count; - struct sk_buff *skb; - - val = isac->read_isac(isac, ISAC_RSTA); - if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB)) - != ISAC_RSTA_CRC) { - DBG(DBG_WARN, "RSTA %#x, dropped", val); - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); - goto out; - } - - count = isac->read_isac(isac, ISAC_RBCL) & 0x1f; - DBG(DBG_IRQ, "RBCL %#x", count); - if (count == 0) - count = 0x20; - - isac_empty_fifo(isac, count); - count = isac->rcvidx; - if (count < 1) { - DBG(DBG_WARN, "count %d < 1", count); - goto out; - } - - skb = alloc_skb(count, GFP_ATOMIC); - if (!skb) { - DBG(DBG_WARN, "no memory, dropping\n"); - goto out; - } - skb_put_data(skb, isac->rcvbuf, count); - DBG_SKB(DBG_RPACKET, skb); - D_L1L2(isac, PH_DATA | INDICATION, skb); -out: - isac->rcvidx = 0; -} - -static inline void isac_xpr_interrupt(struct isac *isac) -{ - if (!isac->tx_skb) - return; - - if (isac->tx_skb->len > 0) { - isac_fill_fifo(isac); - return; - } - dev_kfree_skb_irq(isac->tx_skb); - isac->tx_cnt = 0; - isac->tx_skb = NULL; - D_L1L2(isac, PH_DATA | CONFIRM, NULL); -} - -static inline void isac_exi_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISAC_EXIR); - DBG(2, "EXIR %#x", val); - - if (val & ISAC_EXIR_XMR) { - DBG(DBG_WARN, "ISAC XMR"); - isac_retransmit(isac); - } - if (val & ISAC_EXIR_XDU) { - DBG(DBG_WARN, "ISAC XDU"); - isac_retransmit(isac); - } - if (val & ISAC_EXIR_MOS) { /* MOS */ - DBG(DBG_WARN, "MOS"); - val = isac->read_isac(isac, ISAC_MOSR); - DBG(2, "ISAC MOSR %#x", val); - } -} - -void isac_irq(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISAC_ISTA); - DBG(DBG_IRQ, "ISTA %#x", val); - - if (val & ISAC_ISTA_EXI) { - DBG(DBG_IRQ, "EXI"); - isac_exi_interrupt(isac); - } - if (val & ISAC_ISTA_XPR) { - DBG(DBG_IRQ, "XPR"); - isac_xpr_interrupt(isac); - } - if (val & ISAC_ISTA_RME) { - DBG(DBG_IRQ, "RME"); - isac_rme_interrupt(isac); - } - if (val & ISAC_ISTA_RPF) { - DBG(DBG_IRQ, "RPF"); - isac_empty_fifo(isac, 0x20); - } - if (val & ISAC_ISTA_CISQ) { - DBG(DBG_IRQ, "CISQ"); - isac_cisq_interrupt(isac); - } - if (val & ISAC_ISTA_RSC) { - DBG(DBG_WARN, "RSC"); - } - if (val & ISAC_ISTA_SIN) { - DBG(DBG_WARN, "SIN"); - } - isac->write_isac(isac, ISAC_MASK, 0xff); - isac->write_isac(isac, ISAC_MASK, 0x00); -} - -// ====================================================================== - -static inline void isacsx_cic_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISACSX_CIR0); - DBG(DBG_IRQ, "CIR0 %#x", val); - if (val & ISACSX_CIR0_CIC0) { - DBG(DBG_IRQ, "CODR0 %#x", val >> 4); - FsmEvent(&isac->l1m, val >> 4, NULL); - } -} - -static inline void isacsx_rme_interrupt(struct isac *isac) -{ - int count; - struct sk_buff *skb; - unsigned char val; - - val = isac->read_isac(isac, ISACSX_RSTAD); - if ((val & (ISACSX_RSTAD_VFR | - ISACSX_RSTAD_RDO | - ISACSX_RSTAD_CRC | - ISACSX_RSTAD_RAB)) - != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) { - DBG(DBG_WARN, "RSTAD %#x, dropped", val); - isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC); - goto out; - } - - count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f; - DBG(DBG_IRQ, "RBCLD %#x", count); - if (count == 0) - count = 0x20; - - isac_empty_fifo(isac, count); - // strip trailing status byte - count = isac->rcvidx - 1; - if (count < 1) { - DBG(DBG_WARN, "count %d < 1", count); - goto out; - } - - skb = dev_alloc_skb(count); - if (!skb) { - DBG(DBG_WARN, "no memory, dropping"); - goto out; - } - skb_put_data(skb, isac->rcvbuf, count); - DBG_SKB(DBG_RPACKET, skb); - D_L1L2(isac, PH_DATA | INDICATION, skb); -out: - isac->rcvidx = 0; -} - -static inline void isacsx_xpr_interrupt(struct isac *isac) -{ - if (!isac->tx_skb) - return; - - if (isac->tx_skb->len > 0) { - isac_fill_fifo(isac); - return; - } - dev_kfree_skb_irq(isac->tx_skb); - isac->tx_skb = NULL; - isac->tx_cnt = 0; - D_L1L2(isac, PH_DATA | CONFIRM, NULL); -} - -static inline void isacsx_icd_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISACSX_ISTAD); - DBG(DBG_IRQ, "ISTAD %#x", val); - if (val & ISACSX_ISTAD_XDU) { - DBG(DBG_WARN, "ISTAD XDU"); - isac_retransmit(isac); - } - if (val & ISACSX_ISTAD_XMR) { - DBG(DBG_WARN, "ISTAD XMR"); - isac_retransmit(isac); - } - if (val & ISACSX_ISTAD_XPR) { - DBG(DBG_IRQ, "ISTAD XPR"); - isacsx_xpr_interrupt(isac); - } - if (val & ISACSX_ISTAD_RFO) { - DBG(DBG_WARN, "ISTAD RFO"); - isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC); - } - if (val & ISACSX_ISTAD_RME) { - DBG(DBG_IRQ, "ISTAD RME"); - isacsx_rme_interrupt(isac); - } - if (val & ISACSX_ISTAD_RPF) { - DBG(DBG_IRQ, "ISTAD RPF"); - isac_empty_fifo(isac, 0x20); - } -} - -void isacsx_irq(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISACSX_ISTA); - DBG(DBG_IRQ, "ISTA %#x", val); - - if (val & ISACSX_ISTA_ICD) - isacsx_icd_interrupt(isac); - if (val & ISACSX_ISTA_CIC) - isacsx_cic_interrupt(isac); -} - -void isac_init(struct isac *isac) -{ - isac->tx_skb = NULL; - isac->l1m.fsm = &l1fsm; - isac->l1m.state = ST_L1_RESET; -#ifdef CONFIG_HISAX_DEBUG - isac->l1m.debug = 1; -#else - isac->l1m.debug = 0; -#endif - isac->l1m.userdata = isac; - isac->l1m.printdebug = l1m_debug; - FsmInitTimer(&isac->l1m, &isac->timer); -} - -void isac_setup(struct isac *isac) -{ - int val, eval; - - isac->type = TYPE_ISAC; - isac_version(isac); - - ph_command(isac, ISAC_CMD_RES); - - isac->write_isac(isac, ISAC_MASK, 0xff); - isac->mocr = 0xaa; - if (test_bit(ISAC_IOM1, &isac->flags)) { - /* IOM 1 Mode */ - isac->write_isac(isac, ISAC_ADF2, 0x0); - isac->write_isac(isac, ISAC_SPCR, 0xa); - isac->write_isac(isac, ISAC_ADF1, 0x2); - isac->write_isac(isac, ISAC_STCR, 0x70); - isac->write_isac(isac, ISAC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!isac->adf2) - isac->adf2 = 0x80; - isac->write_isac(isac, ISAC_ADF2, isac->adf2); - isac->write_isac(isac, ISAC_SQXR, 0x2f); - isac->write_isac(isac, ISAC_SPCR, 0x00); - isac->write_isac(isac, ISAC_STCR, 0x70); - isac->write_isac(isac, ISAC_MODE, 0xc9); - isac->write_isac(isac, ISAC_TIMR, 0x00); - isac->write_isac(isac, ISAC_ADF1, 0x00); - } - val = isac->read_isac(isac, ISAC_STAR); - DBG(2, "ISAC STAR %x", val); - val = isac->read_isac(isac, ISAC_MODE); - DBG(2, "ISAC MODE %x", val); - val = isac->read_isac(isac, ISAC_ADF2); - DBG(2, "ISAC ADF2 %x", val); - val = isac->read_isac(isac, ISAC_ISTA); - DBG(2, "ISAC ISTA %x", val); - if (val & 0x01) { - eval = isac->read_isac(isac, ISAC_EXIR); - DBG(2, "ISAC EXIR %x", eval); - } - val = isac->read_isac(isac, ISAC_CIR0); - DBG(2, "ISAC CIR0 %x", val); - FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL); - - isac->write_isac(isac, ISAC_MASK, 0x0); - // RESET Receiver and Transmitter - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES); -} - -void isacsx_setup(struct isac *isac) -{ - isac->type = TYPE_ISACSX; - // clear LDD - isac->write_isac(isac, ISACSX_TR_CONF0, 0x00); - // enable transmitter - isac->write_isac(isac, ISACSX_TR_CONF2, 0x00); - // transparent mode 0, RAC, stop/go - isac->write_isac(isac, ISACSX_MODED, 0xc9); - // all HDLC IRQ unmasked - isac->write_isac(isac, ISACSX_MASKD, 0x03); - // unmask ICD, CID IRQs - isac->write_isac(isac, ISACSX_MASK, - ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC)); -} - -void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) -{ - struct isac *isac = hisax_d_if->priv; - struct sk_buff *skb = arg; - - DBG(DBG_PR, "pr %#x", pr); - - switch (pr) { - case PH_ACTIVATE | REQUEST: - FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL); - break; - case PH_DEACTIVATE | REQUEST: - FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL); - break; - case PH_DATA | REQUEST: - DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len); - DBG_SKB(DBG_XPACKET, skb); - if (isac->l1m.state != ST_L1_F7) { - DBG(1, "L1 wrong state %d\n", isac->l1m.state); - dev_kfree_skb(skb); - break; - } - BUG_ON(isac->tx_skb); - - isac->tx_skb = skb; - isac_fill_fifo(isac); - break; - } -} - -static int __init hisax_isac_init(void) -{ - printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n"); - - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strState = strL1State; - l1fsm.strEvent = strL1Event; - return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); -} - -static void __exit hisax_isac_exit(void) -{ - FsmFree(&l1fsm); -} - -EXPORT_SYMBOL(isac_init); -EXPORT_SYMBOL(isac_d_l2l1); - -EXPORT_SYMBOL(isacsx_setup); -EXPORT_SYMBOL(isacsx_irq); - -EXPORT_SYMBOL(isac_setup); -EXPORT_SYMBOL(isac_irq); - -module_init(hisax_isac_init); -module_exit(hisax_isac_exit); diff --git a/drivers/isdn/hisax/hisax_isac.h b/drivers/isdn/hisax/hisax_isac.h deleted file mode 100644 index d7301da97991..000000000000 --- a/drivers/isdn/hisax/hisax_isac.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __HISAX_ISAC_H__ -#define __HISAX_ISAC_H__ - -#include -#include "fsm.h" -#include "hisax_if.h" - -#define TIMER3_VALUE 7000 -#define MAX_DFRAME_LEN_L1 300 - -#define ISAC_IOM1 0 - -struct isac { - void *priv; - - u_long flags; - struct hisax_d_if hisax_d_if; - struct FsmInst l1m; - struct FsmTimer timer; - u_char mocr; - u_char adf2; - int type; - - u_char rcvbuf[MAX_DFRAME_LEN_L1]; - int rcvidx; - - struct sk_buff *tx_skb; - int tx_cnt; - - u_char (*read_isac) (struct isac *, u_char); - void (*write_isac) (struct isac *, u_char, u_char); - void (*read_isac_fifo) (struct isac *, u_char *, int); - void (*write_isac_fifo)(struct isac *, u_char *, int); -}; - -void isac_init(struct isac *isac); -void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg); - -void isac_setup(struct isac *isac); -void isac_irq(struct isac *isac); - -void isacsx_setup(struct isac *isac); -void isacsx_irq(struct isac *isac); - -#endif diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c deleted file mode 100644 index 3e305fec0ed9..000000000000 --- a/drivers/isdn/hisax/hscx.c +++ /dev/null @@ -1,277 +0,0 @@ -/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $ - * - * HSCX specific routines - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "hscx.h" -#include "isac.h" -#include "isdnl1.h" -#include -#include - -static char *HSCXVer[] = -{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", - "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; - -int -HscxVersion(struct IsdnCardState *cs, char *s) -{ - int verA, verB; - - verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf; - verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf; - printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s, - HSCXVer[verA], HSCXVer[verB]); - if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) - return (1); - else - return (0); -} - -void -modehscx(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->hw.hscx.hscx; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hscx %c mode %d ichan %d", - 'A' + hscx, mode, bc); - bcs->mode = mode; - bcs->channel = bc; - cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF); - cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF); - cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF); - cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0); - cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0); - cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85); - cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30); - cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7); - cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7); - - /* Switch IOM 1 SSI */ - if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0)) - bc = 1 - bc; - - if (bc == 0) { - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, - test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, - test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); - } else { - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1); - } - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f); - cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84); - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d); - cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c); - break; - } - if (mode) - cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41); - cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00); -} - -void -hscx_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - u_long flags; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - modehscx(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - modehscx(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_hscxstate(struct BCState *bcs) -{ - modehscx(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -int -open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hscx.rcvbuf\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_hscx(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hscxstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hscx_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -void -clear_pending_hscx_ints(struct IsdnCardState *cs) -{ - int val, eval; - - val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA); - debugl1(cs, "HSCX B ISTA %x", val); - if (val & 0x01) { - eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); - debugl1(cs, "HSCX B EXIR %x", eval); - } - if (val & 0x02) { - eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); - debugl1(cs, "HSCX A EXIR %x", eval); - } - val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA); - debugl1(cs, "HSCX A ISTA %x", val); - val = cs->BC_Read_Reg(cs, 1, HSCX_STAR); - debugl1(cs, "HSCX B STAR %x", val); - val = cs->BC_Read_Reg(cs, 0, HSCX_STAR); - debugl1(cs, "HSCX A STAR %x", val); - /* disable all IRQ */ - cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF); - cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF); -} - -void -inithscx(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_hscx; - cs->bcs[1].BC_SetStack = setstack_hscx; - cs->bcs[0].BC_Close = close_hscxstate; - cs->bcs[1].BC_Close = close_hscxstate; - cs->bcs[0].hw.hscx.hscx = 0; - cs->bcs[1].hw.hscx.hscx = 1; - cs->bcs[0].hw.hscx.tsaxr0 = 0x2f; - cs->bcs[0].hw.hscx.tsaxr1 = 3; - cs->bcs[1].hw.hscx.tsaxr0 = 0x2f; - cs->bcs[1].hw.hscx.tsaxr1 = 3; - modehscx(cs->bcs, 0, 0); - modehscx(cs->bcs + 1, 0, 0); -} - -void -inithscxisac(struct IsdnCardState *cs, int part) -{ - if (part & 1) { - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); - } - if (part & 2) { - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); - cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); - /* RESET Receiver and Transmitter */ - cs->writeisac(cs, ISAC_CMDR, 0x41); - } -} diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h deleted file mode 100644 index 1148b4bbe711..000000000000 --- a/drivers/isdn/hisax/hscx.h +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $ - * - * HSCX specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#define HSCX_ISTA 0x20 -#define HSCX_CCR1 0x2f -#define HSCX_CCR2 0x2c -#define HSCX_TSAR 0x31 -#define HSCX_TSAX 0x30 -#define HSCX_XCCR 0x32 -#define HSCX_RCCR 0x33 -#define HSCX_MODE 0x22 -#define HSCX_CMDR 0x21 -#define HSCX_EXIR 0x24 -#define HSCX_XAD1 0x24 -#define HSCX_XAD2 0x25 -#define HSCX_RAH2 0x27 -#define HSCX_RSTA 0x27 -#define HSCX_TIMR 0x23 -#define HSCX_STAR 0x21 -#define HSCX_RBCL 0x25 -#define HSCX_XBCH 0x2d -#define HSCX_VSTR 0x2e -#define HSCX_RLCR 0x2e -#define HSCX_MASK 0x20 - -extern int HscxVersion(struct IsdnCardState *cs, char *s); -extern void modehscx(struct BCState *bcs, int mode, int bc); -extern void clear_pending_hscx_ints(struct IsdnCardState *cs); -extern void inithscx(struct IsdnCardState *cs); -extern void inithscxisac(struct IsdnCardState *cs, int part); diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c deleted file mode 100644 index 0d7e783c8bef..000000000000 --- a/drivers/isdn/hisax/hscx_irq.c +++ /dev/null @@ -1,294 +0,0 @@ -/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $ - * - * low level b-channel stuff for Siemens HSCX - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This is an include file for fast inline IRQ stuff - * - */ - - -static inline void -waitforCEC(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); -} - - -static inline void -waitforXFW(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); -} - -static inline void -WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) -{ - waitforCEC(cs, hscx); - WRITEHSCX(cs, hscx, HSCX_CMDR, data); -} - - - -static void -hscx_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_empty_fifo"); - - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hscx_empty_fifo: incoming packet too large"); - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - bcs->hw.hscx.rcvidx = 0; - return; - } - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_empty_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -hscx_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - u_char *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_fill_fifo"); - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > fifo_size) { - more = !0; - count = fifo_size; - } else - count = bcs->tx_skb->len; - - waitforXFW(cs, bcs->hw.hscx.hscx); - ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_fill_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) -{ - u_char r; - struct BCState *bcs = cs->bcs + hscx; - struct sk_buff *skb; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - int count; - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - if (val & 0x80) { /* RME */ - r = READHSCX(cs, hscx, HSCX_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!(r & 0x80)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX invalid frame"); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - } - if ((r & 0x40) && bcs->mode) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX RDO mode=%d", - bcs->mode); -#ifdef ERROR_STATISTIC - bcs->err_rdo++; -#endif - } - if (!(r & 0x20)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX CRC error"); -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - WriteHSCXCMDR(cs, hscx, 0x80); - } else { - count = READHSCX(cs, hscx, HSCX_RBCL) & ( - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f); - if (count == 0) - count = fifo_size; - hscx_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HSCX: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - hscx_empty_fifo(bcs, fifo_size); - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(fifo_size))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - fifo_size); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & 0x10) { /* XPR */ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - hscx_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hscx_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static void -hscx_int_main(struct IsdnCardState *cs, u_char val) -{ - - u_char exval; - struct BCState *bcs; - - if (val & 0x01) { - bcs = cs->bcs + 1; - exval = READHSCX(cs, 1, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == 1) - hscx_fill_fifo(bcs); - else { -#ifdef ERROR_STATISTIC - bcs->err_tx++; -#endif - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX B EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B EXIR %x", exval); - } - if (val & 0xf8) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B interrupt %x", val); - hscx_interrupt(cs, val, 1); - } - if (val & 0x02) { - bcs = cs->bcs; - exval = READHSCX(cs, 0, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == L1_MODE_TRANS) - hscx_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ -#ifdef ERROR_STATISTIC - bcs->err_tx++; -#endif - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX A EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A EXIR %x", exval); - } - if (val & 0x04) { - exval = READHSCX(cs, 0, HSCX_ISTA); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A interrupt %x", exval); - hscx_interrupt(cs, exval, 0); - } -} diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c deleted file mode 100644 index 831dd1bb81ef..000000000000 --- a/drivers/isdn/hisax/icc.c +++ /dev/null @@ -1,680 +0,0 @@ -/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $ - * - * ICC specific routines - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 1999.6.25 Initial implementation of routines for Siemens ISDN - * Communication Controller PEB 2070 based on the ISAC routines - * written by Karsten Keil. - * - */ - -#include -#include "hisax.h" -#include "icc.h" -// #include "arcofi.h" -#include "isdnl1.h" -#include -#include - -#define DBUSY_TIMER_VALUE 80 -#define ARCOFI_USE 0 - -static char *ICCVer[] = -{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; - -void -ICCVersion(struct IsdnCardState *cs, char *s) -{ - int val; - - val = cs->readisac(cs, ICC_RBCH); - printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); -} - -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command %x", command); - cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); -} - - -static void -icc_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.icc.ph_state) { - case (ICC_IND_EI1): - ph_command(cs, ICC_CMD_DI); - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (ICC_IND_DC): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (ICC_IND_DR): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (ICC_IND_PU): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (ICC_IND_FJ): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (ICC_IND_AR): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (ICC_IND_AI): - l1_msg(cs, HW_INFO4 | INDICATION, NULL); - break; - default: - break; - } -} - -static void -icc_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) - icc_new_ph(cs); - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -#if ARCOFI_USE - if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) - return; - if (test_and_clear_bit(D_RX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_RX_END, NULL); - if (test_and_clear_bit(D_TX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_TX_END, NULL); -#endif -} - -static void -icc_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "icc_empty_fifo"); - - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "icc_empty_fifo overrun %d", - cs->rcvidx + count); - cs->writeisac(cs, ICC_CMDR, 0x80); - cs->rcvidx = 0; - return; - } - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->readisacfifo(cs, ptr, count); - cs->writeisac(cs, ICC_CMDR, 0x80); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "icc_empty_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -icc_fill_fifo(struct IsdnCardState *cs) -{ - int count, more; - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "icc_fill_fifo"); - - if (!cs->tx_skb) - return; - - count = cs->tx_skb->len; - if (count <= 0) - return; - - more = 0; - if (count > 32) { - more = !0; - count = 32; - } - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeisacfifo(cs, ptr, count); - cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "icc_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&cs->dbusytimer); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "icc_fill_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -void -icc_interrupt(struct IsdnCardState *cs, u_char val) -{ - u_char exval, v1; - struct sk_buff *skb; - unsigned int count; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ICC interrupt %x", val); - if (val & 0x80) { /* RME */ - exval = cs->readisac(cs, ICC_RSTA); - if ((exval & 0x70) != 0x20) { - if (exval & 0x40) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC RDO"); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - } - if (!(exval & 0x20)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC CRC error"); -#ifdef ERROR_STATISTIC - cs->err_crc++; -#endif - } - cs->writeisac(cs, ICC_CMDR, 0x80); - } else { - count = cs->readisac(cs, ICC_RBCL) & 0x1f; - if (count == 0) - count = 32; - icc_empty_fifo(cs, count); - if ((count = cs->rcvidx) > 0) { - cs->rcvidx = 0; - if (!(skb = alloc_skb(count, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - icc_empty_fifo(cs, 32); - } - if (val & 0x20) { /* RSC */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC RSC interrupt"); - } - if (val & 0x10) { /* XPR */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - icc_fill_fifo(cs); - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - icc_fill_fifo(cs); - } else - schedule_event(cs, D_XMTBUFREADY); - } -afterXPR: - if (val & 0x04) { /* CISQ */ - exval = cs->readisac(cs, ICC_CIR0); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ICC CIR0 %02X", exval); - if (exval & 2) { - cs->dc.icc.ph_state = (exval >> 2) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); - schedule_event(cs, D_L1STATECHANGE); - } - if (exval & 1) { - exval = cs->readisac(cs, ICC_CIR1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ICC CIR1 %02X", exval); - } - } - if (val & 0x02) { /* SIN */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC SIN interrupt"); - } - if (val & 0x01) { /* EXI */ - exval = cs->readisac(cs, ICC_EXIR); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC EXIR %02x", exval); - if (exval & 0x80) { /* XMR */ - debugl1(cs, "ICC XMR"); - printk(KERN_WARNING "HiSax: ICC XMR\n"); - } - if (exval & 0x40) { /* XDU */ - debugl1(cs, "ICC XDU"); - printk(KERN_WARNING "HiSax: ICC XDU\n"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { /* Restart frame */ - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - icc_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); - debugl1(cs, "ICC XDU no skb"); - } - } - if (exval & 0x04) { /* MOS */ - v1 = cs->readisac(cs, ICC_MOSR); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC MOSR %02x", v1); -#if ARCOFI_USE - if (v1 & 0x08) { - if (!cs->dc.icc.mon_rx) { - if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX out of memory!"); - cs->dc.icc.mocr &= 0xf0; - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - goto afterMONR0; - } else - cs->dc.icc.mon_rxp = 0; - } - if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { - cs->dc.icc.mocr &= 0xf0; - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX overflow!"); - goto afterMONR0; - } - cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]); - if (cs->dc.icc.mon_rxp == 1) { - cs->dc.icc.mocr |= 0x04; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - } - } - afterMONR0: - if (v1 & 0x80) { - if (!cs->dc.icc.mon_rx) { - if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX out of memory!"); - cs->dc.icc.mocr &= 0x0f; - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - goto afterMONR1; - } else - cs->dc.icc.mon_rxp = 0; - } - if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { - cs->dc.icc.mocr &= 0x0f; - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX overflow!"); - goto afterMONR1; - } - cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]); - cs->dc.icc.mocr |= 0x40; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - } - afterMONR1: - if (v1 & 0x04) { - cs->dc.icc.mocr &= 0xf0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - schedule_event(cs, D_RX_MON0); - } - if (v1 & 0x40) { - cs->dc.icc.mocr &= 0x0f; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - schedule_event(cs, D_RX_MON1); - } - if (v1 & 0x02) { - if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && - !(v1 & 0x08))) { - cs->dc.icc.mocr &= 0xf0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - if (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - cs->writeisac(cs, ICC_MOX0, - cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]); - } - AfterMOX0: - if (v1 & 0x20) { - if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && - !(v1 & 0x80))) { - cs->dc.icc.mocr &= 0x0f; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - if (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - cs->writeisac(cs, ICC_MOX1, - cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]); - } - AfterMOX1: ; -#endif - } - } -} - -static void -ICC_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - int val; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - icc_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - icc_fill_fifo(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if ((cs->dc.icc.ph_state == ICC_IND_EI1) || - (cs->dc.icc.ph_state == ICC_IND_DR)) - ph_command(cs, ICC_CMD_DI); - else - ph_command(cs, ICC_CMD_RES); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ICC_CMD_DI); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO1 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ICC_CMD_AR); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ICC_CMD_AI); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - val = 0; - if (1 & (long) arg) - val |= 0x0c; - if (2 & (long) arg) - val |= 0x3; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - if (!val) { - cs->writeisac(cs, ICC_SPCR, 0xa); - cs->writeisac(cs, ICC_ADF1, 0x2); - } else { - cs->writeisac(cs, ICC_SPCR, val); - cs->writeisac(cs, ICC_ADF1, 0xa); - } - } else { - /* IOM 2 Mode */ - cs->writeisac(cs, ICC_SPCR, val); - if (val) - cs->writeisac(cs, ICC_ADF1, 0x8); - else - cs->writeisac(cs, ICC_ADF1, 0x0); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "icc_l1hw unknown %04x", pr); - break; - } -} - -static void -setstack_icc(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = ICC_l1hw; -} - -static void -DC_Close_icc(struct IsdnCardState *cs) { - kfree(cs->dc.icc.mon_rx); - cs->dc.icc.mon_rx = NULL; - kfree(cs->dc.icc.mon_tx); - cs->dc.icc.mon_tx = NULL; -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *stptr; - int rbch, star; - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = cs->readisac(cs, ICC_RBCH); - star = cs->readisac(cs, ICC_STAR); - if (cs->debug) - debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", - rbch, star); - if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ - cs->irq_func(cs->irq, cs); - } - } -} - -void -initicc(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_icc; - cs->DC_Close = DC_Close_icc; - cs->dc.icc.mon_tx = NULL; - cs->dc.icc.mon_rx = NULL; - cs->writeisac(cs, ICC_MASK, 0xff); - cs->dc.icc.mocr = 0xaa; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - cs->writeisac(cs, ICC_ADF2, 0x0); - cs->writeisac(cs, ICC_SPCR, 0xa); - cs->writeisac(cs, ICC_ADF1, 0x2); - cs->writeisac(cs, ICC_STCR, 0x70); - cs->writeisac(cs, ICC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!cs->dc.icc.adf2) - cs->dc.icc.adf2 = 0x80; - cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); - cs->writeisac(cs, ICC_SQXR, 0xa0); - cs->writeisac(cs, ICC_SPCR, 0x20); - cs->writeisac(cs, ICC_STCR, 0x70); - cs->writeisac(cs, ICC_MODE, 0xca); - cs->writeisac(cs, ICC_TIMR, 0x00); - cs->writeisac(cs, ICC_ADF1, 0x20); - } - ph_command(cs, ICC_CMD_RES); - cs->writeisac(cs, ICC_MASK, 0x0); - ph_command(cs, ICC_CMD_DI); -} - -void -clear_pending_icc_ints(struct IsdnCardState *cs) -{ - int val, eval; - - val = cs->readisac(cs, ICC_STAR); - debugl1(cs, "ICC STAR %x", val); - val = cs->readisac(cs, ICC_MODE); - debugl1(cs, "ICC MODE %x", val); - val = cs->readisac(cs, ICC_ADF2); - debugl1(cs, "ICC ADF2 %x", val); - val = cs->readisac(cs, ICC_ISTA); - debugl1(cs, "ICC ISTA %x", val); - if (val & 0x01) { - eval = cs->readisac(cs, ICC_EXIR); - debugl1(cs, "ICC EXIR %x", eval); - } - val = cs->readisac(cs, ICC_CIR0); - debugl1(cs, "ICC CIR0 %x", val); - cs->dc.icc.ph_state = (val >> 2) & 0xf; - schedule_event(cs, D_L1STATECHANGE); - /* Disable all IRQ */ - cs->writeisac(cs, ICC_MASK, 0xFF); -} - -void setup_icc(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, icc_bh); - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); -} diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h deleted file mode 100644 index f367df5d3669..000000000000 --- a/drivers/isdn/hisax/icc.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $ - * - * ICC specific routines - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 1999.7.14 Initial implementation of routines for Siemens ISDN - * Communication Controller PEB 2070 based on the ISAC routines - * written by Karsten Keil. - */ - -/* All Registers original Siemens Spec */ - -#define ICC_MASK 0x20 -#define ICC_ISTA 0x20 -#define ICC_STAR 0x21 -#define ICC_CMDR 0x21 -#define ICC_EXIR 0x24 -#define ICC_ADF2 0x39 -#define ICC_SPCR 0x30 -#define ICC_ADF1 0x38 -#define ICC_CIR0 0x31 -#define ICC_CIX0 0x31 -#define ICC_CIR1 0x33 -#define ICC_CIX1 0x33 -#define ICC_STCR 0x37 -#define ICC_MODE 0x22 -#define ICC_RSTA 0x27 -#define ICC_RBCL 0x25 -#define ICC_RBCH 0x2A -#define ICC_TIMR 0x23 -#define ICC_SQXR 0x3b -#define ICC_MOSR 0x3a -#define ICC_MOCR 0x3a -#define ICC_MOR0 0x32 -#define ICC_MOX0 0x32 -#define ICC_MOR1 0x34 -#define ICC_MOX1 0x34 - -#define ICC_RBCH_XAC 0x80 - -#define ICC_CMD_TIM 0x0 -#define ICC_CMD_RES 0x1 -#define ICC_CMD_DU 0x3 -#define ICC_CMD_EI1 0x4 -#define ICC_CMD_SSP 0x5 -#define ICC_CMD_DT 0x6 -#define ICC_CMD_AR 0x8 -#define ICC_CMD_ARL 0xA -#define ICC_CMD_AI 0xC -#define ICC_CMD_DI 0xF - -#define ICC_IND_DR 0x0 -#define ICC_IND_FJ 0x2 -#define ICC_IND_EI1 0x4 -#define ICC_IND_INT 0x6 -#define ICC_IND_PU 0x7 -#define ICC_IND_AR 0x8 -#define ICC_IND_ARL 0xA -#define ICC_IND_AI 0xC -#define ICC_IND_AIL 0xE -#define ICC_IND_DC 0xF - -extern void ICCVersion(struct IsdnCardState *cs, char *s); -extern void initicc(struct IsdnCardState *cs); -extern void icc_interrupt(struct IsdnCardState *cs, u_char val); -extern void clear_pending_icc_ints(struct IsdnCardState *cs); -extern void setup_icc(struct IsdnCardState *); diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h deleted file mode 100644 index 4f937f02ee34..000000000000 --- a/drivers/isdn/hisax/ipac.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $ - * - * IPAC specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#define IPAC_CONF 0xC0 -#define IPAC_MASK 0xC1 -#define IPAC_ISTA 0xC1 -#define IPAC_ID 0xC2 -#define IPAC_ACFG 0xC3 -#define IPAC_AOE 0xC4 -#define IPAC_ARX 0xC5 -#define IPAC_ATX 0xC5 -#define IPAC_PITA1 0xC6 -#define IPAC_PITA2 0xC7 -#define IPAC_POTA1 0xC8 -#define IPAC_POTA2 0xC9 -#define IPAC_PCFG 0xCA -#define IPAC_SCFG 0xCB -#define IPAC_TIMR2 0xCC diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c deleted file mode 100644 index c7086c1534bd..000000000000 --- a/drivers/isdn/hisax/ipacx.c +++ /dev/null @@ -1,913 +0,0 @@ -/* - * - * IPACX specific routines - * - * Author Joerg Petersohn - * Derived from hisax_isac.c, isac.c, hscx.c and others - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#include -#include -#include -#include "hisax_if.h" -#include "hisax.h" -#include "isdnl1.h" -#include "ipacx.h" - -#define DBUSY_TIMER_VALUE 80 -#define TIMER3_VALUE 7000 -#define MAX_DFRAME_LEN_L1 300 -#define B_FIFO_SIZE 64 -#define D_FIFO_SIZE 32 - - -// ipacx interrupt mask values -#define _MASK_IMASK 0x2E // global mask -#define _MASKB_IMASK 0x0B -#define _MASKD_IMASK 0x03 // all on - -//---------------------------------------------------------- -// local function declarations -//---------------------------------------------------------- -static void ph_command(struct IsdnCardState *cs, unsigned int command); -static inline void cic_int(struct IsdnCardState *cs); -static void dch_l2l1(struct PStack *st, int pr, void *arg); -static void dbusy_timer_handler(struct timer_list *t); -static void dch_empty_fifo(struct IsdnCardState *cs, int count); -static void dch_fill_fifo(struct IsdnCardState *cs); -static inline void dch_int(struct IsdnCardState *cs); -static void dch_setstack(struct PStack *st, struct IsdnCardState *cs); -static void dch_init(struct IsdnCardState *cs); -static void bch_l2l1(struct PStack *st, int pr, void *arg); -static void bch_empty_fifo(struct BCState *bcs, int count); -static void bch_fill_fifo(struct BCState *bcs); -static void bch_int(struct IsdnCardState *cs, u_char hscx); -static void bch_mode(struct BCState *bcs, int mode, int bc); -static void bch_close_state(struct BCState *bcs); -static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs); -static int bch_setstack(struct PStack *st, struct BCState *bcs); -static void bch_init(struct IsdnCardState *cs, int hscx); -static void clear_pending_ints(struct IsdnCardState *cs); - -//---------------------------------------------------------- -// Issue Layer 1 command to chip -//---------------------------------------------------------- -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command (%#x) in (%#x)", command, - cs->dc.isac.ph_state); -//################################### -// printk(KERN_INFO "ph_command (%#x)\n", command); -//################################### - cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E); -} - -//---------------------------------------------------------- -// Transceiver interrupt handler -//---------------------------------------------------------- -static inline void -cic_int(struct IsdnCardState *cs) -{ - u_char event; - - event = cs->readisac(cs, IPACX_CIR0) >> 4; - if (cs->debug & L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event); -//######################################### -// printk(KERN_INFO "cic_int(%x)\n", event); -//######################################### - cs->dc.isac.ph_state = event; - schedule_event(cs, D_L1STATECHANGE); -} - -//========================================================== -// D channel functions -//========================================================== - -//---------------------------------------------------------- -// Command entry point -//---------------------------------------------------------- -static void -dch_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_char cda1_cr; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - dch_fill_fifo(cs); - } - break; - - case (PH_PULL | INDICATION): - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - break; - } - if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - dch_fill_fifo(cs); - break; - - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - - case (HW_RESET | REQUEST): - case (HW_ENABLE | REQUEST): - if ((cs->dc.isac.ph_state == IPACX_IND_RES) || - (cs->dc.isac.ph_state == IPACX_IND_DR) || - (cs->dc.isac.ph_state == IPACX_IND_DC)) - ph_command(cs, IPACX_CMD_TIM); - else - ph_command(cs, IPACX_CMD_RES); - break; - - case (HW_INFO3 | REQUEST): - ph_command(cs, IPACX_CMD_AR8); - break; - - case (HW_TESTLOOP | REQUEST): - cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 - cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 - cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); - (void) cs->readisac(cs, IPACX_CDA2_CR); - if ((long)arg & 1) { // loop B1 - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x0a); - } - else { // B1 off - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x0a); - } - if ((long)arg & 2) { // loop B2 - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x14); - } - else { // B2 off - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x14); - } - break; - - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - break; - - default: - if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr); - break; - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *st; - int rbchd, stard; - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbchd = cs->readisac(cs, IPACX_RBCHD); - stard = cs->readisac(cs, IPACX_STARD); - if (cs->debug) - debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard); - if (!(stard & 0x40)) { // D-Channel Busy - set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - for (st = cs->stlist; st; st = st->next) { - st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on - } - } else { - // seems we lost an interrupt; reset transceiver */ - clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR - } - } -} - -//---------------------------------------------------------- -// Fill buffer from receive FIFO -//---------------------------------------------------------- -static void -dch_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "dch_empty_fifo()"); - - // message too large, remove - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_empty_fifo() incoming message too large"); - cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC - cs->rcvidx = 0; - return; - } - - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - - cs->readisacfifo(cs, ptr, count); - cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "dch_empty_fifo() cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -//---------------------------------------------------------- -// Fill transmit FIFO -//---------------------------------------------------------- -static void -dch_fill_fifo(struct IsdnCardState *cs) -{ - int count; - u_char cmd, *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "dch_fill_fifo()"); - - if (!cs->tx_skb) return; - count = cs->tx_skb->len; - if (count <= 0) return; - - if (count > D_FIFO_SIZE) { - count = D_FIFO_SIZE; - cmd = 0x08; // XTF - } else { - cmd = 0x0A; // XTF | XME - } - - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeisacfifo(cs, ptr, count); - cs->writeisac(cs, IPACX_CMDRD, cmd); - - // set timeout for transmission contol - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "dch_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&cs->dbusytimer); - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "dch_fill_fifo() cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -//---------------------------------------------------------- -// D channel interrupt handler -//---------------------------------------------------------- -static inline void -dch_int(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - u_char istad, rstad; - int count; - - istad = cs->readisac(cs, IPACX_ISTAD); -//############################################## -// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad); -//############################################## - - if (istad & 0x80) { // RME - rstad = cs->readisac(cs, IPACX_RSTAD); - if ((rstad & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) - if (!(rstad & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_int(): invalid frame"); - if ((rstad & 0x40)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_int(): RDO"); - if (!(rstad & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_int(): CRC error"); - cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC - } else { // received frame ok - count = cs->readisac(cs, IPACX_RBCLD); - if (count) count--; // RSTAB is last byte - count &= D_FIFO_SIZE - 1; - if (count == 0) count = D_FIFO_SIZE; - dch_empty_fifo(cs, count); - if ((count = cs->rcvidx) > 0) { - cs->rcvidx = 0; - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - - if (istad & 0x40) { // RPF - dch_empty_fifo(cs, D_FIFO_SIZE); - } - - if (istad & 0x20) { // RFO - if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): RFO"); - cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES - } - - if (istad & 0x10) { // XPR - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - dch_fill_fifo(cs); - goto afterXPR; - } - else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_skb = NULL; - cs->tx_cnt = 0; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - dch_fill_fifo(cs); - } - else { - schedule_event(cs, D_XMTBUFREADY); - } - } -afterXPR: - - if (istad & 0x0C) { // XDU or XMR - if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): XDU"); - if (cs->tx_skb) { - skb_push(cs->tx_skb, cs->tx_cnt); // retransmit - cs->tx_cnt = 0; - dch_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); - debugl1(cs, "ISAC XDU no skb"); - } - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -dch_setstack(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = dch_l2l1; -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -dch_init(struct IsdnCardState *cs) -{ - printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n"); - - cs->setstack_d = dch_setstack; - - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); - - cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD - cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter - cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go - cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel -} - - -//========================================================== -// B channel functions -//========================================================== - -//---------------------------------------------------------- -// Entry point for commands -//---------------------------------------------------------- -static void -bch_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - bch_fill_fifo(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n"); - } else { - set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hscx.count = 0; - bch_fill_fifo(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - set_bit(BC_FLG_ACTIV, &bcs->Flag); - bch_mode(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - clear_bit(BC_FLG_ACTIV, &bcs->Flag); - clear_bit(BC_FLG_BUSY, &bcs->Flag); - bch_mode(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -//---------------------------------------------------------- -// Read B channel fifo to receive buffer -//---------------------------------------------------------- -static void -bch_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr, hscx; - struct IsdnCardState *cs; - int cnt; - - cs = bcs->cs; - hscx = bcs->hw.hscx.hscx; - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "bch_empty_fifo()"); - - // message too large, remove - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_empty_fifo() incoming packet too large"); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC - bcs->hw.hscx.rcvidx = 0; - return; - } - - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - cnt = count; - while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC - - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -//---------------------------------------------------------- -// Fill buffer to transmit FIFO -//---------------------------------------------------------- -static void -bch_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs; - int more, count, cnt; - u_char *ptr, *p, hscx; - - cs = bcs->cs; - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "bch_fill_fifo()"); - - if (!bcs->tx_skb) return; - if (bcs->tx_skb->len <= 0) return; - - hscx = bcs->hw.hscx.hscx; - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > B_FIFO_SIZE) { - more = 1; - count = B_FIFO_SIZE; - } else { - count = bcs->tx_skb->len; - } - cnt = count; - - p = ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a)); - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "%s() B-%d cnt %d", __func__, hscx, count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -//---------------------------------------------------------- -// B channel interrupt handler -//---------------------------------------------------------- -static void -bch_int(struct IsdnCardState *cs, u_char hscx) -{ - u_char istab; - struct BCState *bcs; - struct sk_buff *skb; - int count; - u_char rstab; - - bcs = cs->bcs + hscx; - istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB); -//############################################## -// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab); -//############################################## - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; - - if (istab & 0x80) { // RME - rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB); - if ((rstab & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) - if (!(rstab & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: invalid frame", hscx); - if ((rstab & 0x40) && (bcs->mode != L1_MODE_NULL)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode); - if (!(rstab & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: CRC error", hscx); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC - } - else { // received frame ok - count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) & (B_FIFO_SIZE - 1); - if (count == 0) count = B_FIFO_SIZE; - bch_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "bch_int Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - - if (istab & 0x40) { // RPF - bch_empty_fifo(bcs, B_FIFO_SIZE); - - if (bcs->mode == L1_MODE_TRANS) { // queue every chunk - // receive transparent audio data - if (!(skb = dev_alloc_skb(B_FIFO_SIZE))) - printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - B_FIFO_SIZE); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - - if (istab & 0x20) { // RFO - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RFO error", hscx); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES - } - - if (istab & 0x10) { // XPR - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - bch_fill_fifo(bcs); - goto afterXPR; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - set_bit(BC_FLG_BUSY, &bcs->Flag); - bch_fill_fifo(bcs); - } else { - clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -afterXPR: - - if (istab & 0x04) { // XDU - if (bcs->mode == L1_MODE_TRANS) { - bch_fill_fifo(bcs); - } - else { - if (bcs->tx_skb) { // restart transmitting the whole frame - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d XDU error", hscx); - } - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -bch_mode(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->hw.hscx.hscx; - - bc = bc ? 1 : 0; // in case bc is greater than 1 - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc); - bcs->mode = mode; - bcs->channel = bc; - - // map controller to according timeslot - if (!hscx) - { - cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc); - cs->writeisac(cs, IPACX_BCHA_CR, 0x88); - } - else - { - cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc); - cs->writeisac(cs, IPACX_BCHB_CR, 0x88); - } - - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off - cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj. - cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode - cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000 - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments - cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0 - cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments - cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); - break; - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -bch_close_state(struct BCState *bcs) -{ - bch_mode(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static int -bch_open_state(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax open_bchstate(): No memory for hscx.rcvbuf\n"); - clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax open_bchstate: No memory for bcs->blog\n"); - clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static int -bch_setstack(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (bch_open_state(st->l1.hardware, bcs)) return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = bch_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -bch_init(struct IsdnCardState *cs, int hscx) -{ - cs->bcs[hscx].BC_SetStack = bch_setstack; - cs->bcs[hscx].BC_Close = bch_close_state; - cs->bcs[hscx].hw.hscx.hscx = hscx; - cs->bcs[hscx].cs = cs; - bch_mode(cs->bcs + hscx, 0, hscx); -} - - -//========================================================== -// Shared functions -//========================================================== - -//---------------------------------------------------------- -// Main interrupt handler -//---------------------------------------------------------- -void -interrupt_ipacx(struct IsdnCardState *cs) -{ - u_char ista; - - while ((ista = cs->readisac(cs, IPACX_ISTA))) { -//################################################# -// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista); -//################################################# - if (ista & 0x80) bch_int(cs, 0); // B channel interrupts - if (ista & 0x40) bch_int(cs, 1); - - if (ista & 0x01) dch_int(cs); // D channel - if (ista & 0x10) cic_int(cs); // Layer 1 state - } -} - -//---------------------------------------------------------- -// Clears chip interrupt status -//---------------------------------------------------------- -static void -clear_pending_ints(struct IsdnCardState *cs) -{ - int ista; - - // all interrupts off - cs->writeisac(cs, IPACX_MASK, 0xff); - cs->writeisac(cs, IPACX_MASKD, 0xff); - cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff); - cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff); - - ista = cs->readisac(cs, IPACX_ISTA); - if (ista & 0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB); - if (ista & 0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB); - if (ista & 0x10) cs->readisac(cs, IPACX_CIR0); - if (ista & 0x01) cs->readisac(cs, IPACX_ISTAD); -} - -//---------------------------------------------------------- -// Does chip configuration work -// Work to do depends on bit mask in part -//---------------------------------------------------------- -void -init_ipacx(struct IsdnCardState *cs, int part) -{ - if (part & 1) { // initialise chip -//################################################## -// printk(KERN_INFO "init_ipacx(%x)\n", part); -//################################################## - clear_pending_ints(cs); - bch_init(cs, 0); - bch_init(cs, 1); - dch_init(cs); - } - if (part & 2) { // reenable all interrupts and start chip - cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK); - cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK); - cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK); - cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register - - // reset HDLC Transmitters/receivers - cs->writeisac(cs, IPACX_CMDRD, 0x41); - cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41); - cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41); - ph_command(cs, IPACX_CMD_RES); - } -} - -//----------------- end of file ----------------------- diff --git a/drivers/isdn/hisax/ipacx.h b/drivers/isdn/hisax/ipacx.h deleted file mode 100644 index e8a22e8f34b6..000000000000 --- a/drivers/isdn/hisax/ipacx.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * - * IPACX specific defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#ifndef INCLUDE_IPACX_H -#define INCLUDE_IPACX_H - -/* D-channel registers */ -#define IPACX_RFIFOD 0x00 /* RD */ -#define IPACX_XFIFOD 0x00 /* WR */ -#define IPACX_ISTAD 0x20 /* RD */ -#define IPACX_MASKD 0x20 /* WR */ -#define IPACX_STARD 0x21 /* RD */ -#define IPACX_CMDRD 0x21 /* WR */ -#define IPACX_MODED 0x22 /* RD/WR */ -#define IPACX_EXMD1 0x23 /* RD/WR */ -#define IPACX_TIMR1 0x24 /* RD/WR */ -#define IPACX_SAP1 0x25 /* WR */ -#define IPACX_SAP2 0x26 /* WR */ -#define IPACX_RBCLD 0x26 /* RD */ -#define IPACX_RBCHD 0x27 /* RD */ -#define IPACX_TEI1 0x27 /* WR */ -#define IPACX_TEI2 0x28 /* WR */ -#define IPACX_RSTAD 0x28 /* RD */ -#define IPACX_TMD 0x29 /* RD/WR */ -#define IPACX_CIR0 0x2E /* RD */ -#define IPACX_CIX0 0x2E /* WR */ -#define IPACX_CIR1 0x2F /* RD */ -#define IPACX_CIX1 0x2F /* WR */ - -/* Transceiver registers */ -#define IPACX_TR_CONF0 0x30 /* RD/WR */ -#define IPACX_TR_CONF1 0x31 /* RD/WR */ -#define IPACX_TR_CONF2 0x32 /* RD/WR */ -#define IPACX_TR_STA 0x33 /* RD */ -#define IPACX_TR_CMD 0x34 /* RD/WR */ -#define IPACX_SQRR1 0x35 /* RD */ -#define IPACX_SQXR1 0x35 /* WR */ -#define IPACX_SQRR2 0x36 /* RD */ -#define IPACX_SQXR2 0x36 /* WR */ -#define IPACX_SQRR3 0x37 /* RD */ -#define IPACX_SQXR3 0x37 /* WR */ -#define IPACX_ISTATR 0x38 /* RD */ -#define IPACX_MASKTR 0x39 /* RD/WR */ -#define IPACX_TR_MODE 0x3A /* RD/WR */ -#define IPACX_ACFG1 0x3C /* RD/WR */ -#define IPACX_ACFG2 0x3D /* RD/WR */ -#define IPACX_AOE 0x3E /* RD/WR */ -#define IPACX_ARX 0x3F /* RD */ -#define IPACX_ATX 0x3F /* WR */ - -/* IOM: Timeslot, DPS, CDA */ -#define IPACX_CDA10 0x40 /* RD/WR */ -#define IPACX_CDA11 0x41 /* RD/WR */ -#define IPACX_CDA20 0x42 /* RD/WR */ -#define IPACX_CDA21 0x43 /* RD/WR */ -#define IPACX_CDA_TSDP10 0x44 /* RD/WR */ -#define IPACX_CDA_TSDP11 0x45 /* RD/WR */ -#define IPACX_CDA_TSDP20 0x46 /* RD/WR */ -#define IPACX_CDA_TSDP21 0x47 /* RD/WR */ -#define IPACX_BCHA_TSDP_BC1 0x48 /* RD/WR */ -#define IPACX_BCHA_TSDP_BC2 0x49 /* RD/WR */ -#define IPACX_BCHB_TSDP_BC1 0x4A /* RD/WR */ -#define IPACX_BCHB_TSDP_BC2 0x4B /* RD/WR */ -#define IPACX_TR_TSDP_BC1 0x4C /* RD/WR */ -#define IPACX_TR_TSDP_BC2 0x4D /* RD/WR */ -#define IPACX_CDA1_CR 0x4E /* RD/WR */ -#define IPACX_CDA2_CR 0x4F /* RD/WR */ - -/* IOM: Contol, Sync transfer, Monitor */ -#define IPACX_TR_CR 0x50 /* RD/WR */ -#define IPACX_TRC_CR 0x50 /* RD/WR */ -#define IPACX_BCHA_CR 0x51 /* RD/WR */ -#define IPACX_BCHB_CR 0x52 /* RD/WR */ -#define IPACX_DCI_CR 0x53 /* RD/WR */ -#define IPACX_DCIC_CR 0x53 /* RD/WR */ -#define IPACX_MON_CR 0x54 /* RD/WR */ -#define IPACX_SDS1_CR 0x55 /* RD/WR */ -#define IPACX_SDS2_CR 0x56 /* RD/WR */ -#define IPACX_IOM_CR 0x57 /* RD/WR */ -#define IPACX_STI 0x58 /* RD */ -#define IPACX_ASTI 0x58 /* WR */ -#define IPACX_MSTI 0x59 /* RD/WR */ -#define IPACX_SDS_CONF 0x5A /* RD/WR */ -#define IPACX_MCDA 0x5B /* RD */ -#define IPACX_MOR 0x5C /* RD */ -#define IPACX_MOX 0x5C /* WR */ -#define IPACX_MOSR 0x5D /* RD */ -#define IPACX_MOCR 0x5E /* RD/WR */ -#define IPACX_MSTA 0x5F /* RD */ -#define IPACX_MCONF 0x5F /* WR */ - -/* Interrupt and general registers */ -#define IPACX_ISTA 0x60 /* RD */ -#define IPACX_MASK 0x60 /* WR */ -#define IPACX_AUXI 0x61 /* RD */ -#define IPACX_AUXM 0x61 /* WR */ -#define IPACX_MODE1 0x62 /* RD/WR */ -#define IPACX_MODE2 0x63 /* RD/WR */ -#define IPACX_ID 0x64 /* RD */ -#define IPACX_SRES 0x64 /* WR */ -#define IPACX_TIMR2 0x65 /* RD/WR */ - -/* B-channel registers */ -#define IPACX_OFF_B1 0x70 -#define IPACX_OFF_B2 0x80 - -#define IPACX_ISTAB 0x00 /* RD */ -#define IPACX_MASKB 0x00 /* WR */ -#define IPACX_STARB 0x01 /* RD */ -#define IPACX_CMDRB 0x01 /* WR */ -#define IPACX_MODEB 0x02 /* RD/WR */ -#define IPACX_EXMB 0x03 /* RD/WR */ -#define IPACX_RAH1 0x05 /* WR */ -#define IPACX_RAH2 0x06 /* WR */ -#define IPACX_RBCLB 0x06 /* RD */ -#define IPACX_RBCHB 0x07 /* RD */ -#define IPACX_RAL1 0x07 /* WR */ -#define IPACX_RAL2 0x08 /* WR */ -#define IPACX_RSTAB 0x08 /* RD */ -#define IPACX_TMB 0x09 /* RD/WR */ -#define IPACX_RFIFOB 0x0A /*- RD */ -#define IPACX_XFIFOB 0x0A /*- WR */ - -/* Layer 1 Commands */ -#define IPACX_CMD_TIM 0x0 -#define IPACX_CMD_RES 0x1 -#define IPACX_CMD_SSP 0x2 -#define IPACX_CMD_SCP 0x3 -#define IPACX_CMD_AR8 0x8 -#define IPACX_CMD_AR10 0x9 -#define IPACX_CMD_ARL 0xa -#define IPACX_CMD_DI 0xf - -/* Layer 1 Indications */ -#define IPACX_IND_DR 0x0 -#define IPACX_IND_RES 0x1 -#define IPACX_IND_TMA 0x2 -#define IPACX_IND_SLD 0x3 -#define IPACX_IND_RSY 0x4 -#define IPACX_IND_DR6 0x5 -#define IPACX_IND_PU 0x7 -#define IPACX_IND_AR 0x8 -#define IPACX_IND_ARL 0xa -#define IPACX_IND_CVR 0xb -#define IPACX_IND_AI8 0xc -#define IPACX_IND_AI10 0xd -#define IPACX_IND_AIL 0xe -#define IPACX_IND_DC 0xf - -extern void init_ipacx(struct IsdnCardState *, int); -extern void interrupt_ipacx(struct IsdnCardState *); -extern void setup_isac(struct IsdnCardState *); - -#endif diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c deleted file mode 100644 index bd40e0671ded..000000000000 --- a/drivers/isdn/hisax/isac.c +++ /dev/null @@ -1,681 +0,0 @@ -/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $ - * - * ISAC specific routines - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - */ - -#include "hisax.h" -#include "isac.h" -#include "arcofi.h" -#include "isdnl1.h" -#include -#include -#include - -#define DBUSY_TIMER_VALUE 80 -#define ARCOFI_USE 1 - -static char *ISACVer[] = -{"2086/2186 V1.1", "2085 B1", "2085 B2", - "2085 V2.3"}; - -void ISACVersion(struct IsdnCardState *cs, char *s) -{ - int val; - - val = cs->readisac(cs, ISAC_RBCH); - printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]); -} - -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command %x", command); - cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3); -} - - -static void -isac_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.isac.ph_state) { - case (ISAC_IND_RS): - case (ISAC_IND_EI): - ph_command(cs, ISAC_CMD_DUI); - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (ISAC_IND_DID): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (ISAC_IND_DR): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (ISAC_IND_PU): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (ISAC_IND_RSY): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (ISAC_IND_ARD): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (ISAC_IND_AI8): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (ISAC_IND_AI10): - l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); - break; - default: - break; - } -} - -static void -isac_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) - isac_new_ph(cs); - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -#if ARCOFI_USE - if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) - return; - if (test_and_clear_bit(D_RX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_RX_END, NULL); - if (test_and_clear_bit(D_TX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_TX_END, NULL); -#endif -} - -static void -isac_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "isac_empty_fifo"); - - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isac_empty_fifo overrun %d", - cs->rcvidx + count); - cs->writeisac(cs, ISAC_CMDR, 0x80); - cs->rcvidx = 0; - return; - } - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->readisacfifo(cs, ptr, count); - cs->writeisac(cs, ISAC_CMDR, 0x80); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "isac_empty_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -isac_fill_fifo(struct IsdnCardState *cs) -{ - int count, more; - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "isac_fill_fifo"); - - if (!cs->tx_skb) - return; - - count = cs->tx_skb->len; - if (count <= 0) - return; - - more = 0; - if (count > 32) { - more = !0; - count = 32; - } - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeisacfifo(cs, ptr, count); - cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa); - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "isac_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&cs->dbusytimer); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "isac_fill_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -void -isac_interrupt(struct IsdnCardState *cs, u_char val) -{ - u_char exval, v1; - struct sk_buff *skb; - unsigned int count; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC interrupt %x", val); - if (val & 0x80) { /* RME */ - exval = cs->readisac(cs, ISAC_RSTA); - if ((exval & 0x70) != 0x20) { - if (exval & 0x40) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC RDO"); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - } - if (!(exval & 0x20)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC CRC error"); -#ifdef ERROR_STATISTIC - cs->err_crc++; -#endif - } - cs->writeisac(cs, ISAC_CMDR, 0x80); - } else { - count = cs->readisac(cs, ISAC_RBCL) & 0x1f; - if (count == 0) - count = 32; - isac_empty_fifo(cs, count); - count = cs->rcvidx; - if (count > 0) { - cs->rcvidx = 0; - skb = alloc_skb(count, GFP_ATOMIC); - if (!skb) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - isac_empty_fifo(cs, 32); - } - if (val & 0x20) { /* RSC */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC RSC interrupt"); - } - if (val & 0x10) { /* XPR */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - isac_fill_fifo(cs); - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - cs->tx_skb = skb_dequeue(&cs->sq); - if (cs->tx_skb) { - cs->tx_cnt = 0; - isac_fill_fifo(cs); - } else - schedule_event(cs, D_XMTBUFREADY); - } -afterXPR: - if (val & 0x04) { /* CISQ */ - exval = cs->readisac(cs, ISAC_CIR0); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC CIR0 %02X", exval); - if (exval & 2) { - cs->dc.isac.ph_state = (exval >> 2) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state); - schedule_event(cs, D_L1STATECHANGE); - } - if (exval & 1) { - exval = cs->readisac(cs, ISAC_CIR1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC CIR1 %02X", exval); - } - } - if (val & 0x02) { /* SIN */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC SIN interrupt"); - } - if (val & 0x01) { /* EXI */ - exval = cs->readisac(cs, ISAC_EXIR); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC EXIR %02x", exval); - if (exval & 0x80) { /* XMR */ - debugl1(cs, "ISAC XMR"); - printk(KERN_WARNING "HiSax: ISAC XMR\n"); - } - if (exval & 0x40) { /* XDU */ - debugl1(cs, "ISAC XDU"); - printk(KERN_WARNING "HiSax: ISAC XDU\n"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { /* Restart frame */ - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - isac_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); - debugl1(cs, "ISAC XDU no skb"); - } - } - if (exval & 0x04) { /* MOS */ - v1 = cs->readisac(cs, ISAC_MOSR); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC MOSR %02x", v1); -#if ARCOFI_USE - if (v1 & 0x08) { - if (!cs->dc.isac.mon_rx) { - cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); - if (!cs->dc.isac.mon_rx) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX out of memory!"); - cs->dc.isac.mocr &= 0xf0; - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - goto afterMONR0; - } else - cs->dc.isac.mon_rxp = 0; - } - if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { - cs->dc.isac.mocr &= 0xf0; - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX overflow!"); - goto afterMONR0; - } - cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]); - if (cs->dc.isac.mon_rxp == 1) { - cs->dc.isac.mocr |= 0x04; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - } - } - afterMONR0: - if (v1 & 0x80) { - if (!cs->dc.isac.mon_rx) { - cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); - if (!cs->dc.isac.mon_rx) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX out of memory!"); - cs->dc.isac.mocr &= 0x0f; - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - goto afterMONR1; - } else - cs->dc.isac.mon_rxp = 0; - } - if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { - cs->dc.isac.mocr &= 0x0f; - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX overflow!"); - goto afterMONR1; - } - cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]); - cs->dc.isac.mocr |= 0x40; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - } - afterMONR1: - if (v1 & 0x04) { - cs->dc.isac.mocr &= 0xf0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - schedule_event(cs, D_RX_MON0); - } - if (v1 & 0x40) { - cs->dc.isac.mocr &= 0x0f; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - schedule_event(cs, D_RX_MON1); - } - if (v1 & 0x02) { - if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && - !(v1 & 0x08))) { - cs->dc.isac.mocr &= 0xf0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - if (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - cs->writeisac(cs, ISAC_MOX0, - cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]); - } - AfterMOX0: - if (v1 & 0x20) { - if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && - !(v1 & 0x80))) { - cs->dc.isac.mocr &= 0x0f; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - if (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - cs->writeisac(cs, ISAC_MOX1, - cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]); - } - AfterMOX1:; -#endif - } - } -} - -static void -ISAC_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - int val; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - isac_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - } else { - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - isac_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if ((cs->dc.isac.ph_state == ISAC_IND_EI) || - (cs->dc.isac.ph_state == ISAC_IND_DR) || - (cs->dc.isac.ph_state == ISAC_IND_RS)) - ph_command(cs, ISAC_CMD_TIM); - else - ph_command(cs, ISAC_CMD_RS); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ISAC_CMD_TIM); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ISAC_CMD_AR8); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - val = 0; - if (1 & (long) arg) - val |= 0x0c; - if (2 & (long) arg) - val |= 0x3; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - if (!val) { - cs->writeisac(cs, ISAC_SPCR, 0xa); - cs->writeisac(cs, ISAC_ADF1, 0x2); - } else { - cs->writeisac(cs, ISAC_SPCR, val); - cs->writeisac(cs, ISAC_ADF1, 0xa); - } - } else { - /* IOM 2 Mode */ - cs->writeisac(cs, ISAC_SPCR, val); - if (val) - cs->writeisac(cs, ISAC_ADF1, 0x8); - else - cs->writeisac(cs, ISAC_ADF1, 0x0); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isac_l1hw unknown %04x", pr); - break; - } -} - -static void -setstack_isac(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = ISAC_l1hw; -} - -static void -DC_Close_isac(struct IsdnCardState *cs) -{ - kfree(cs->dc.isac.mon_rx); - cs->dc.isac.mon_rx = NULL; - kfree(cs->dc.isac.mon_tx); - cs->dc.isac.mon_tx = NULL; -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *stptr; - int rbch, star; - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = cs->readisac(cs, ISAC_RBCH); - star = cs->readisac(cs, ISAC_STAR); - if (cs->debug) - debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", - rbch, star); - if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ - cs->irq_func(cs->irq, cs); - } - } -} - -void initisac(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_isac; - cs->DC_Close = DC_Close_isac; - cs->dc.isac.mon_tx = NULL; - cs->dc.isac.mon_rx = NULL; - cs->writeisac(cs, ISAC_MASK, 0xff); - cs->dc.isac.mocr = 0xaa; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - cs->writeisac(cs, ISAC_ADF2, 0x0); - cs->writeisac(cs, ISAC_SPCR, 0xa); - cs->writeisac(cs, ISAC_ADF1, 0x2); - cs->writeisac(cs, ISAC_STCR, 0x70); - cs->writeisac(cs, ISAC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!cs->dc.isac.adf2) - cs->dc.isac.adf2 = 0x80; - cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2); - cs->writeisac(cs, ISAC_SQXR, 0x2f); - cs->writeisac(cs, ISAC_SPCR, 0x00); - cs->writeisac(cs, ISAC_STCR, 0x70); - cs->writeisac(cs, ISAC_MODE, 0xc9); - cs->writeisac(cs, ISAC_TIMR, 0x00); - cs->writeisac(cs, ISAC_ADF1, 0x00); - } - ph_command(cs, ISAC_CMD_RS); - cs->writeisac(cs, ISAC_MASK, 0x0); -} - -void clear_pending_isac_ints(struct IsdnCardState *cs) -{ - int val, eval; - - val = cs->readisac(cs, ISAC_STAR); - debugl1(cs, "ISAC STAR %x", val); - val = cs->readisac(cs, ISAC_MODE); - debugl1(cs, "ISAC MODE %x", val); - val = cs->readisac(cs, ISAC_ADF2); - debugl1(cs, "ISAC ADF2 %x", val); - val = cs->readisac(cs, ISAC_ISTA); - debugl1(cs, "ISAC ISTA %x", val); - if (val & 0x01) { - eval = cs->readisac(cs, ISAC_EXIR); - debugl1(cs, "ISAC EXIR %x", eval); - } - val = cs->readisac(cs, ISAC_CIR0); - debugl1(cs, "ISAC CIR0 %x", val); - cs->dc.isac.ph_state = (val >> 2) & 0xf; - schedule_event(cs, D_L1STATECHANGE); - /* Disable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0xFF); -} - -void setup_isac(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, isac_bh); - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); -} diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h deleted file mode 100644 index 04f16b91b822..000000000000 --- a/drivers/isdn/hisax/isac.h +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $ - * - * ISAC specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#define ISAC_MASK 0x20 -#define ISAC_ISTA 0x20 -#define ISAC_STAR 0x21 -#define ISAC_CMDR 0x21 -#define ISAC_EXIR 0x24 -#define ISAC_ADF2 0x39 -#define ISAC_SPCR 0x30 -#define ISAC_ADF1 0x38 -#define ISAC_CIR0 0x31 -#define ISAC_CIX0 0x31 -#define ISAC_CIR1 0x33 -#define ISAC_CIX1 0x33 -#define ISAC_STCR 0x37 -#define ISAC_MODE 0x22 -#define ISAC_RSTA 0x27 -#define ISAC_RBCL 0x25 -#define ISAC_RBCH 0x2A -#define ISAC_TIMR 0x23 -#define ISAC_SQXR 0x3b -#define ISAC_MOSR 0x3a -#define ISAC_MOCR 0x3a -#define ISAC_MOR0 0x32 -#define ISAC_MOX0 0x32 -#define ISAC_MOR1 0x34 -#define ISAC_MOX1 0x34 - -#define ISAC_RBCH_XAC 0x80 - -#define ISAC_CMD_TIM 0x0 -#define ISAC_CMD_RS 0x1 -#define ISAC_CMD_SCZ 0x4 -#define ISAC_CMD_SSZ 0x2 -#define ISAC_CMD_AR8 0x8 -#define ISAC_CMD_AR10 0x9 -#define ISAC_CMD_ARL 0xA -#define ISAC_CMD_DUI 0xF - -#define ISAC_IND_RS 0x1 -#define ISAC_IND_PU 0x7 -#define ISAC_IND_DR 0x0 -#define ISAC_IND_SD 0x2 -#define ISAC_IND_DIS 0x3 -#define ISAC_IND_EI 0x6 -#define ISAC_IND_RSY 0x4 -#define ISAC_IND_ARD 0x8 -#define ISAC_IND_TI 0xA -#define ISAC_IND_ATI 0xB -#define ISAC_IND_AI8 0xC -#define ISAC_IND_AI10 0xD -#define ISAC_IND_DID 0xF - -extern void ISACVersion(struct IsdnCardState *, char *); -extern void setup_isac(struct IsdnCardState *); -extern void initisac(struct IsdnCardState *); -extern void isac_interrupt(struct IsdnCardState *, u_char); -extern void clear_pending_isac_ints(struct IsdnCardState *); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c deleted file mode 100644 index 82c1879f5664..000000000000 --- a/drivers/isdn/hisax/isar.c +++ /dev/null @@ -1,1910 +0,0 @@ -/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $ - * - * isar.c ISAR (Siemens PSB 7110) specific routines - * - * Author Karsten Keil (keil@isdn4linux.de) - * - * This file is (c) under GNU General Public License - * - */ - -#include -#include "hisax.h" -#include "isar.h" -#include "isdnl1.h" -#include -#include - -#define DBG_LOADFIRM 0 -#define DUMP_MBOXFRAME 2 - -#define DLE 0x10 -#define ETX 0x03 - -#define FAXMODCNT 13 -static const u_char faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, 122, 145, 146}; -static u_int modmask = 0x1fff; -static int frm_extra_delay = 2; -static int para_TOA = 6; -static const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL"}; - -static void isar_setup(struct IsdnCardState *cs); -static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para); -static void ll_deliver_faxstat(struct BCState *bcs, u_char status); - -static inline int -waitforHIA(struct IsdnCardState *cs, int timeout) -{ - - while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) - printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n"); - return (timeout); -} - - -static int -sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, - u_char *msg) -{ - int i; - - if (!waitforHIA(cs, 4000)) - return (0); -#if DUMP_MBOXFRAME - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len); -#endif - cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg); - cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len); - cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0); - if (msg && len) { - cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]); - for (i = 1; i < len; i++) - cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]); -#if DUMP_MBOXFRAME > 1 - if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256], *t; - - i = len; - while (i > 0) { - t = tmp; - t += sprintf(t, "sendmbox cnt %d", len); - QuickHex(t, &msg[len-i], (i > 64) ? 64 : i); - debugl1(cs, "%s", tmp); - i -= 64; - } - } -#endif - } - cs->BC_Write_Reg(cs, 1, ISAR_HIS, his); - waitforHIA(cs, 10000); - return (1); -} - -/* Call only with IRQ disabled !!! */ -static inline void -rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg) -{ - int i; - - cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0); - if (msg && ireg->clsb) { - msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX); - for (i = 1; i < ireg->clsb; i++) - msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX); -#if DUMP_MBOXFRAME > 1 - if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256], *t; - - i = ireg->clsb; - while (i > 0) { - t = tmp; - t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb); - QuickHex(t, &msg[ireg->clsb - i], (i > 64) ? 64 : i); - debugl1(cs, "%s", tmp); - i -= 64; - } - } -#endif - } - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); -} - -/* Call only with IRQ disabled !!! */ -static inline void -get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg) -{ - ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS); - ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H); - ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L); -#if DUMP_MBOXFRAME - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb, - ireg->clsb); -#endif -} - -static int -waitrecmsg(struct IsdnCardState *cs, u_char *len, - u_char *msg, int maxdelay) -{ - int timeout = 0; - struct isar_reg *ir = cs->bcs[0].hw.isar.reg; - - - while ((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && - (timeout++ < maxdelay)) - udelay(1); - if (timeout > maxdelay) { - printk(KERN_WARNING"isar recmsg IRQSTA timeout\n"); - return (0); - } - get_irq_infos(cs, ir); - rcv_mbox(cs, ir, msg); - *len = ir->clsb; - return (1); -} - -int -ISARVersion(struct IsdnCardState *cs, char *s) -{ - int ver; - u_char msg[] = ISAR_MSG_HWVER; - u_char tmp[64]; - u_char len; - u_long flags; - int debug; - - cs->cardmsg(cs, CARD_RESET, NULL); - spin_lock_irqsave(&cs->lock, flags); - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - debug = cs->debug; - cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); - if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) { - spin_unlock_irqrestore(&cs->lock, flags); - return (-1); - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - spin_unlock_irqrestore(&cs->lock, flags); - return (-2); - } - cs->debug = debug; - if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) { - if (len == 1) { - ver = tmp[0] & 0xf; - printk(KERN_INFO "%s ISAR version %d\n", s, ver); - } else - ver = -3; - } else - ver = -4; - spin_unlock_irqrestore(&cs->lock, flags); - return (ver); -} - -static int -isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf) -{ - int cfu_ret, ret, size, cnt, debug; - u_char len, nom, noc; - u_short sadr, left, *sp; - u_char __user *p = buf; - u_char *msg, *tmpmsg, *mp, tmp[64]; - u_long flags; - struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; - - struct {u_short sadr; - u_short len; - u_short d_key; - } blk_head; - -#define BLK_HEAD_SIZE 6 - if (1 != (ret = ISARVersion(cs, "Testing"))) { - printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret); - return (1); - } - debug = cs->debug; -#if DBG_LOADFIRM < 2 - cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); -#endif - - cfu_ret = copy_from_user(&size, p, sizeof(int)); - if (cfu_ret) { - printk(KERN_ERR "isar_load_firmware copy_from_user ret %d\n", cfu_ret); - return -EFAULT; - } - p += sizeof(int); - printk(KERN_DEBUG"isar_load_firmware size: %d\n", size); - cnt = 0; - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - if (!(msg = kmalloc(256, GFP_KERNEL))) { - printk(KERN_ERR"isar_load_firmware no buffer\n"); - return (1); - } - if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) { - printk(KERN_ERR"isar_load_firmware no tmp buffer\n"); - kfree(msg); - return (1); - } - spin_lock_irqsave(&cs->lock, flags); - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - spin_unlock_irqrestore(&cs->lock, flags); - while (cnt < size) { - if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) { - printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - goto reterror; - } -#ifdef __BIG_ENDIAN - sadr = (blk_head.sadr & 0xff) * 256 + blk_head.sadr / 256; - blk_head.sadr = sadr; - sadr = (blk_head.len & 0xff) * 256 + blk_head.len / 256; - blk_head.len = sadr; - sadr = (blk_head.d_key & 0xff) * 256 + blk_head.d_key / 256; - blk_head.d_key = sadr; -#endif /* __BIG_ENDIAN */ - cnt += BLK_HEAD_SIZE; - p += BLK_HEAD_SIZE; - printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", - blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); - sadr = blk_head.sadr; - left = blk_head.len; - spin_lock_irqsave(&cs->lock, flags); - if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) { - printk(KERN_ERR"isar sendmsg dkey failed\n"); - ret = 1; goto reterr_unlock; - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - printk(KERN_ERR"isar waitrecmsg dkey failed\n"); - ret = 1; goto reterr_unlock; - } - if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) { - printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n", - ireg->iis, ireg->cmsb, len); - ret = 1; goto reterr_unlock; - } - spin_unlock_irqrestore(&cs->lock, flags); - while (left > 0) { - if (left > 126) - noc = 126; - else - noc = left; - nom = 2 * noc; - mp = msg; - *mp++ = sadr / 256; - *mp++ = sadr % 256; - left -= noc; - *mp++ = noc; - if ((ret = copy_from_user(tmpmsg, p, nom))) { - printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - goto reterror; - } - p += nom; - cnt += nom; - nom += 3; - sp = (u_short *)tmpmsg; -#if DBG_LOADFIRM - printk(KERN_DEBUG"isar: load %3d words at %04x left %d\n", - noc, sadr, left); -#endif - sadr += noc; - while (noc) { -#ifdef __BIG_ENDIAN - *mp++ = *sp % 256; - *mp++ = *sp / 256; -#else - *mp++ = *sp / 256; - *mp++ = *sp % 256; -#endif /* __BIG_ENDIAN */ - sp++; - noc--; - } - spin_lock_irqsave(&cs->lock, flags); - if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) { - printk(KERN_ERR"isar sendmsg prog failed\n"); - ret = 1; goto reterr_unlock; - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - printk(KERN_ERR"isar waitrecmsg prog failed\n"); - ret = 1; goto reterr_unlock; - } - if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) { - printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n", - ireg->iis, ireg->cmsb, len); - ret = 1; goto reterr_unlock; - } - spin_unlock_irqrestore(&cs->lock, flags); - } - printk(KERN_DEBUG"isar firmware block %5d words loaded\n", - blk_head.len); - } - /* 10ms delay */ - cnt = 10; - while (cnt--) - udelay(1000); - msg[0] = 0xff; - msg[1] = 0xfe; - ireg->bstat = 0; - spin_lock_irqsave(&cs->lock, flags); - if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) { - printk(KERN_ERR"isar sendmsg start dsp failed\n"); - ret = 1; goto reterr_unlock; - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - printk(KERN_ERR"isar waitrecmsg start dsp failed\n"); - ret = 1; goto reterr_unlock; - } - if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) { - printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n", - ireg->iis, ireg->cmsb, len); - ret = 1; goto reterr_unlock; - } else - printk(KERN_DEBUG"isar start dsp success\n"); - /* NORMAL mode entered */ - /* Enable IRQs of ISAR */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA); - spin_unlock_irqrestore(&cs->lock, flags); - cnt = 1000; /* max 1s */ - while ((!ireg->bstat) && cnt) { - udelay(1000); - cnt--; - } - if (!cnt) { - printk(KERN_ERR"isar no general status event received\n"); - ret = 1; goto reterror; - } else { - printk(KERN_DEBUG"isar general status event %x\n", - ireg->bstat); - } - /* 10ms delay */ - cnt = 10; - while (cnt--) - udelay(1000); - spin_lock_irqsave(&cs->lock, flags); - ireg->iis = 0; - if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { - printk(KERN_ERR"isar sendmsg self tst failed\n"); - ret = 1; goto reterr_unlock; - } - cnt = 10000; /* max 100 ms */ - spin_unlock_irqrestore(&cs->lock, flags); - while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { - udelay(10); - cnt--; - } - udelay(1000); - if (!cnt) { - printk(KERN_ERR"isar no self tst response\n"); - ret = 1; goto reterror; - } - if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) - && (ireg->par[0] == 0)) { - printk(KERN_DEBUG"isar selftest OK\n"); - } else { - printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n", - ireg->cmsb, ireg->clsb, ireg->par[0]); - ret = 1; goto reterror; - } - spin_lock_irqsave(&cs->lock, flags); - ireg->iis = 0; - if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { - printk(KERN_ERR"isar RQST SVN failed\n"); - ret = 1; goto reterr_unlock; - } - spin_unlock_irqrestore(&cs->lock, flags); - cnt = 30000; /* max 300 ms */ - while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { - udelay(10); - cnt--; - } - udelay(1000); - if (!cnt) { - printk(KERN_ERR"isar no SVN response\n"); - ret = 1; goto reterror; - } else { - if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1)) - printk(KERN_DEBUG"isar software version %#x\n", - ireg->par[0]); - else { - printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n", - ireg->cmsb, ireg->clsb, cnt); - ret = 1; goto reterror; - } - } - spin_lock_irqsave(&cs->lock, flags); - cs->debug = debug; - isar_setup(cs); - - ret = 0; -reterr_unlock: - spin_unlock_irqrestore(&cs->lock, flags); -reterror: - cs->debug = debug; - if (ret) - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - kfree(msg); - kfree(tmpmsg); - return (ret); -} - -#define B_LL_NOCARRIER 8 -#define B_LL_CONNECT 9 -#define B_LL_OK 10 - -static void -isar_bh(struct work_struct *work) -{ - struct BCState *bcs = container_of(work, struct BCState, tqueue); - - BChannel_bh(work); - if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); - if (test_and_clear_bit(B_LL_CONNECT, &bcs->event)) - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - if (test_and_clear_bit(B_LL_OK, &bcs->event)) - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK); -} - -static void -send_DLE_ETX(struct BCState *bcs) -{ - u_char dleetx[2] = {DLE, ETX}; - struct sk_buff *skb; - - if ((skb = dev_alloc_skb(2))) { - skb_put_data(skb, dleetx, 2); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } else { - printk(KERN_WARNING "HiSax: skb out of memory\n"); - } -} - -static inline int -dle_count(unsigned char *buf, int len) -{ - int count = 0; - - while (len--) - if (*buf++ == DLE) - count++; - return count; -} - -static inline void -insert_dle(unsigned char *dest, unsigned char *src, int count) { - /* in input stream have to be flagged as */ - while (count--) { - *dest++ = *src; - if (*src++ == DLE) - *dest++ = DLE; - } -} - -static void -isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) -{ - u_char *ptr; - struct sk_buff *skb; - struct isar_reg *ireg = bcs->hw.isar.reg; - - if (!ireg->clsb) { - debugl1(cs, "isar zero len frame"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - return; - } - switch (bcs->mode) { - case L1_MODE_NULL: - debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - break; - case L1_MODE_TRANS: - case L1_MODE_V32: - if ((skb = dev_alloc_skb(ireg->clsb))) { - rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb)); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } else { - printk(KERN_WARNING "HiSax: skb out of memory\n"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case L1_MODE_HDLC: - if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: incoming packet too large"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - } else if (ireg->cmsb & HDLC_ERROR) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame error %x len %d", - ireg->cmsb, ireg->clsb); -#ifdef ERROR_STATISTIC - if (ireg->cmsb & HDLC_ERR_RER) - bcs->err_inv++; - if (ireg->cmsb & HDLC_ERR_CER) - bcs->err_crc++; -#endif - bcs->hw.isar.rcvidx = 0; - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } else { - if (ireg->cmsb & HDLC_FSD) - bcs->hw.isar.rcvidx = 0; - ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; - bcs->hw.isar.rcvidx += ireg->clsb; - rcv_mbox(cs, ireg, ptr); - if (ireg->cmsb & HDLC_FED) { - if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame to short %d", - bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx - 2))) { - printk(KERN_WARNING "ISAR: receive out of memory\n"); - } else { - skb_put_data(skb, bcs->hw.isar.rcvbuf, - bcs->hw.isar.rcvidx - 2); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - bcs->hw.isar.rcvidx = 0; - } - } - break; - case L1_MODE_FAX: - if (bcs->hw.isar.state != STFAX_ACTIV) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: not ACTIV"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - break; - } - if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { - rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf); - bcs->hw.isar.rcvidx = ireg->clsb + - dle_count(bcs->hw.isar.rcvbuf, ireg->clsb); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)", - ireg->clsb, bcs->hw.isar.rcvidx); - if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { - insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx), - bcs->hw.isar.rcvbuf, ireg->clsb); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - if (ireg->cmsb & SART_NMD) { /* ABORT */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: no more data"); - bcs->hw.isar.rcvidx = 0; - send_DLE_ETX(bcs); - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, - 0, NULL); - bcs->hw.isar.state = STFAX_ESCAPE; - schedule_event(bcs, B_LL_NOCARRIER); - } - } else { - printk(KERN_WARNING "HiSax: skb out of memory\n"); - } - break; - } - if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: unknown fax mode %x", - bcs->hw.isar.cmd); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - break; - } - /* PCTRL_CMD_FRH */ - if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: incoming packet too large"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - } else if (ireg->cmsb & HDLC_ERROR) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame error %x len %d", - ireg->cmsb, ireg->clsb); - bcs->hw.isar.rcvidx = 0; - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } else { - if (ireg->cmsb & HDLC_FSD) { - bcs->hw.isar.rcvidx = 0; - } - ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; - bcs->hw.isar.rcvidx += ireg->clsb; - rcv_mbox(cs, ireg, ptr); - if (ireg->cmsb & HDLC_FED) { - int len = bcs->hw.isar.rcvidx + - dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); - if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame to short %d", - bcs->hw.isar.rcvidx); - printk(KERN_WARNING "ISAR: frame to short %d\n", - bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(len))) { - printk(KERN_WARNING "ISAR: receive out of memory\n"); - } else { - insert_dle((u_char *)skb_put(skb, len), - bcs->hw.isar.rcvbuf, - bcs->hw.isar.rcvidx); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - send_DLE_ETX(bcs); - schedule_event(bcs, B_LL_OK); - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - } - bcs->hw.isar.rcvidx = 0; - } - } - if (ireg->cmsb & SART_NMD) { /* ABORT */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: no more data"); - bcs->hw.isar.rcvidx = 0; - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); - bcs->hw.isar.state = STFAX_ESCAPE; - if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) { - send_DLE_ETX(bcs); - schedule_event(bcs, B_LL_NOCARRIER); - } - } - break; - default: - printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - break; - } -} - -void -isar_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int count; - u_char msb; - u_char *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "isar_fill_fifo"); - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - if (!(bcs->hw.isar.reg->bstat & - (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) - return; - if (bcs->tx_skb->len > bcs->hw.isar.mml) { - msb = 0; - count = bcs->hw.isar.mml; - } else { - count = bcs->tx_skb->len; - msb = HDLC_FED; - } - ptr = bcs->tx_skb->data; - if (!bcs->hw.isar.txcnt) { - msb |= HDLC_FST; - if ((bcs->mode == L1_MODE_FAX) && - (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) { - if (bcs->tx_skb->len > 1) { - if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) - /* last frame */ - test_and_set_bit(BC_FLG_LASTDATA, - &bcs->Flag); - } - } - } - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.isar.txcnt += count; - switch (bcs->mode) { - case L1_MODE_NULL: - printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); - break; - case L1_MODE_TRANS: - case L1_MODE_V32: - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - 0, count, ptr); - break; - case L1_MODE_HDLC: - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - msb, count, ptr); - break; - case L1_MODE_FAX: - if (bcs->hw.isar.state != STFAX_ACTIV) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_fill_fifo: not ACTIV"); - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - msb, count, ptr); - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - 0, count, ptr); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_fill_fifo: not FTH/FTM"); - } - break; - default: - if (cs->debug) - debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode); - printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode); - break; - } -} - -static inline -struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath) -{ - if ((!dpath) || (dpath == 3)) - return (NULL); - if (cs->bcs[0].hw.isar.dpath == dpath) - return (&cs->bcs[0]); - if (cs->bcs[1].hw.isar.dpath == dpath) - return (&cs->bcs[1]); - return (NULL); -} - -static void -send_frames(struct BCState *bcs) -{ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - isar_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.isar.txcnt; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - if (bcs->mode == L1_MODE_FAX) { - if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { - if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { - test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); - } - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { - if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) { - test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag); - test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); - } - } - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->hw.isar.txcnt = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.isar.txcnt = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - isar_fill_fifo(bcs); - } else { - if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) { - if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) { - if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) { - u_char dummy = 0; - sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) | - ISAR_HIS_SDATA, 0x01, 1, &dummy); - } - test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag); - } else { - schedule_event(bcs, B_LL_CONNECT); - } - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } -} - -static inline void -check_send(struct IsdnCardState *cs, u_char rdm) -{ - struct BCState *bcs; - - if (rdm & BSTAT_RDM1) { - if ((bcs = sel_bcs_isar(cs, 1))) { - if (bcs->mode) { - send_frames(bcs); - } - } - } - if (rdm & BSTAT_RDM2) { - if ((bcs = sel_bcs_isar(cs, 2))) { - if (bcs->mode) { - send_frames(bcs); - } - } - } - -} - -static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", - "NODEF4", "300", "600", "1200", "2400", - "4800", "7200", "9600nt", "9600t", "12000", - "14400", "WRONG"}; -static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", - "Bell103", "V23", "Bell202", "V17", "V29", - "V27ter"}; - -static void -isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { - struct IsdnCardState *cs = bcs->cs; - u_char ril = ireg->par[0]; - u_char rim; - - if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags)) - return; - if (ril > 14) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "wrong pstrsp ril=%d", ril); - ril = 15; - } - switch (ireg->par[1]) { - case 0: - rim = 0; - break; - case 0x20: - rim = 2; - break; - case 0x40: - rim = 3; - break; - case 0x41: - rim = 4; - break; - case 0x51: - rim = 5; - break; - case 0x61: - rim = 6; - break; - case 0x71: - rim = 7; - break; - case 0x82: - rim = 8; - break; - case 0x92: - rim = 9; - break; - case 0xa2: - rim = 10; - break; - default: - rim = 1; - break; - } - sprintf(bcs->hw.isar.conmsg, "%s %s", dmril[ril], dmrim[rim]); - bcs->conmsg = bcs->hw.isar.conmsg; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump strsp %s", bcs->conmsg); -} - -static void -isar_pump_statev_modem(struct BCState *bcs, u_char devt) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - - switch (devt) { - case PSEV_10MS_TIMER: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev TIMER"); - break; - case PSEV_CON_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CONNECT"); - l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); - break; - case PSEV_CON_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev NO CONNECT"); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - l1_msg_b(bcs->st, PH_DEACTIVATE | REQUEST, NULL); - break; - case PSEV_V24_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev V24 OFF"); - break; - case PSEV_CTS_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CTS ON"); - break; - case PSEV_CTS_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CTS OFF"); - break; - case PSEV_DCD_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CARRIER ON"); - test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - break; - case PSEV_DCD_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CARRIER OFF"); - break; - case PSEV_DSR_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev DSR ON"); - break; - case PSEV_DSR_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev DSR_OFF"); - break; - case PSEV_REM_RET: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev REMOTE RETRAIN"); - break; - case PSEV_REM_REN: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev REMOTE RENEGOTIATE"); - break; - case PSEV_GSTN_CLR: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev GSTN CLEAR"); - break; - default: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "unknown pump stev %x", devt); - break; - } -} - -static void -ll_deliver_faxstat(struct BCState *bcs, u_char status) -{ - isdn_ctrl ic; - struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "HL->LL FAXIND %x", status); - ic.driver = bcs->cs->myid; - ic.command = ISDN_STAT_FAXIND; - ic.arg = chanp->chan; - ic.parm.aux.cmd = status; - bcs->cs->iif.statcallb(&ic); -} - -static void -isar_pump_statev_fax(struct BCState *bcs, u_char devt) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char p1; - - switch (devt) { - case PSEV_10MS_TIMER: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev TIMER"); - break; - case PSEV_RSP_READY: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_READY"); - bcs->hw.isar.state = STFAX_READY; - l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); - if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { - isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3); - } else { - isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3); - } - break; - case PSEV_LINE_TX_H: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_TX_H"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_TX_H wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_LINE_RX_H: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_RX_H"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_RX_H wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_LINE_TX_B: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_TX_B"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_TX_B wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_LINE_RX_B: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_RX_B"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_RX_B wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_RSP_CONN: - if (bcs->hw.isar.state == STFAX_CONT) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_CONN"); - bcs->hw.isar.state = STFAX_ACTIV; - test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { - /* 1s Flags before data */ - if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) - del_timer(&bcs->hw.isar.ftimer); - /* 1000 ms */ - bcs->hw.isar.ftimer.expires = - jiffies + ((1000 * HZ) / 1000); - test_and_set_bit(BC_FLG_LL_CONN, - &bcs->Flag); - add_timer(&bcs->hw.isar.ftimer); - } else { - schedule_event(bcs, B_LL_CONNECT); - } - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev RSP_CONN wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_FLAGS_DET: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev FLAGS_DET"); - break; - case PSEV_RSP_DISC: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_DISC"); - if (bcs->hw.isar.state == STFAX_ESCAPE) { - p1 = 5; - switch (bcs->hw.isar.newcmd) { - case 0: - bcs->hw.isar.state = STFAX_READY; - break; - case PCTRL_CMD_FTM: - p1 = 2; - /* fall through */ - case PCTRL_CMD_FTH: - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_SILON, 1, &p1); - bcs->hw.isar.state = STFAX_SILDET; - break; - case PCTRL_CMD_FRM: - if (frm_extra_delay) - mdelay(frm_extra_delay); - /* fall through */ - case PCTRL_CMD_FRH: - p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.cmd = bcs->hw.isar.newcmd; - bcs->hw.isar.newcmd = 0; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - bcs->hw.isar.cmd, 1, &p1); - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.try_mod = 3; - break; - default: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd); - break; - } - } else if (bcs->hw.isar.state == STFAX_ACTIV) { - if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) { - schedule_event(bcs, B_LL_OK); - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { - send_DLE_ETX(bcs); - schedule_event(bcs, B_LL_NOCARRIER); - } else { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); - } - bcs->hw.isar.state = STFAX_READY; - } else { - bcs->hw.isar.state = STFAX_READY; - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); - } - break; - case PSEV_RSP_SILDET: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_SILDET"); - if (bcs->hw.isar.state == STFAX_SILDET) { - p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.cmd = bcs->hw.isar.newcmd; - bcs->hw.isar.newcmd = 0; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - bcs->hw.isar.cmd, 1, &p1); - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.try_mod = 3; - } - break; - case PSEV_RSP_SILOFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_SILOFF"); - break; - case PSEV_RSP_FCERR: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_FCERR try %d", - bcs->hw.isar.try_mod); - if (bcs->hw.isar.try_mod--) { - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - bcs->hw.isar.cmd, 1, - &bcs->hw.isar.mod); - break; - } - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_FCERR"); - bcs->hw.isar.state = STFAX_ESCAPE; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); - break; - default: - break; - } -} - -static char debbuf[128]; - -void -isar_int_main(struct IsdnCardState *cs) -{ - struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; - struct BCState *bcs; - - get_irq_infos(cs, ireg); - switch (ireg->iis & ISAR_IIS_MSCMSD) { - case ISAR_IIS_RDATA: - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - isar_rcv_frame(cs, bcs); - } else { - debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case ISAR_IIS_GSTEV: - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - ireg->bstat |= ireg->cmsb; - check_send(cs, ireg->cmsb); - break; - case ISAR_IIS_BSTEV: -#ifdef ERROR_STATISTIC - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - if (ireg->cmsb == BSTEV_TBO) - bcs->err_tx++; - if (ireg->cmsb == BSTEV_RBO) - bcs->err_rdo++; - } -#endif - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Buffer STEV dpath%d msb(%x)", - ireg->iis >> 6, ireg->cmsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - break; - case ISAR_IIS_PSTEV: - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - rcv_mbox(cs, ireg, (u_char *)ireg->par); - if (bcs->mode == L1_MODE_V32) { - isar_pump_statev_modem(bcs, ireg->cmsb); - } else if (bcs->mode == L1_MODE_FAX) { - isar_pump_statev_fax(bcs, ireg->cmsb); - } else if (ireg->cmsb == PSEV_10MS_TIMER) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev TIMER"); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar IIS_PSTEV pmode %d stat %x", - bcs->mode, ireg->cmsb); - } - } else { - debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case ISAR_IIS_PSTRSP: - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - rcv_mbox(cs, ireg, (u_char *)ireg->par); - isar_pump_status_rsp(bcs, ireg); - } else { - debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case ISAR_IIS_DIAG: - case ISAR_IIS_BSTRSP: - case ISAR_IIS_IOM2RSP: - rcv_mbox(cs, ireg, (u_char *)ireg->par); - if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO)) - == L1_DEB_HSCX) { - u_char *tp = debbuf; - - tp += sprintf(debbuf, "msg iis(%x) msb(%x)", - ireg->iis, ireg->cmsb); - QuickHex(tp, (u_char *)ireg->par, ireg->clsb); - debugl1(cs, "%s", debbuf); - } - break; - case ISAR_IIS_INVMSG: - rcv_mbox(cs, ireg, debbuf); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "invalid msg his:%x", - ireg->cmsb); - break; - default: - rcv_mbox(cs, ireg, debbuf); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "unhandled msg iis(%x) ctrl(%x/%x)", - ireg->iis, ireg->cmsb, ireg->clsb); - break; - } -} - -static void -ftimer_handler(struct timer_list *t) { - struct BCState *bcs = from_timer(bcs, t, hw.isar.ftimer); - if (bcs->cs->debug) - debugl1(bcs->cs, "ftimer flags %04lx", - bcs->Flag); - test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag); - if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) { - schedule_event(bcs, B_LL_CONNECT); - } - if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) { - schedule_event(bcs, B_LL_OK); - } -} - -static void -setup_pump(struct BCState *bcs) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char ctrl, param[6]; - - switch (bcs->mode) { - case L1_MODE_NULL: - case L1_MODE_TRANS: - case L1_MODE_HDLC: - sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); - break; - case L1_MODE_V32: - ctrl = PMOD_DATAMODEM; - if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { - ctrl |= PCTRL_ORIG; - param[5] = PV32P6_CTN; - } else { - param[5] = PV32P6_ATN; - } - param[0] = para_TOA; /* 6 db */ - param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | - PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; - param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; - param[3] = PV32P4_UT144; - param[4] = PV32P5_UT144; - sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); - break; - case L1_MODE_FAX: - ctrl = PMOD_FAX; - if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { - ctrl |= PCTRL_ORIG; - param[1] = PFAXP2_CTN; - } else { - param[1] = PFAXP2_ATN; - } - param[0] = para_TOA; /* 6 db */ - sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); - bcs->hw.isar.state = STFAX_NULL; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.newmod = 0; - test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag); - break; - } - udelay(1000); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - udelay(1000); -} - -static void -setup_sart(struct BCState *bcs) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char ctrl, param[2]; - - switch (bcs->mode) { - case L1_MODE_NULL: - sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, - NULL); - break; - case L1_MODE_TRANS: - sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, - "\0\0"); - break; - case L1_MODE_HDLC: - param[0] = 0; - sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, - param); - break; - case L1_MODE_V32: - ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; - param[0] = S_P1_CHS_8; - param[1] = S_P2_BFT_DEF; - sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, - param); - break; - case L1_MODE_FAX: - /* SART must not configured with FAX */ - break; - } - udelay(1000); - sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); - udelay(1000); -} - -static void -setup_iom2(struct BCState *bcs) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; - - if (bcs->channel) - msg[1] = msg[3] = 1; - switch (bcs->mode) { - case L1_MODE_NULL: - cmsb = 0; - /* dummy slot */ - msg[1] = msg[3] = bcs->hw.isar.dpath + 2; - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - break; - case L1_MODE_V32: - case L1_MODE_FAX: - cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV; - break; - } - sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); - udelay(1000); - sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); - udelay(1000); -} - -static int -modeisar(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - /* Here we are selecting the best datapath for requested mode */ - if (bcs->mode == L1_MODE_NULL) { /* New Setup */ - bcs->channel = bc; - switch (mode) { - case L1_MODE_NULL: /* init */ - if (!bcs->hw.isar.dpath) - /* no init for dpath 0 */ - return (0); - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - /* best is datapath 2 */ - if (!test_and_set_bit(ISAR_DP2_USE, - &bcs->hw.isar.reg->Flags)) - bcs->hw.isar.dpath = 2; - else if (!test_and_set_bit(ISAR_DP1_USE, - &bcs->hw.isar.reg->Flags)) - bcs->hw.isar.dpath = 1; - else { - printk(KERN_WARNING"isar modeisar both paths in use\n"); - return (1); - } - break; - case L1_MODE_V32: - case L1_MODE_FAX: - /* only datapath 1 */ - if (!test_and_set_bit(ISAR_DP1_USE, - &bcs->hw.isar.reg->Flags)) - bcs->hw.isar.dpath = 1; - else { - printk(KERN_WARNING"isar modeisar analog functions only with DP1\n"); - debugl1(cs, "isar modeisar analog functions only with DP1"); - return (1); - } - break; - } - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar dp%d mode %d->%d ichan %d", - bcs->hw.isar.dpath, bcs->mode, mode, bc); - bcs->mode = mode; - setup_pump(bcs); - setup_iom2(bcs); - setup_sart(bcs); - if (bcs->mode == L1_MODE_NULL) { - /* Clear resources */ - if (bcs->hw.isar.dpath == 1) - test_and_clear_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags); - else if (bcs->hw.isar.dpath == 2) - test_and_clear_bit(ISAR_DP2_USE, &bcs->hw.isar.reg->Flags); - bcs->hw.isar.dpath = 0; - } - return (0); -} - -static void -isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) -{ - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char ctrl = 0, nom = 0, p1 = 0; - - switch (cmd) { - case ISDN_FAX_CLASS1_FTM: - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FTM; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FTM) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FTM; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAX_CLASS1_FTH: - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FTH; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FTH) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FTH; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAX_CLASS1_FRM: - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FRM; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FRM) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FRM; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAX_CLASS1_FRH: - test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FRH; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FRH) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FRH; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAXPUMP_HALT: - bcs->hw.isar.state = STFAX_NULL; - nom = 0; - ctrl = PCTRL_CMD_HALT; - break; - } - if (ctrl) - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); -} - -static void -isar_setup(struct IsdnCardState *cs) -{ - u_char msg; - int i; - - /* Dpath 1, 2 */ - msg = 61; - for (i = 0; i < 2; i++) { - /* Buffer Config */ - sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | - ISAR_HIS_P12CFG, 4, 1, &msg); - cs->bcs[i].hw.isar.mml = msg; - cs->bcs[i].mode = 0; - cs->bcs[i].hw.isar.dpath = i + 1; - modeisar(&cs->bcs[i], 0, 0); - INIT_WORK(&cs->bcs[i].tqueue, isar_bh); - } -} - -static void -isar_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - int ret; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "DRQ set BC_FLG_BUSY"); - bcs->hw.isar.txcnt = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "PUI set BC_FLG_BUSY"); - bcs->tx_skb = skb; - bcs->hw.isar.txcnt = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - bcs->hw.isar.conmsg[0] = 0; - if (test_bit(FLG_ORIG, &st->l2.flag)) - test_and_set_bit(BC_FLG_ORIG, &bcs->Flag); - else - test_and_clear_bit(BC_FLG_ORIG, &bcs->Flag); - switch (st->l1.mode) { - case L1_MODE_TRANS: - case L1_MODE_HDLC: - ret = modeisar(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - if (ret) - l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); - else - l1_msg_b(st, PH_ACTIVATE | REQUEST, arg); - break; - case L1_MODE_V32: - case L1_MODE_FAX: - ret = modeisar(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - if (ret) - l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); - break; - default: - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - } - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - switch (st->l1.mode) { - case L1_MODE_TRANS: - case L1_MODE_HDLC: - case L1_MODE_V32: - break; - case L1_MODE_FAX: - isar_pump_cmd(bcs, ISDN_FAXPUMP_HALT, 0); - break; - } - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "PDAC clear BC_FLG_BUSY"); - modeisar(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_isarstate(struct BCState *bcs) -{ - modeisar(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.isar.rcvbuf); - bcs->hw.isar.rcvbuf = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY"); - } - } - del_timer(&bcs->hw.isar.ftimer); -} - -static int -open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.isar.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for isar.rcvbuf\n"); - return (1); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "openisar clear BC_FLG_BUSY"); - bcs->event = 0; - bcs->hw.isar.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_isar(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_isarstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = isar_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -int -isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { - u_long adr; - int features, i; - struct BCState *bcs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd cmd/ch %x/%ld", ic->command, ic->arg); - switch (ic->command) { - case (ISDN_CMD_FAXCMD): - bcs = cs->channel[ic->arg].bcs; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d", - ic->parm.aux.cmd, ic->parm.aux.subcmd); - switch (ic->parm.aux.cmd) { - case ISDN_FAX_CLASS1_CTRL: - if (ic->parm.aux.subcmd == ETX) - test_and_set_bit(BC_FLG_DLEETX, - &bcs->Flag); - break; - case ISDN_FAX_CLASS1_FTS: - if (ic->parm.aux.subcmd == AT_QUERY) { - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { - strcpy(ic->parm.aux.para, "0-255"); - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd %s=%d", - FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]); - if (bcs->hw.isar.state == STFAX_READY) { - if (!ic->parm.aux.para[0]) { - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK; - cs->iif.statcallb(ic); - return (0); - } - if (!test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) { - /* n*10 ms */ - bcs->hw.isar.ftimer.expires = - jiffies + ((ic->parm.aux.para[0] * 10 * HZ) / 1000); - test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag); - add_timer(&bcs->hw.isar.ftimer); - return (0); - } else { - if (cs->debug) - debugl1(cs, "isar FTS=%d and FTI busy", - ic->parm.aux.para[0]); - } - } else { - if (cs->debug) - debugl1(cs, "isar FTS=%d and isar.state not ready(%x)", - ic->parm.aux.para[0], bcs->hw.isar.state); - } - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; - cs->iif.statcallb(ic); - } - break; - case ISDN_FAX_CLASS1_FRM: - case ISDN_FAX_CLASS1_FRH: - case ISDN_FAX_CLASS1_FTM: - case ISDN_FAX_CLASS1_FTH: - if (ic->parm.aux.subcmd == AT_QUERY) { - sprintf(ic->parm.aux.para, - "%d", bcs->hw.isar.mod); - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { - char *p = ic->parm.aux.para; - for (i = 0; i < FAXMODCNT; i++) - if ((1 << i) & modmask) - p += sprintf(p, "%d,", faxmodulation[i]); - p--; - *p = 0; - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd %s=%d", - FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]); - for (i = 0; i < FAXMODCNT; i++) - if (faxmodulation[i] == ic->parm.aux.para[0]) - break; - if ((i < FAXMODCNT) && ((1 << i) & modmask) && - test_bit(BC_FLG_INIT, &bcs->Flag)) { - isar_pump_cmd(bcs, - ic->parm.aux.cmd, - ic->parm.aux.para[0]); - return (0); - } - } - /* wrong modulation or not activ */ - /* fall through */ - default: - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; - cs->iif.statcallb(ic); - } - break; - case (ISDN_CMD_IOCTL): - switch (ic->arg) { - case 9: /* load firmware */ - features = ISDN_FEATURE_L2_MODEM | - ISDN_FEATURE_L2_FAX | - ISDN_FEATURE_L3_FCLASS1; - memcpy(&adr, ic->parm.num, sizeof(ulong)); - if (isar_load_firmware(cs, (u_char __user *)adr)) - return (1); - else - ll_run(cs, features); - break; - case 20: - features = *(unsigned int *) ic->parm.num; - printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n", - modmask, features); - modmask = features; - break; - case 21: - features = *(unsigned int *) ic->parm.num; - printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n", - frm_extra_delay, features); - if (features >= 0) - frm_extra_delay = features; - break; - case 22: - features = *(unsigned int *) ic->parm.num; - printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n", - para_TOA, features); - if (features >= 0 && features < 32) - para_TOA = features; - break; - default: - printk(KERN_DEBUG "HiSax: invalid ioctl %d\n", - (int) ic->arg); - return (-EINVAL); - } - break; - default: - return (-EINVAL); - } - return (0); -} - -void initisar(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_isar; - cs->bcs[1].BC_SetStack = setstack_isar; - cs->bcs[0].BC_Close = close_isarstate; - cs->bcs[1].BC_Close = close_isarstate; - timer_setup(&cs->bcs[0].hw.isar.ftimer, ftimer_handler, 0); - timer_setup(&cs->bcs[1].hw.isar.ftimer, ftimer_handler, 0); -} diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h deleted file mode 100644 index 0f4d101faf37..000000000000 --- a/drivers/isdn/hisax/isar.h +++ /dev/null @@ -1,222 +0,0 @@ -/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $ - * - * ISAR (Siemens PSB 7110) specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define ISAR_IRQMSK 0x04 -#define ISAR_IRQSTA 0x04 -#define ISAR_IRQBIT 0x75 -#define ISAR_CTRL_H 0x61 -#define ISAR_CTRL_L 0x60 -#define ISAR_IIS 0x58 -#define ISAR_IIA 0x58 -#define ISAR_HIS 0x50 -#define ISAR_HIA 0x50 -#define ISAR_MBOX 0x4c -#define ISAR_WADR 0x4a -#define ISAR_RADR 0x48 - -#define ISAR_HIS_VNR 0x14 -#define ISAR_HIS_DKEY 0x02 -#define ISAR_HIS_FIRM 0x1e -#define ISAR_HIS_STDSP 0x08 -#define ISAR_HIS_DIAG 0x05 -#define ISAR_HIS_WAITSTATE 0x27 -#define ISAR_HIS_TIMERIRQ 0x25 -#define ISAR_HIS_P0CFG 0x3c -#define ISAR_HIS_P12CFG 0x24 -#define ISAR_HIS_SARTCFG 0x25 -#define ISAR_HIS_PUMPCFG 0x26 -#define ISAR_HIS_PUMPCTRL 0x2a -#define ISAR_HIS_IOM2CFG 0x27 -#define ISAR_HIS_IOM2REQ 0x07 -#define ISAR_HIS_IOM2CTRL 0x2b -#define ISAR_HIS_BSTREQ 0x0c -#define ISAR_HIS_PSTREQ 0x0e -#define ISAR_HIS_SDATA 0x20 -#define ISAR_HIS_DPS1 0x40 -#define ISAR_HIS_DPS2 0x80 -#define SET_DPS(x) ((x << 6) & 0xc0) - -#define ISAR_CMD_TIMERIRQ_OFF 0x20 -#define ISAR_CMD_TIMERIRQ_ON 0x21 - - -#define ISAR_IIS_MSCMSD 0x3f -#define ISAR_IIS_VNR 0x15 -#define ISAR_IIS_DKEY 0x03 -#define ISAR_IIS_FIRM 0x1f -#define ISAR_IIS_STDSP 0x09 -#define ISAR_IIS_DIAG 0x25 -#define ISAR_IIS_GSTEV 0x00 -#define ISAR_IIS_BSTEV 0x28 -#define ISAR_IIS_BSTRSP 0x2c -#define ISAR_IIS_PSTRSP 0x2e -#define ISAR_IIS_PSTEV 0x2a -#define ISAR_IIS_IOM2RSP 0x27 -#define ISAR_IIS_RDATA 0x20 -#define ISAR_IIS_INVMSG 0x3f - -#define ISAR_CTRL_SWVER 0x10 -#define ISAR_CTRL_STST 0x40 - -#define ISAR_MSG_HWVER {0x20, 0, 1} - -#define ISAR_DP1_USE 1 -#define ISAR_DP2_USE 2 -#define ISAR_RATE_REQ 3 - -#define PMOD_DISABLE 0 -#define PMOD_FAX 1 -#define PMOD_DATAMODEM 2 -#define PMOD_HALFDUPLEX 3 -#define PMOD_V110 4 -#define PMOD_DTMF 5 -#define PMOD_DTMF_TRANS 6 -#define PMOD_BYPASS 7 - -#define PCTRL_ORIG 0x80 -#define PV32P2_V23R 0x40 -#define PV32P2_V22A 0x20 -#define PV32P2_V22B 0x10 -#define PV32P2_V22C 0x08 -#define PV32P2_V21 0x02 -#define PV32P2_BEL 0x01 - -// LSB MSB in ISAR doc wrong !!! Arghhh -#define PV32P3_AMOD 0x80 -#define PV32P3_V32B 0x02 -#define PV32P3_V23B 0x01 -#define PV32P4_48 0x11 -#define PV32P5_48 0x05 -#define PV32P4_UT48 0x11 -#define PV32P5_UT48 0x0d -#define PV32P4_96 0x11 -#define PV32P5_96 0x03 -#define PV32P4_UT96 0x11 -#define PV32P5_UT96 0x0f -#define PV32P4_B96 0x91 -#define PV32P5_B96 0x0b -#define PV32P4_UTB96 0xd1 -#define PV32P5_UTB96 0x0f -#define PV32P4_120 0xb1 -#define PV32P5_120 0x09 -#define PV32P4_UT120 0xf1 -#define PV32P5_UT120 0x0f -#define PV32P4_144 0x99 -#define PV32P5_144 0x09 -#define PV32P4_UT144 0xf9 -#define PV32P5_UT144 0x0f -#define PV32P6_CTN 0x01 -#define PV32P6_ATN 0x02 - -#define PFAXP2_CTN 0x01 -#define PFAXP2_ATN 0x04 - -#define PSEV_10MS_TIMER 0x02 -#define PSEV_CON_ON 0x18 -#define PSEV_CON_OFF 0x19 -#define PSEV_V24_OFF 0x20 -#define PSEV_CTS_ON 0x21 -#define PSEV_CTS_OFF 0x22 -#define PSEV_DCD_ON 0x23 -#define PSEV_DCD_OFF 0x24 -#define PSEV_DSR_ON 0x25 -#define PSEV_DSR_OFF 0x26 -#define PSEV_REM_RET 0xcc -#define PSEV_REM_REN 0xcd -#define PSEV_GSTN_CLR 0xd4 - -#define PSEV_RSP_READY 0xbc -#define PSEV_LINE_TX_H 0xb3 -#define PSEV_LINE_TX_B 0xb2 -#define PSEV_LINE_RX_H 0xb1 -#define PSEV_LINE_RX_B 0xb0 -#define PSEV_RSP_CONN 0xb5 -#define PSEV_RSP_DISC 0xb7 -#define PSEV_RSP_FCERR 0xb9 -#define PSEV_RSP_SILDET 0xbe -#define PSEV_RSP_SILOFF 0xab -#define PSEV_FLAGS_DET 0xba - -#define PCTRL_CMD_FTH 0xa7 -#define PCTRL_CMD_FRH 0xa5 -#define PCTRL_CMD_FTM 0xa8 -#define PCTRL_CMD_FRM 0xa6 -#define PCTRL_CMD_SILON 0xac -#define PCTRL_CMD_CONT 0xa2 -#define PCTRL_CMD_ESC 0xa4 -#define PCTRL_CMD_SILOFF 0xab -#define PCTRL_CMD_HALT 0xa9 - -#define PCTRL_LOC_RET 0xcf -#define PCTRL_LOC_REN 0xce - -#define SMODE_DISABLE 0 -#define SMODE_V14 2 -#define SMODE_HDLC 3 -#define SMODE_BINARY 4 -#define SMODE_FSK_V14 5 - -#define SCTRL_HDMC_BOTH 0x00 -#define SCTRL_HDMC_DTX 0x80 -#define SCTRL_HDMC_DRX 0x40 -#define S_P1_OVSP 0x40 -#define S_P1_SNP 0x20 -#define S_P1_EOP 0x10 -#define S_P1_EDP 0x08 -#define S_P1_NSB 0x04 -#define S_P1_CHS_8 0x03 -#define S_P1_CHS_7 0x02 -#define S_P1_CHS_6 0x01 -#define S_P1_CHS_5 0x00 - -#define S_P2_BFT_DEF 0x10 - -#define IOM_CTRL_ENA 0x80 -#define IOM_CTRL_NOPCM 0x00 -#define IOM_CTRL_ALAW 0x02 -#define IOM_CTRL_ULAW 0x04 -#define IOM_CTRL_RCV 0x01 - -#define IOM_P1_TXD 0x10 - -#define HDLC_FED 0x40 -#define HDLC_FSD 0x20 -#define HDLC_FST 0x20 -#define HDLC_ERROR 0x1c -#define HDLC_ERR_FAD 0x10 -#define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x04 -#define SART_NMD 0x01 - -#define BSTAT_RDM0 0x1 -#define BSTAT_RDM1 0x2 -#define BSTAT_RDM2 0x4 -#define BSTAT_RDM3 0x8 -#define BSTEV_TBO 0x1f -#define BSTEV_RBO 0x2f - -/* FAX State Machine */ -#define STFAX_NULL 0 -#define STFAX_READY 1 -#define STFAX_LINE 2 -#define STFAX_CONT 3 -#define STFAX_ACTIV 4 -#define STFAX_ESCAPE 5 -#define STFAX_SILDET 6 - -#define ISDN_FAXPUMP_HALT 100 - -extern int ISARVersion(struct IsdnCardState *cs, char *s); -extern void isar_int_main(struct IsdnCardState *cs); -extern void initisar(struct IsdnCardState *cs); -extern void isar_fill_fifo(struct BCState *bcs); -extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic); diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c deleted file mode 100644 index a560842c0e48..000000000000 --- a/drivers/isdn/hisax/isdnl1.c +++ /dev/null @@ -1,930 +0,0 @@ -/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $ - * - * common low level stuff for Siemens Chipsetbased isdn cards - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Beat Doebeli - * - */ - -#include -#include -#include "hisax.h" -#include "isdnl1.h" - -const char *l1_revision = "$Revision: 2.46.2.5 $"; - -#define TIMER3_VALUE 7000 - -static struct Fsm l1fsm_b; -static struct Fsm l1fsm_s; - -enum { - ST_L1_F2, - ST_L1_F3, - ST_L1_F4, - ST_L1_F5, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1S_STATE_COUNT (ST_L1_F8 + 1) - -static char *strL1SState[] = -{ - "ST_L1_F2", - "ST_L1_F3", - "ST_L1_F4", - "ST_L1_F5", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -#ifdef HISAX_UINTERFACE -static -struct Fsm l1fsm_u = -{NULL, 0, 0, NULL, NULL}; - -enum { - ST_L1_RESET, - ST_L1_DEACT, - ST_L1_SYNC2, - ST_L1_TRANS, -}; - -#define L1U_STATE_COUNT (ST_L1_TRANS + 1) - -static char *strL1UState[] = -{ - "ST_L1_RESET", - "ST_L1_DEACT", - "ST_L1_SYNC2", - "ST_L1_TRANS", -}; -#endif - -enum { - ST_L1_NULL, - ST_L1_WAIT_ACT, - ST_L1_WAIT_DEACT, - ST_L1_ACTIV, -}; - -#define L1B_STATE_COUNT (ST_L1_ACTIV + 1) - -static char *strL1BState[] = -{ - "ST_L1_NULL", - "ST_L1_WAIT_ACT", - "ST_L1_WAIT_DEACT", - "ST_L1_ACTIV", -}; - -enum { - EV_PH_ACTIVATE, - EV_PH_DEACTIVATE, - EV_RESET_IND, - EV_DEACT_CNF, - EV_DEACT_IND, - EV_POWER_UP, - EV_RSYNC_IND, - EV_INFO2_IND, - EV_INFO4_IND, - EV_TIMER_DEACT, - EV_TIMER_ACT, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -static char *strL1Event[] = -{ - "EV_PH_ACTIVATE", - "EV_PH_DEACTIVATE", - "EV_RESET_IND", - "EV_DEACT_CNF", - "EV_DEACT_IND", - "EV_POWER_UP", - "EV_RSYNC_IND", - "EV_INFO2_IND", - "EV_INFO4_IND", - "EV_TIMER_DEACT", - "EV_TIMER_ACT", - "EV_TIMER3", -}; - -void -debugl1(struct IsdnCardState *cs, char *fmt, ...) -{ - va_list args; - char tmp[8]; - - va_start(args, fmt); - sprintf(tmp, "Card%d ", cs->cardnr + 1); - VHiSax_putstatus(cs, tmp, fmt, args); - va_end(args); -} - -static void -l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; - char tmp[8]; - - va_start(args, fmt); - sprintf(tmp, "Card%d ", cs->cardnr + 1); - VHiSax_putstatus(cs, tmp, fmt, args); - va_end(args); -} - -static void -L1activated(struct IsdnCardState *cs) -{ - struct PStack *st; - - st = cs->stlist; - while (st) { - if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - else - st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL); - st = st->next; - } -} - -static void -L1deactivated(struct IsdnCardState *cs) -{ - struct PStack *st; - - st = cs->stlist; - while (st) { - if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); - st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL); - st = st->next; - } - test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); -} - -void -DChannel_proc_xmt(struct IsdnCardState *cs) -{ - struct PStack *stptr; - - if (cs->tx_skb) - return; - - stptr = cs->stlist; - while (stptr != NULL) { - if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) { - stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL); - break; - } else - stptr = stptr->next; - } -} - -void -DChannel_proc_rcv(struct IsdnCardState *cs) -{ - struct sk_buff *skb, *nskb; - struct PStack *stptr = cs->stlist; - int found, tei, sapi; - - if (stptr) - if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags)) - FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL); - while ((skb = skb_dequeue(&cs->rq))) { -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 1); -#endif - stptr = cs->stlist; - if (skb->len < 3) { - debugl1(cs, "D-channel frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - if ((skb->data[0] & 1) || !(skb->data[1] & 1)) { - debugl1(cs, "D-channel frame wrong EA0/EA1"); - dev_kfree_skb(skb); - return; - } - sapi = skb->data[0] >> 2; - tei = skb->data[1] >> 1; - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 1); - if (tei == GROUP_TEI) { - if (sapi == CTRL_SAPI) { /* sapi 0 */ - while (stptr != NULL) { - if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); - else - printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); - stptr = stptr->next; - } - } else if (sapi == TEI_SAPI) { - while (stptr != NULL) { - if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb); - else - printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n"); - stptr = stptr->next; - } - } - dev_kfree_skb(skb); - } else if (sapi == CTRL_SAPI) { /* sapi 0 */ - found = 0; - while (stptr != NULL) - if (tei == stptr->l2.tei) { - stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); - found = !0; - break; - } else - stptr = stptr->next; - if (!found) - dev_kfree_skb(skb); - } else - dev_kfree_skb(skb); - } -} - -static void -BChannel_proc_xmt(struct BCState *bcs) -{ - struct PStack *st = bcs->st; - - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { - debugl1(bcs->cs, "BC_BUSY Error"); - return; - } - - if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { - if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && - skb_queue_empty(&bcs->squeue)) { - st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); - } - } -} - -static void -BChannel_proc_rcv(struct BCState *bcs) -{ - struct sk_buff *skb; - - if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) { - FsmDelTimer(&bcs->st->l1.timer, 4); - FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL); - } - while ((skb = skb_dequeue(&bcs->rqueue))) { - bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb); - } -} - -static void -BChannel_proc_ack(struct BCState *bcs) -{ - u_long flags; - int ack; - - spin_lock_irqsave(&bcs->aclock, flags); - ack = bcs->ackcnt; - bcs->ackcnt = 0; - spin_unlock_irqrestore(&bcs->aclock, flags); - if (ack) - lli_writewakeup(bcs->st, ack); -} - -void -BChannel_bh(struct work_struct *work) -{ - struct BCState *bcs = container_of(work, struct BCState, tqueue); - - if (!bcs) - return; - if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event)) - BChannel_proc_rcv(bcs); - if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event)) - BChannel_proc_xmt(bcs); - if (test_and_clear_bit(B_ACKPENDING, &bcs->event)) - BChannel_proc_ack(bcs); -} - -void -HiSax_addlist(struct IsdnCardState *cs, - struct PStack *st) -{ - st->next = cs->stlist; - cs->stlist = st; -} - -void -HiSax_rmlist(struct IsdnCardState *cs, - struct PStack *st) -{ - struct PStack *p; - - FsmDelTimer(&st->l1.timer, 0); - if (cs->stlist == st) - cs->stlist = st->next; - else { - p = cs->stlist; - while (p) - if (p->next == st) { - p->next = st->next; - return; - } else - p = p->next; - } -} - -void -init_bcstate(struct IsdnCardState *cs, int bc) -{ - struct BCState *bcs = cs->bcs + bc; - - bcs->cs = cs; - bcs->channel = bc; - INIT_WORK(&bcs->tqueue, BChannel_bh); - spin_lock_init(&bcs->aclock); - bcs->BC_SetStack = NULL; - bcs->BC_Close = NULL; - bcs->Flag = 0; -} - -#ifdef L2FRAME_DEBUG /* psa */ - -static char * -l2cmd(u_char cmd) -{ - switch (cmd & ~0x10) { - case 1: - return "RR"; - case 5: - return "RNR"; - case 9: - return "REJ"; - case 0x6f: - return "SABME"; - case 0x0f: - return "DM"; - case 3: - return "UI"; - case 0x43: - return "DISC"; - case 0x63: - return "UA"; - case 0x87: - return "FRMR"; - case 0xaf: - return "XID"; - default: - if (!(cmd & 1)) - return "I"; - else - return "invalid command"; - } -} - -static char tmpdeb[32]; - -static char * -l2frames(u_char *ptr) -{ - switch (ptr[2] & ~0x10) { - case 1: - case 5: - case 9: - sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); - break; - case 0x6f: - case 0x0f: - case 3: - case 0x43: - case 0x63: - case 0x87: - case 0xaf: - sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); - break; - default: - if (!(ptr[2] & 1)) { - sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); - break; - } else - return "invalid command"; - } - - - return tmpdeb; -} - -void -Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir) -{ - u_char *ptr; - - ptr = skb->data; - - if (ptr[0] & 1 || !(ptr[1] & 1)) - debugl1(cs, "Address not LAPD"); - else - debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)", - (dir ? "<-" : "->"), buf, l2frames(ptr), - ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1); -} -#endif - -static void -l1_reset(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3); -} - -static void -l1_deact_cnf(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_F3); - if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); -} - -static void -l1_deact_req_s(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_F3); - FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); - test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); -} - -static void -l1_power_up_s(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) { - FsmChangeState(fi, ST_L1_F4); - st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); - FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); - } else - FsmChangeState(fi, ST_L1_F3); -} - -static void -l1_go_F5(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F5); -} - -static void -l1_go_F8(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F8); -} - -static void -l1_info2_ind(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - -#ifdef HISAX_UINTERFACE - if (test_bit(FLG_L1_UINT, &st->l1.Flags)) - FsmChangeState(fi, ST_L1_SYNC2); - else -#endif - FsmChangeState(fi, ST_L1_F6); - st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); -} - -static void -l1_info4_ind(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - -#ifdef HISAX_UINTERFACE - if (test_bit(FLG_L1_UINT, &st->l1.Flags)) - FsmChangeState(fi, ST_L1_TRANS); - else -#endif - FsmChangeState(fi, ST_L1_F7); - st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); - if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) - FsmDelTimer(&st->l1.timer, 4); - if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) { - if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags)) - FsmDelTimer(&st->l1.timer, 3); - FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2); - test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags); - } -} - -static void -l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); - if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - L1deactivated(st->l1.hardware); - -#ifdef HISAX_UINTERFACE - if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) -#endif - if (st->l1.l1m.state != ST_L1_F6) { - FsmChangeState(fi, ST_L1_F3); - st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); - } -} - -static void -l1_timer_act(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags); - test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1activated(st->l1.hardware); -} - -static void -l1_timer_deact(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); - test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1deactivated(st->l1.hardware); - st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL); -} - -static void -l1_activate_s(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l1.l1hw(st, HW_RESET | REQUEST, NULL); -} - -static void -l1_activate_no(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) { - test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags); - L1deactivated(st->l1.hardware); - } -} - -static struct FsmNode L1SFnList[] __initdata = -{ - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, - {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, - {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, - {ST_L1_F3, EV_RESET_IND, l1_reset}, - {ST_L1_F4, EV_RESET_IND, l1_reset}, - {ST_L1_F5, EV_RESET_IND, l1_reset}, - {ST_L1_F6, EV_RESET_IND, l1_reset}, - {ST_L1_F7, EV_RESET_IND, l1_reset}, - {ST_L1_F8, EV_RESET_IND, l1_reset}, - {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, - {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, - {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, - {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, - {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F3, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F5, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, - {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, -}; - -#ifdef HISAX_UINTERFACE -static void -l1_deact_req_u(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_RESET); - FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); - test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); - st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); -} - -static void -l1_power_up_u(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); -} - -static void -l1_info0_ind(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_DEACT); -} - -static void -l1_activate_u(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); -} - -static struct FsmNode L1UFnList[] __initdata = -{ - {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, - {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, - {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, - {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_DEACT, EV_TIMER3, l1_timer3}, - {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, - {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, - {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, -}; - -#endif - -static void -l1b_activate(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_WAIT_ACT); - FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); -} - -static void -l1b_deactivate(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_WAIT_DEACT); - FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); -} - -static void -l1b_timer_act(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_ACTIV); - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); -} - -static void -l1b_timer_deact(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_NULL); - st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); -} - -static struct FsmNode L1BFnList[] __initdata = -{ - {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate}, - {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act}, - {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate}, - {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, -}; - -int __init -Isdnl1New(void) -{ - int retval; - - l1fsm_s.state_count = L1S_STATE_COUNT; - l1fsm_s.event_count = L1_EVENT_COUNT; - l1fsm_s.strEvent = strL1Event; - l1fsm_s.strState = strL1SState; - retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); - if (retval) - return retval; - - l1fsm_b.state_count = L1B_STATE_COUNT; - l1fsm_b.event_count = L1_EVENT_COUNT; - l1fsm_b.strEvent = strL1Event; - l1fsm_b.strState = strL1BState; - retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList)); - if (retval) { - FsmFree(&l1fsm_s); - return retval; - } -#ifdef HISAX_UINTERFACE - l1fsm_u.state_count = L1U_STATE_COUNT; - l1fsm_u.event_count = L1_EVENT_COUNT; - l1fsm_u.strEvent = strL1Event; - l1fsm_u.strState = strL1UState; - retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList)); - if (retval) { - FsmFree(&l1fsm_s); - FsmFree(&l1fsm_b); - return retval; - } -#endif - return 0; -} - -void Isdnl1Free(void) -{ -#ifdef HISAX_UINTERFACE - FsmFree(&l1fsm_u); -#endif - FsmFree(&l1fsm_s); - FsmFree(&l1fsm_b); -} - -static void -dch_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - if (cs->debug) - debugl1(cs, "PH_ACTIVATE_REQ %s", - st->l1.l1m.fsm->strState[st->l1.l1m.state]); - if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - else { - test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags); - FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg); - } - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(cs, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (cs->debug) - debugl1(cs, "dch_l2l1 msg %04X unhandled", pr); - break; - } -} - -void -l1_msg(struct IsdnCardState *cs, int pr, void *arg) { - struct PStack *st; - - st = cs->stlist; - - while (st) { - switch (pr) { - case (HW_RESET | INDICATION): - FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); - break; - case (HW_DEACTIVATE | CONFIRM): - FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); - break; - case (HW_DEACTIVATE | INDICATION): - FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); - break; - case (HW_POWERUP | CONFIRM): - FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); - break; - case (HW_RSYNC | INDICATION): - FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); - break; - case (HW_INFO2 | INDICATION): - FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); - break; - case (HW_INFO4_P8 | INDICATION): - case (HW_INFO4_P10 | INDICATION): - FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); - break; - default: - if (cs->debug) - debugl1(cs, "%s %04X unhandled", __func__, pr); - break; - } - st = st->next; - } -} - -void -l1_msg_b(struct PStack *st, int pr, void *arg) { - switch (pr) { - case (PH_ACTIVATE | REQUEST): - FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE | REQUEST): - FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL); - break; - } -} - -void -setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.hardware = cs; - st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm_s; - st->l1.l1m.state = ST_L1_F3; - st->l1.Flags = 0; -#ifdef HISAX_UINTERFACE - if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { - st->l1.l1m.fsm = &l1fsm_u; - st->l1.l1m.state = ST_L1_RESET; - st->l1.Flags = FLG_L1_UINT; - } -#endif - st->l1.l1m.debug = cs->debug; - st->l1.l1m.userdata = st; - st->l1.l1m.userint = 0; - st->l1.l1m.printdebug = l1m_debug; - FsmInitTimer(&st->l1.l1m, &st->l1.timer); - setstack_tei(st); - setstack_manager(st); - st->l1.stlistp = &(cs->stlist); - st->l2.l2l1 = dch_l2l1; - if (cs->setstack_d) - cs->setstack_d(st, cs); -} - -void -setstack_l1_B(struct PStack *st) -{ - struct IsdnCardState *cs = st->l1.hardware; - - st->l1.l1m.fsm = &l1fsm_b; - st->l1.l1m.state = ST_L1_NULL; - st->l1.l1m.debug = cs->debug; - st->l1.l1m.userdata = st; - st->l1.l1m.userint = 0; - st->l1.l1m.printdebug = l1m_debug; - st->l1.Flags = 0; - FsmInitTimer(&st->l1.l1m, &st->l1.timer); -} diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h deleted file mode 100644 index 66ddcab19bba..000000000000 --- a/drivers/isdn/hisax/isdnl1.h +++ /dev/null @@ -1,32 +0,0 @@ -/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $ - * - * Layer 1 defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define D_RCVBUFREADY 0 -#define D_XMTBUFREADY 1 -#define D_L1STATECHANGE 2 -#define D_CLEARBUSY 3 -#define D_RX_MON0 4 -#define D_RX_MON1 5 -#define D_TX_MON0 6 -#define D_TX_MON1 7 -#define E_RCVBUFREADY 8 - -#define B_RCVBUFREADY 0 -#define B_XMTBUFREADY 1 -#define B_ACKPENDING 2 - -__printf(2, 3) -void debugl1(struct IsdnCardState *cs, char *fmt, ...); -void DChannel_proc_xmt(struct IsdnCardState *cs); -void DChannel_proc_rcv(struct IsdnCardState *cs); -void l1_msg(struct IsdnCardState *cs, int pr, void *arg); -void l1_msg_b(struct PStack *st, int pr, void *arg); -void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, - int dir); -void BChannel_bh(struct work_struct *work); diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c deleted file mode 100644 index 1a40ed04cb52..000000000000 --- a/drivers/isdn/hisax/isdnl2.c +++ /dev/null @@ -1,1839 +0,0 @@ -/* $Id: isdnl2.c,v 2.30.2.4 2004/02/11 13:21:34 keil Exp $ - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include -#include -#include "hisax.h" -#include "isdnl2.h" - -const char *l2_revision = "$Revision: 2.30.2.4 $"; - -static void l2m_debug(struct FsmInst *fi, char *fmt, ...); - -static struct Fsm l2fsm; - -enum { - ST_L2_1, - ST_L2_2, - ST_L2_3, - ST_L2_4, - ST_L2_5, - ST_L2_6, - ST_L2_7, - ST_L2_8, -}; - -#define L2_STATE_COUNT (ST_L2_8 + 1) - -static char *strL2State[] = -{ - "ST_L2_1", - "ST_L2_2", - "ST_L2_3", - "ST_L2_4", - "ST_L2_5", - "ST_L2_6", - "ST_L2_7", - "ST_L2_8", -}; - -enum { - EV_L2_UI, - EV_L2_SABME, - EV_L2_DISC, - EV_L2_DM, - EV_L2_UA, - EV_L2_FRMR, - EV_L2_SUPER, - EV_L2_I, - EV_L2_DL_DATA, - EV_L2_ACK_PULL, - EV_L2_DL_UNIT_DATA, - EV_L2_DL_ESTABLISH_REQ, - EV_L2_DL_RELEASE_REQ, - EV_L2_MDL_ASSIGN, - EV_L2_MDL_REMOVE, - EV_L2_MDL_ERROR, - EV_L1_DEACTIVATE, - EV_L2_T200, - EV_L2_T203, - EV_L2_SET_OWN_BUSY, - EV_L2_CLEAR_OWN_BUSY, - EV_L2_FRAME_ERROR, -}; - -#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1) - -static char *strL2Event[] = -{ - "EV_L2_UI", - "EV_L2_SABME", - "EV_L2_DISC", - "EV_L2_DM", - "EV_L2_UA", - "EV_L2_FRMR", - "EV_L2_SUPER", - "EV_L2_I", - "EV_L2_DL_DATA", - "EV_L2_ACK_PULL", - "EV_L2_DL_UNIT_DATA", - "EV_L2_DL_ESTABLISH_REQ", - "EV_L2_DL_RELEASE_REQ", - "EV_L2_MDL_ASSIGN", - "EV_L2_MDL_REMOVE", - "EV_L2_MDL_ERROR", - "EV_L1_DEACTIVATE", - "EV_L2_T200", - "EV_L2_T203", - "EV_L2_SET_OWN_BUSY", - "EV_L2_CLEAR_OWN_BUSY", - "EV_L2_FRAME_ERROR", -}; - -static int l2addrsize(struct Layer2 *l2); - -static void -set_peer_busy(struct Layer2 *l2) { - test_and_set_bit(FLG_PEER_BUSY, &l2->flag); - if (!skb_queue_empty(&l2->i_queue) || - !skb_queue_empty(&l2->ui_queue)) - test_and_set_bit(FLG_L2BLOCK, &l2->flag); -} - -static void -clear_peer_busy(struct Layer2 *l2) { - if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) - test_and_clear_bit(FLG_L2BLOCK, &l2->flag); -} - -static void -InitWin(struct Layer2 *l2) -{ - int i; - - for (i = 0; i < MAX_WINDOW; i++) - l2->windowar[i] = NULL; -} - -static int -freewin1(struct Layer2 *l2) -{ - int i, cnt = 0; - - for (i = 0; i < MAX_WINDOW; i++) { - if (l2->windowar[i]) { - cnt++; - dev_kfree_skb(l2->windowar[i]); - l2->windowar[i] = NULL; - } - } - return cnt; -} - -static inline void -freewin(struct PStack *st) -{ - freewin1(&st->l2); -} - -static void -ReleaseWin(struct Layer2 *l2) -{ - int cnt; - - if ((cnt = freewin1(l2))) - printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt); -} - -static inline unsigned int -cansend(struct PStack *st) -{ - unsigned int p1; - - if (test_bit(FLG_MOD128, &st->l2.flag)) - p1 = (st->l2.vs - st->l2.va) % 128; - else - p1 = (st->l2.vs - st->l2.va) % 8; - return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag)); -} - -static inline void -clear_exception(struct Layer2 *l2) -{ - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - test_and_clear_bit(FLG_REJEXC, &l2->flag); - test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); - clear_peer_busy(l2); -} - -static inline int -l2headersize(struct Layer2 *l2, int ui) -{ - return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + - (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1)); -} - -inline int -l2addrsize(struct Layer2 *l2) -{ - return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); -} - -static int -sethdraddr(struct Layer2 *l2, u_char *header, int rsp) -{ - u_char *ptr = header; - int crbit = rsp; - - if (test_bit(FLG_LAPD, &l2->flag)) { - *ptr++ = (l2->sap << 2) | (rsp ? 2 : 0); - *ptr++ = (l2->tei << 1) | 1; - return (2); - } else { - if (test_bit(FLG_ORIG, &l2->flag)) - crbit = !crbit; - if (crbit) - *ptr++ = 1; - else - *ptr++ = 3; - return (1); - } -} - -static inline void -enqueue_super(struct PStack *st, - struct sk_buff *skb) -{ - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len; - st->l2.l2l1(st, PH_DATA | REQUEST, skb); -} - -#define enqueue_ui(a, b) enqueue_super(a, b) - -static inline int -IsUI(u_char *data) -{ - return ((data[0] & 0xef) == UI); -} - -static inline int -IsUA(u_char *data) -{ - return ((data[0] & 0xef) == UA); -} - -static inline int -IsDM(u_char *data) -{ - return ((data[0] & 0xef) == DM); -} - -static inline int -IsDISC(u_char *data) -{ - return ((data[0] & 0xef) == DISC); -} - -static inline int -IsSFrame(u_char *data, struct PStack *st) -{ - register u_char d = *data; - - if (!test_bit(FLG_MOD128, &st->l2.flag)) - d &= 0xf; - return (((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c)); -} - -static inline int -IsSABME(u_char *data, struct PStack *st) -{ - u_char d = data[0] & ~0x10; - - return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM); -} - -static inline int -IsREJ(u_char *data, struct PStack *st) -{ - return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ); -} - -static inline int -IsFRMR(u_char *data) -{ - return ((data[0] & 0xef) == FRMR); -} - -static inline int -IsRNR(u_char *data, struct PStack *st) -{ - return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR); -} - -static int -iframe_error(struct PStack *st, struct sk_buff *skb) -{ - int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); - int rsp = *skb->data & 0x2; - - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (rsp) - return 'L'; - - - if (skb->len < i) - return 'N'; - - if ((skb->len - i) > st->l2.maxlen) - return 'O'; - - - return 0; -} - -static int -super_error(struct PStack *st, struct sk_buff *skb) -{ - if (skb->len != l2addrsize(&st->l2) + - (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1)) - return 'N'; - - return 0; -} - -static int -unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp) -{ - int rsp = (*skb->data & 0x2) >> 1; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (rsp != wantrsp) - return 'L'; - - if (skb->len != l2addrsize(&st->l2) + 1) - return 'N'; - - return 0; -} - -static int -UI_error(struct PStack *st, struct sk_buff *skb) -{ - int rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (rsp) - return 'L'; - - if (skb->len > st->l2.maxlen + l2addrsize(&st->l2) + 1) - return 'O'; - - return 0; -} - -static int -FRMR_error(struct PStack *st, struct sk_buff *skb) -{ - int headers = l2addrsize(&st->l2) + 1; - u_char *datap = skb->data + headers; - int rsp = *skb->data & 0x2; - - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (!rsp) - return 'L'; - - if (test_bit(FLG_MOD128, &st->l2.flag)) { - if (skb->len < headers + 5) - return 'N'; - else - l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x", - datap[0], datap[1], datap[2], - datap[3], datap[4]); - } else { - if (skb->len < headers + 3) - return 'N'; - else - l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x", - datap[0], datap[1], datap[2]); - } - - return 0; -} - -static unsigned int -legalnr(struct PStack *st, unsigned int nr) -{ - struct Layer2 *l2 = &st->l2; - - if (test_bit(FLG_MOD128, &l2->flag)) - return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); - else - return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); -} - -static void -setva(struct PStack *st, unsigned int nr) -{ - struct Layer2 *l2 = &st->l2; - int len; - u_long flags; - - spin_lock_irqsave(&l2->lock, flags); - while (l2->va != nr) { - (l2->va)++; - if (test_bit(FLG_MOD128, &l2->flag)) - l2->va %= 128; - else - l2->va %= 8; - len = l2->windowar[l2->sow]->len; - if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type) - len = -1; - dev_kfree_skb(l2->windowar[l2->sow]); - l2->windowar[l2->sow] = NULL; - l2->sow = (l2->sow + 1) % l2->window; - spin_unlock_irqrestore(&l2->lock, flags); - if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >= 0)) - lli_writewakeup(st, len); - spin_lock_irqsave(&l2->lock, flags); - } - spin_unlock_irqrestore(&l2->lock, flags); -} - -static void -send_uframe(struct PStack *st, u_char cmd, u_char cr) -{ - struct sk_buff *skb; - u_char tmp[MAX_HEADER_LEN]; - int i; - - i = sethdraddr(&st->l2, tmp, cr); - tmp[i++] = cmd; - if (!(skb = alloc_skb(i, GFP_ATOMIC))) { - printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n"); - return; - } - skb_put_data(skb, tmp, i); - enqueue_super(st, skb); -} - -static inline u_char -get_PollFlag(struct PStack *st, struct sk_buff *skb) -{ - return (skb->data[l2addrsize(&(st->l2))] & 0x10); -} - -static inline u_char -get_PollFlagFree(struct PStack *st, struct sk_buff *skb) -{ - u_char PF; - - PF = get_PollFlag(st, skb); - dev_kfree_skb(skb); - return (PF); -} - -static inline void -start_t200(struct PStack *st, int i) -{ - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); -} - -static inline void -restart_t200(struct PStack *st, int i) -{ - FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); -} - -static inline void -stop_t200(struct PStack *st, int i) -{ - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, i); -} - -static inline void -st5_dl_release_l2l3(struct PStack *st) -{ - int pr; - - if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) - pr = DL_RELEASE | CONFIRM; - else - pr = DL_RELEASE | INDICATION; - - st->l2.l2l3(st, pr, NULL); -} - -static inline void -lapb_dl_release_l2l3(struct PStack *st, int f) -{ - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - st->l2.l2l3(st, DL_RELEASE | f, NULL); -} - -static void -establishlink(struct FsmInst *fi) -{ - struct PStack *st = fi->userdata; - u_char cmd; - - clear_exception(&st->l2); - st->l2.rc = 0; - cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10; - send_uframe(st, cmd, CMD); - FsmDelTimer(&st->l2.t203, 1); - restart_t200(st, 1); - test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); - freewin(st); - FsmChangeState(fi, ST_L2_5); -} - -static void -l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct PStack *st = fi->userdata; - - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C'); - else - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D'); -} - -static void -l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct PStack *st = fi->userdata; - - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); - else { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } -} - -static void -l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct PStack *st = fi->userdata; - - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); - else { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); - } - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -l2_go_st3(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L2_3); -} - -static void -l2_mdl_assign(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L2_3); - st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); -} - -static void -l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l2.ui_queue, skb); - FsmChangeState(fi, ST_L2_2); - st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); -} - -static void -l2_queue_ui(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l2.ui_queue, skb); -} - -static void -tx_ui(struct PStack *st) -{ - struct sk_buff *skb; - u_char header[MAX_HEADER_LEN]; - int i; - - i = sethdraddr(&(st->l2), header, CMD); - header[i++] = UI; - while ((skb = skb_dequeue(&st->l2.ui_queue))) { - memcpy(skb_push(skb, i), header, i); - enqueue_ui(st, skb); - } -} - -static void -l2_send_ui(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l2.ui_queue, skb); - tx_ui(st); -} - -static void -l2_got_ui(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_pull(skb, l2headersize(&st->l2, 1)); - st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb); -/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * in states 1-3 for broadcast - */ - - -} - -static void -l2_establish(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); - test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); -} - -static void -l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -l2_release(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); -} - -static void -l2_pend_rel(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_set_bit(FLG_PEND_REL, &st->l2.flag); -} - -static void -l2_disconnect(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - freewin(st); - FsmChangeState(fi, ST_L2_6); - st->l2.rc = 0; - send_uframe(st, DISC | 0x10, CMD); - FsmDelTimer(&st->l2.t203, 1); - restart_t200(st, 2); -} - -static void -l2_start_multi(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - - clear_exception(&st->l2); - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); - - st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); -} - -static void -l2_send_UA(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); -} - -static void -l2_send_DM(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(st, DM | get_PollFlagFree(st, skb), RSP); -} - -static void -l2_restart_multi(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int est = 0, state; - - state = fi->state; - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F'); - - if (st->l2.vs != st->l2.va) { - skb_queue_purge(&st->l2.i_queue); - est = 1; - } - - clear_exception(&st->l2); - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - stop_t200(st, 3); - FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); - - if (est) - st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); - - if ((ST_L2_7 == state) || (ST_L2_8 == state)) - if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_stop_multi(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - FsmChangeState(fi, ST_L2_4); - FsmDelTimer(&st->l2.t203, 3); - stop_t200(st, 4); - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - - skb_queue_purge(&st->l2.i_queue); - freewin(st); - lapb_dl_release_l2l3(st, INDICATION); -} - -static void -l2_connected(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int pr = -1; - - if (!get_PollFlag(st, skb)) { - l2_mdl_error_ua(fi, event, arg); - return; - } - dev_kfree_skb(skb); - - if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) - l2_disconnect(fi, event, arg); - - if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { - pr = DL_ESTABLISH | CONFIRM; - } else if (st->l2.vs != st->l2.va) { - skb_queue_purge(&st->l2.i_queue); - pr = DL_ESTABLISH | INDICATION; - } - - stop_t200(st, 5); - - st->l2.vr = 0; - st->l2.vs = 0; - st->l2.va = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4); - - if (pr != -1) - st->l2.l2l3(st, pr, NULL); - - if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_released(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (!get_PollFlag(st, skb)) { - l2_mdl_error_ua(fi, event, arg); - return; - } - dev_kfree_skb(skb); - - stop_t200(st, 6); - lapb_dl_release_l2l3(st, CONFIRM); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_reestablish(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (!get_PollFlagFree(st, skb)) { - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); - } -} - -static void -l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (get_PollFlagFree(st, skb)) { - stop_t200(st, 7); - if (!test_bit(FLG_L3_INIT, &st->l2.flag)) - skb_queue_purge(&st->l2.i_queue); - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - st5_dl_release_l2l3(st); - FsmChangeState(fi, ST_L2_4); - } -} - -static void -l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (get_PollFlagFree(st, skb)) { - stop_t200(st, 8); - lapb_dl_release_l2l3(st, CONFIRM); - FsmChangeState(fi, ST_L2_4); - } -} - -static inline void -enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) -{ - struct sk_buff *skb; - struct Layer2 *l2; - u_char tmp[MAX_HEADER_LEN]; - int i; - - l2 = &st->l2; - i = sethdraddr(l2, tmp, cr); - if (test_bit(FLG_MOD128, &l2->flag)) { - tmp[i++] = typ; - tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); - } else - tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); - if (!(skb = alloc_skb(i, GFP_ATOMIC))) { - printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n"); - return; - } - skb_put_data(skb, tmp, i); - enqueue_super(st, skb); -} - -static inline void -enquiry_response(struct PStack *st) -{ - if (test_bit(FLG_OWN_BUSY, &st->l2.flag)) - enquiry_cr(st, RNR, RSP, 1); - else - enquiry_cr(st, RR, RSP, 1); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); -} - -static inline void -transmit_enquiry(struct PStack *st) -{ - if (test_bit(FLG_OWN_BUSY, &st->l2.flag)) - enquiry_cr(st, RNR, CMD, 1); - else - enquiry_cr(st, RR, CMD, 1); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - start_t200(st, 9); -} - - -static void -nrerrorrecovery(struct FsmInst *fi) -{ - struct PStack *st = fi->userdata; - - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -invoke_retransmission(struct PStack *st, unsigned int nr) -{ - struct Layer2 *l2 = &st->l2; - u_int p1; - u_long flags; - - spin_lock_irqsave(&l2->lock, flags); - if (l2->vs != nr) { - while (l2->vs != nr) { - (l2->vs)--; - if (test_bit(FLG_MOD128, &l2->flag)) { - l2->vs %= 128; - p1 = (l2->vs - l2->va) % 128; - } else { - l2->vs %= 8; - p1 = (l2->vs - l2->va) % 8; - } - p1 = (p1 + l2->sow) % l2->window; - if (test_bit(FLG_LAPB, &l2->flag)) - st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0); - skb_queue_head(&l2->i_queue, l2->windowar[p1]); - l2->windowar[p1] = NULL; - } - spin_unlock_irqrestore(&l2->lock, flags); - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - return; - } - spin_unlock_irqrestore(&l2->lock, flags); -} - -static void -l2_st7_got_super(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, rsp, typ = RR; - unsigned int nr; - struct Layer2 *l2 = &st->l2; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - - skb_pull(skb, l2addrsize(l2)); - if (IsRNR(skb->data, st)) { - set_peer_busy(l2); - typ = RNR; - } else - clear_peer_busy(l2); - if (IsREJ(skb->data, st)) - typ = REJ; - - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } - dev_kfree_skb(skb); - - if (PollFlag) { - if (rsp) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A'); - else - enquiry_response(st); - } - if (legalnr(st, nr)) { - if (typ == REJ) { - setva(st, nr); - invoke_retransmission(st, nr); - stop_t200(st, 10); - if (FsmAddTimer(&st->l2.t203, st->l2.T203, - EV_L2_T203, NULL, 6)) - l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ"); - } else if ((nr == l2->vs) && (typ == RR)) { - setva(st, nr); - stop_t200(st, 11); - FsmRestartTimer(&st->l2.t203, st->l2.T203, - EV_L2_T203, NULL, 7); - } else if ((l2->va != nr) || (typ == RNR)) { - setva(st, nr); - if (typ != RR) FsmDelTimer(&st->l2.t203, 9); - restart_t200(st, 12); - } - if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - } else - nrerrorrecovery(fi); -} - -static void -l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - if (!test_bit(FLG_L3_INIT, &st->l2.flag)) - skb_queue_tail(&st->l2.i_queue, skb); - else - dev_kfree_skb(skb); -} - -static void -l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - skb_queue_tail(&st->l2.i_queue, skb); - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - skb_queue_tail(&st->l2.i_queue, skb); -} - -static void -l2_got_iframe(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - struct Layer2 *l2 = &(st->l2); - int PollFlag, ns, i; - unsigned int nr; - - i = l2addrsize(l2); - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); - ns = skb->data[i] >> 1; - nr = (skb->data[i + 1] >> 1) & 0x7f; - } else { - PollFlag = (skb->data[i] & 0x10); - ns = (skb->data[i] >> 1) & 0x7; - nr = (skb->data[i] >> 5) & 0x7; - } - if (test_bit(FLG_OWN_BUSY, &l2->flag)) { - dev_kfree_skb(skb); - if (PollFlag) enquiry_response(st); - } else if (l2->vr == ns) { - (l2->vr)++; - if (test_bit(FLG_MOD128, &l2->flag)) - l2->vr %= 128; - else - l2->vr %= 8; - test_and_clear_bit(FLG_REJEXC, &l2->flag); - - if (PollFlag) - enquiry_response(st); - else - test_and_set_bit(FLG_ACK_PEND, &l2->flag); - skb_pull(skb, l2headersize(l2, 0)); - st->l2.l2l3(st, DL_DATA | INDICATION, skb); - } else { - /* n(s)!=v(r) */ - dev_kfree_skb(skb); - if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { - if (PollFlag) - enquiry_response(st); - } else { - enquiry_cr(st, REJ, RSP, PollFlag); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - } - } - - if (legalnr(st, nr)) { - if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) { - if (nr == st->l2.vs) { - stop_t200(st, 13); - FsmRestartTimer(&st->l2.t203, st->l2.T203, - EV_L2_T203, NULL, 7); - } else if (nr != st->l2.va) - restart_t200(st, 14); - } - setva(st, nr); - } else { - nrerrorrecovery(fi); - return; - } - - if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) - enquiry_cr(st, RR, RSP, 0); -} - -static void -l2_got_tei(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.tei = (long) arg; - - if (fi->state == ST_L2_3) { - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); - } else - FsmChangeState(fi, ST_L2_4); - if (!skb_queue_empty(&st->l2.ui_queue)) - tx_ui(st); -} - -static void -l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - } else if (st->l2.rc == st->l2.N200) { - FsmChangeState(fi, ST_L2_4); - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - skb_queue_purge(&st->l2.i_queue); - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G'); - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - st5_dl_release_l2l3(st); - } else { - st->l2.rc++; - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - send_uframe(st, (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) - | 0x10, CMD); - } -} - -static void -l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - } else if (st->l2.rc == st->l2.N200) { - FsmChangeState(fi, ST_L2_4); - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H'); - lapb_dl_release_l2l3(st, CONFIRM); - } else { - st->l2.rc++; - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, - NULL, 9); - send_uframe(st, DISC | 0x10, CMD); - } -} - -static void -l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - return; - } - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - st->l2.rc = 0; - FsmChangeState(fi, ST_L2_8); - - transmit_enquiry(st); - st->l2.rc++; -} - -static void -l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - return; - } - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - if (st->l2.rc == st->l2.N200) { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'I'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } else { - transmit_enquiry(st); - st->l2.rc++; - } -} - -static void -l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 9); - return; - } - FsmChangeState(fi, ST_L2_8); - transmit_enquiry(st); - st->l2.rc = 0; -} - -static void -l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb, *nskb; - struct Layer2 *l2 = &st->l2; - u_char header[MAX_HEADER_LEN]; - int i, hdr_space_needed; - int unsigned p1; - u_long flags; - - if (!cansend(st)) - return; - - skb = skb_dequeue(&l2->i_queue); - if (!skb) - return; - - hdr_space_needed = l2headersize(l2, 0); - nskb = skb_realloc_headroom(skb, hdr_space_needed); - if (!nskb) { - skb_queue_head(&l2->i_queue, skb); - return; - } - spin_lock_irqsave(&l2->lock, flags); - if (test_bit(FLG_MOD128, &l2->flag)) - p1 = (l2->vs - l2->va) % 128; - else - p1 = (l2->vs - l2->va) % 8; - p1 = (p1 + l2->sow) % l2->window; - if (l2->windowar[p1]) { - printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", - p1); - dev_kfree_skb(l2->windowar[p1]); - } - l2->windowar[p1] = skb; - - i = sethdraddr(&st->l2, header, CMD); - - if (test_bit(FLG_MOD128, &l2->flag)) { - header[i++] = l2->vs << 1; - header[i++] = l2->vr << 1; - l2->vs = (l2->vs + 1) % 128; - } else { - header[i++] = (l2->vr << 5) | (l2->vs << 1); - l2->vs = (l2->vs + 1) % 8; - } - spin_unlock_irqrestore(&l2->lock, flags); - memcpy(skb_push(nskb, i), header, i); - st->l2.l2l1(st, PH_PULL | INDICATION, nskb); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { - FsmDelTimer(&st->l2.t203, 13); - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); - } - if (!skb_queue_empty(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_st8_got_super(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, rsp, rnr = 0; - unsigned int nr; - struct Layer2 *l2 = &st->l2; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - - skb_pull(skb, l2addrsize(l2)); - - if (IsRNR(skb->data, st)) { - set_peer_busy(l2); - rnr = 1; - } else - clear_peer_busy(l2); - - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } - dev_kfree_skb(skb); - - if (rsp && PollFlag) { - if (legalnr(st, nr)) { - if (rnr) { - restart_t200(st, 15); - } else { - stop_t200(st, 16); - FsmAddTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 5); - setva(st, nr); - } - invoke_retransmission(st, nr); - FsmChangeState(fi, ST_L2_7); - if (!skb_queue_empty(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - } else - nrerrorrecovery(fi); - } else { - if (!rsp && PollFlag) - enquiry_response(st); - if (legalnr(st, nr)) { - setva(st, nr); - } else - nrerrorrecovery(fi); - } -} - -static void -l2_got_FRMR(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_pull(skb, l2addrsize(&st->l2) + 1); - - if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ - (IsUA(skb->data) && (fi->state == ST_L2_7))) { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } - dev_kfree_skb(skb); -} - -static void -l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - st->l2.tei = -1; - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - st->l2.tei = -1; - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - st->l2.tei = -1; - stop_t200(st, 17); - st5_dl_release_l2l3(st); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - st->l2.tei = -1; - stop_t200(st, 18); - st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - st->l2.tei = -1; - stop_t200(st, 17); - FsmDelTimer(&st->l2.t203, 19); - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); -} - -static void -l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - stop_t200(st, 19); - st5_dl_release_l2l3(st); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - stop_t200(st, 20); - st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - stop_t200(st, 19); - FsmDelTimer(&st->l2.t203, 19); - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_set_own_busy(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (!test_and_set_bit(FLG_OWN_BUSY, &st->l2.flag)) { - enquiry_cr(st, RNR, RSP, 0); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - } -} - -static void -l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (!test_and_clear_bit(FLG_OWN_BUSY, &st->l2.flag)) { - enquiry_cr(st, RR, RSP, 0); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - } -} - -static void -l2_frame_error(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->ma.layer(st, MDL_ERROR | INDICATION, arg); -} - -static void -l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->ma.layer(st, MDL_ERROR | INDICATION, arg); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); -} - -static struct FsmNode L2FnList[] __initdata = -{ - {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, - {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, - {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, - {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, - {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, - {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, - {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, - {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, - {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, - {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, - {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, - {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, - {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, - {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_queue_ui_assign}, - {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_queue_ui}, - {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_queue_ui}, - {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, - {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, - {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, - {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, - {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, - {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_4, EV_L2_SABME, l2_start_multi}, - {ST_L2_5, EV_L2_SABME, l2_send_UA}, - {ST_L2_6, EV_L2_SABME, l2_send_DM}, - {ST_L2_7, EV_L2_SABME, l2_restart_multi}, - {ST_L2_8, EV_L2_SABME, l2_restart_multi}, - {ST_L2_4, EV_L2_DISC, l2_send_DM}, - {ST_L2_5, EV_L2_DISC, l2_send_DM}, - {ST_L2_6, EV_L2_DISC, l2_send_UA}, - {ST_L2_7, EV_L2_DISC, l2_stop_multi}, - {ST_L2_8, EV_L2_DISC, l2_stop_multi}, - {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_5, EV_L2_UA, l2_connected}, - {ST_L2_6, EV_L2_UA, l2_released}, - {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_4, EV_L2_DM, l2_reestablish}, - {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, - {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, - {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, - {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, - {ST_L2_1, EV_L2_UI, l2_got_ui}, - {ST_L2_2, EV_L2_UI, l2_got_ui}, - {ST_L2_3, EV_L2_UI, l2_got_ui}, - {ST_L2_4, EV_L2_UI, l2_got_ui}, - {ST_L2_5, EV_L2_UI, l2_got_ui}, - {ST_L2_6, EV_L2_UI, l2_got_ui}, - {ST_L2_7, EV_L2_UI, l2_got_ui}, - {ST_L2_8, EV_L2_UI, l2_got_ui}, - {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, - {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, - {ST_L2_7, EV_L2_I, l2_got_iframe}, - {ST_L2_8, EV_L2_I, l2_got_iframe}, - {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, - {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, - {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, - {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, - {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, - {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, - {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, - {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, - {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, - {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, - {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, -}; - -static void -isdnl2_l1l2(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *datap; - int ret = 1, len; - int c = 0; - - switch (pr) { - case (PH_DATA | INDICATION): - datap = skb->data; - len = l2addrsize(&st->l2); - if (skb->len > len) - datap += len; - else { - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N'); - dev_kfree_skb(skb); - return; - } - if (!(*datap & 1)) { /* I-Frame */ - if (!(c = iframe_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb); - } else if (IsSFrame(datap, st)) { /* S-Frame */ - if (!(c = super_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb); - } else if (IsUI(datap)) { - if (!(c = UI_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb); - } else if (IsSABME(datap, st)) { - if (!(c = unnum_error(st, skb, CMD))) - ret = FsmEvent(&st->l2.l2m, EV_L2_SABME, skb); - } else if (IsUA(datap)) { - if (!(c = unnum_error(st, skb, RSP))) - ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb); - } else if (IsDISC(datap)) { - if (!(c = unnum_error(st, skb, CMD))) - ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb); - } else if (IsDM(datap)) { - if (!(c = unnum_error(st, skb, RSP))) - ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb); - } else if (IsFRMR(datap)) { - if (!(c = FRMR_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); - } else { - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L'); - dev_kfree_skb(skb); - ret = 0; - } - if (c) { - dev_kfree_skb(skb); - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c); - ret = 0; - } - if (ret) - dev_kfree_skb(skb); - break; - case (PH_PULL | CONFIRM): - FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); - break; - case (PH_PAUSE | INDICATION): - test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag); - break; - case (PH_PAUSE | CONFIRM): - test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag); - break; - case (PH_ACTIVATE | CONFIRM): - case (PH_ACTIVATE | INDICATION): - test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag); - if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg); - break; - case (PH_DEACTIVATE | INDICATION): - case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag); - FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg); - break; - default: - l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr); - break; - } -} - -static void -isdnl2_l3l2(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_DATA | REQUEST): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) { - dev_kfree_skb((struct sk_buff *) arg); - } - break; - case (DL_UNIT_DATA | REQUEST): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) { - dev_kfree_skb((struct sk_buff *) arg); - } - break; - case (DL_ESTABLISH | REQUEST): - if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) { - if (test_bit(FLG_LAPD, &st->l2.flag) || - test_bit(FLG_ORIG, &st->l2.flag)) { - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg); - } - } else { - if (test_bit(FLG_LAPD, &st->l2.flag) || - test_bit(FLG_ORIG, &st->l2.flag)) { - test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag); - } - st->l2.l2l1(st, PH_ACTIVATE, NULL); - } - break; - case (DL_RELEASE | REQUEST): - if (test_bit(FLG_LAPB, &st->l2.flag)) { - st->l2.l2l1(st, PH_DEACTIVATE, NULL); - } - FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg); - break; - case (MDL_ASSIGN | REQUEST): - FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg); - break; - case (MDL_REMOVE | REQUEST): - FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg); - break; - case (MDL_ERROR | RESPONSE): - FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg); - break; - } -} - -void -releasestack_isdnl2(struct PStack *st) -{ - FsmDelTimer(&st->l2.t200, 21); - FsmDelTimer(&st->l2.t203, 16); - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - ReleaseWin(&st->l2); -} - -static void -l2m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - - va_start(args, fmt); - VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args); - va_end(args); -} - -void -setstack_isdnl2(struct PStack *st, char *debug_id) -{ - spin_lock_init(&st->l2.lock); - st->l1.l1l2 = isdnl2_l1l2; - st->l3.l3l2 = isdnl2_l3l2; - - skb_queue_head_init(&st->l2.i_queue); - skb_queue_head_init(&st->l2.ui_queue); - InitWin(&st->l2); - st->l2.debug = 0; - - st->l2.l2m.fsm = &l2fsm; - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2m.state = ST_L2_4; - else - st->l2.l2m.state = ST_L2_1; - st->l2.l2m.debug = 0; - st->l2.l2m.userdata = st; - st->l2.l2m.userint = 0; - st->l2.l2m.printdebug = l2m_debug; - strcpy(st->l2.debug_id, debug_id); - - FsmInitTimer(&st->l2.l2m, &st->l2.t200); - FsmInitTimer(&st->l2.l2m, &st->l2.t203); -} - -static void -transl2_l3l2(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_DATA | REQUEST): - case (DL_UNIT_DATA | REQUEST): - st->l2.l2l1(st, PH_DATA | REQUEST, arg); - break; - case (DL_ESTABLISH | REQUEST): - st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); - break; - case (DL_RELEASE | REQUEST): - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - break; - } -} - -void -setstack_transl2(struct PStack *st) -{ - st->l3.l3l2 = transl2_l3l2; -} - -void -releasestack_transl2(struct PStack *st) -{ -} - -int __init -Isdnl2New(void) -{ - l2fsm.state_count = L2_STATE_COUNT; - l2fsm.event_count = L2_EVENT_COUNT; - l2fsm.strEvent = strL2Event; - l2fsm.strState = strL2State; - return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); -} - -void -Isdnl2Free(void) -{ - FsmFree(&l2fsm); -} diff --git a/drivers/isdn/hisax/isdnl2.h b/drivers/isdn/hisax/isdnl2.h deleted file mode 100644 index 7e447fb8ed1d..000000000000 --- a/drivers/isdn/hisax/isdnl2.h +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: isdnl2.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $ - * - * Layer 2 defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define RR 0x01 -#define RNR 0x05 -#define REJ 0x09 -#define SABME 0x6f -#define SABM 0x2f -#define DM 0x0f -#define UI 0x03 -#define DISC 0x43 -#define UA 0x63 -#define FRMR 0x87 -#define XID 0xaf - -#define CMD 0 -#define RSP 1 - -#define LC_FLUSH_WAIT 1 diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c deleted file mode 100644 index bb3f9ec62749..000000000000 --- a/drivers/isdn/hisax/isdnl3.c +++ /dev/null @@ -1,594 +0,0 @@ -/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $ - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include -#include -#include "hisax.h" -#include "isdnl3.h" - -const char *l3_revision = "$Revision: 2.22.2.3 $"; - -static struct Fsm l3fsm; - -enum { - ST_L3_LC_REL, - ST_L3_LC_ESTAB_WAIT, - ST_L3_LC_REL_DELAY, - ST_L3_LC_REL_WAIT, - ST_L3_LC_ESTAB, -}; - -#define L3_STATE_COUNT (ST_L3_LC_ESTAB + 1) - -static char *strL3State[] = -{ - "ST_L3_LC_REL", - "ST_L3_LC_ESTAB_WAIT", - "ST_L3_LC_REL_DELAY", - "ST_L3_LC_REL_WAIT", - "ST_L3_LC_ESTAB", -}; - -enum { - EV_ESTABLISH_REQ, - EV_ESTABLISH_IND, - EV_ESTABLISH_CNF, - EV_RELEASE_REQ, - EV_RELEASE_CNF, - EV_RELEASE_IND, - EV_TIMEOUT, -}; - -#define L3_EVENT_COUNT (EV_TIMEOUT + 1) - -static char *strL3Event[] = -{ - "EV_ESTABLISH_REQ", - "EV_ESTABLISH_IND", - "EV_ESTABLISH_CNF", - "EV_RELEASE_REQ", - "EV_RELEASE_CNF", - "EV_RELEASE_IND", - "EV_TIMEOUT", -}; - -static __printf(2, 3) void - l3m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - - va_start(args, fmt); - VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args); - va_end(args); -} - -u_char * -findie(u_char *p, int size, u_char ie, int wanted_set) -{ - int l, codeset, maincodeset; - u_char *pend = p + size; - - /* skip protocol discriminator, callref and message type */ - p++; - l = (*p++) & 0xf; - p += l; - p++; - codeset = 0; - maincodeset = 0; - /* while there are bytes left... */ - while (p < pend) { - if ((*p & 0xf0) == 0x90) { - codeset = *p & 0x07; - if (!(*p & 0x08)) - maincodeset = codeset; - } - if (*p & 0x80) - p++; - else { - if (codeset == wanted_set) { - if (*p == ie) - { /* improved length check (Werner Cornelius) */ - if ((pend - p) < 2) - return (NULL); - if (*(p + 1) > (pend - (p + 2))) - return (NULL); - return (p); - } - - if (*p > ie) - return (NULL); - } - p++; - l = *p++; - p += l; - codeset = maincodeset; - } - } - return (NULL); -} - -int -getcallref(u_char *p) -{ - int l, cr = 0; - - p++; /* prot discr */ - if (*p & 0xfe) /* wrong callref BRI only 1 octet*/ - return (-2); - l = 0xf & *p++; /* callref length */ - if (!l) /* dummy CallRef */ - return (-1); - cr = *p++; - return (cr); -} - -static int OrigCallRef = 0; - -int -newcallref(void) -{ - if (OrigCallRef == 127) - OrigCallRef = 1; - else - OrigCallRef++; - return (OrigCallRef); -} - -void -newl3state(struct l3_process *pc, int state) -{ - if (pc->debug & L3_DEB_STATE) - l3_debug(pc->st, "%s cr %d %d --> %d", __func__, - pc->callref & 0x7F, - pc->state, state); - pc->state = state; -} - -static void -L3ExpireTimer(struct timer_list *timer) -{ - struct L3Timer *t = from_timer(t, timer, tl); - t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc); -} - -void -L3InitTimer(struct l3_process *pc, struct L3Timer *t) -{ - t->pc = pc; - timer_setup(&t->tl, L3ExpireTimer, 0); -} - -void -L3DelTimer(struct L3Timer *t) -{ - del_timer(&t->tl); -} - -int -L3AddTimer(struct L3Timer *t, - int millisec, int event) -{ - if (timer_pending(&t->tl)) { - printk(KERN_WARNING "L3AddTimer: timer already active!\n"); - return -1; - } - t->event = event; - t->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&t->tl); - return 0; -} - -void -StopAllL3Timer(struct l3_process *pc) -{ - L3DelTimer(&pc->timer); -} - -struct sk_buff * -l3_alloc_skb(int len) -{ - struct sk_buff *skb; - - if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) { - printk(KERN_WARNING "HiSax: No skb for D-channel\n"); - return (NULL); - } - skb_reserve(skb, MAX_HEADER_LEN); - return (skb); -} - -static void -no_l3_proto(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - - HiSax_putstatus(st->l1.hardware, "L3", "no D protocol"); - if (skb) { - dev_kfree_skb(skb); - } -} - -static int -no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic) -{ - printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n", ic->arg & 0xFF); - return (-1); -} - -struct l3_process -*getl3proc(struct PStack *st, int cr) -{ - struct l3_process *p = st->l3.proc; - - while (p) - if (p->callref == cr) - return (p); - else - p = p->next; - return (NULL); -} - -struct l3_process -*new_l3_process(struct PStack *st, int cr) -{ - struct l3_process *p, *np; - - if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { - printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr); - return (NULL); - } - if (!st->l3.proc) - st->l3.proc = p; - else { - np = st->l3.proc; - while (np->next) - np = np->next; - np->next = p; - } - p->next = NULL; - p->debug = st->l3.debug; - p->callref = cr; - p->state = 0; - p->chan = NULL; - p->st = st; - p->N303 = st->l3.N303; - L3InitTimer(p, &p->timer); - return (p); -}; - -void -release_l3_process(struct l3_process *p) -{ - struct l3_process *np, *pp = NULL; - - if (!p) - return; - np = p->st->l3.proc; - while (np) { - if (np == p) { - StopAllL3Timer(p); - if (pp) - pp->next = np->next; - else if (!(p->st->l3.proc = np->next) && - !test_bit(FLG_PTP, &p->st->l2.flag)) { - if (p->debug) - l3_debug(p->st, "release_l3_process: last process"); - if (skb_queue_empty(&p->st->l3.squeue)) { - if (p->debug) - l3_debug(p->st, "release_l3_process: release link"); - if (p->st->protocol != ISDN_PTYPE_NI1) - FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL); - else - FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL); - } else { - if (p->debug) - l3_debug(p->st, "release_l3_process: not release link"); - } - } - kfree(p); - return; - } - pp = np; - np = np->next; - } - printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref); - l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref); -}; - -static void -l3ml3p(struct PStack *st, int pr) -{ - struct l3_process *p = st->l3.proc; - struct l3_process *np; - - while (p) { - /* p might be kfreed under us, so we need to save where we want to go on */ - np = p->next; - st->l3.l3ml3(st, pr, p); - p = np; - } -} - -void -setstack_l3dc(struct PStack *st, struct Channel *chanp) -{ - char tmp[64]; - - st->l3.proc = NULL; - st->l3.global = NULL; - skb_queue_head_init(&st->l3.squeue); - st->l3.l3m.fsm = &l3fsm; - st->l3.l3m.state = ST_L3_LC_REL; - st->l3.l3m.debug = 1; - st->l3.l3m.userdata = st; - st->l3.l3m.userint = 0; - st->l3.l3m.printdebug = l3m_debug; - FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer); - strcpy(st->l3.debug_id, "L3DC "); - st->lli.l4l3_proto = no_l3_proto_spec; - -#ifdef CONFIG_HISAX_EURO - if (st->protocol == ISDN_PTYPE_EURO) { - setstack_dss1(st); - } else -#endif -#ifdef CONFIG_HISAX_NI1 - if (st->protocol == ISDN_PTYPE_NI1) { - setstack_ni1(st); - } else -#endif -#ifdef CONFIG_HISAX_1TR6 - if (st->protocol == ISDN_PTYPE_1TR6) { - setstack_1tr6(st); - } else -#endif - if (st->protocol == ISDN_PTYPE_LEASED) { - st->lli.l4l3 = no_l3_proto; - st->l2.l2l3 = no_l3_proto; - st->l3.l3ml3 = no_l3_proto; - printk(KERN_INFO "HiSax: Leased line mode\n"); - } else { - st->lli.l4l3 = no_l3_proto; - st->l2.l2l3 = no_l3_proto; - st->l3.l3ml3 = no_l3_proto; - sprintf(tmp, "protocol %s not supported", - (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : - (st->protocol == ISDN_PTYPE_EURO) ? "euro" : - (st->protocol == ISDN_PTYPE_NI1) ? "ni1" : - "unknown"); - printk(KERN_WARNING "HiSax: %s\n", tmp); - st->protocol = -1; - } -} - -static void -isdnl3_trans(struct PStack *st, int pr, void *arg) { - st->l3.l3l2(st, pr, arg); -} - -void -releasestack_isdnl3(struct PStack *st) -{ - while (st->l3.proc) - release_l3_process(st->l3.proc); - if (st->l3.global) { - StopAllL3Timer(st->l3.global); - kfree(st->l3.global); - st->l3.global = NULL; - } - FsmDelTimer(&st->l3.l3m_timer, 54); - skb_queue_purge(&st->l3.squeue); -} - -void -setstack_l3bc(struct PStack *st, struct Channel *chanp) -{ - - st->l3.proc = NULL; - st->l3.global = NULL; - skb_queue_head_init(&st->l3.squeue); - st->l3.l3m.fsm = &l3fsm; - st->l3.l3m.state = ST_L3_LC_REL; - st->l3.l3m.debug = 1; - st->l3.l3m.userdata = st; - st->l3.l3m.userint = 0; - st->l3.l3m.printdebug = l3m_debug; - strcpy(st->l3.debug_id, "L3BC "); - st->lli.l4l3 = isdnl3_trans; -} - -#define DREL_TIMER_VALUE 40000 - -static void -lc_activate(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT); - st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -lc_connect(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int dequeued = 0; - - FsmChangeState(fi, ST_L3_LC_ESTAB); - while ((skb = skb_dequeue(&st->l3.squeue))) { - st->l3.l3l2(st, DL_DATA | REQUEST, skb); - dequeued++; - } - if ((!st->l3.proc) && dequeued) { - if (st->l3.debug) - l3_debug(st, "lc_connect: release link"); - FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); - } else - l3ml3p(st, DL_ESTABLISH | INDICATION); -} - -static void -lc_connected(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int dequeued = 0; - - FsmDelTimer(&st->l3.l3m_timer, 51); - FsmChangeState(fi, ST_L3_LC_ESTAB); - while ((skb = skb_dequeue(&st->l3.squeue))) { - st->l3.l3l2(st, DL_DATA | REQUEST, skb); - dequeued++; - } - if ((!st->l3.proc) && dequeued) { - if (st->l3.debug) - l3_debug(st, "lc_connected: release link"); - FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); - } else - l3ml3p(st, DL_ESTABLISH | CONFIRM); -} - -static void -lc_start_delay(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_REL_DELAY); - FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); -} - -static void -lc_start_delay_check(struct FsmInst *fi, int event, void *arg) -/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */ -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_REL_DELAY); - /* 19/09/00 - GE timer not user for NI-1 */ - if (st->protocol != ISDN_PTYPE_NI1) - FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); -} - -static void -lc_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_L2BLOCK, &st->l2.flag)) { - if (st->l3.debug) - l3_debug(st, "lc_release_req: l2 blocked"); - /* restart release timer */ - FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51); - } else { - FsmChangeState(fi, ST_L3_LC_REL_WAIT); - st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL); - } -} - -static void -lc_release_ind(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmDelTimer(&st->l3.l3m_timer, 52); - FsmChangeState(fi, ST_L3_LC_REL); - skb_queue_purge(&st->l3.squeue); - l3ml3p(st, DL_RELEASE | INDICATION); -} - -static void -lc_release_cnf(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_REL); - skb_queue_purge(&st->l3.squeue); - l3ml3p(st, DL_RELEASE | CONFIRM); -} - - -/* *INDENT-OFF* */ -static struct FsmNode L3FnList[] __initdata = -{ - {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate}, - {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect}, - {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect}, - {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected}, - {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay}, - {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check}, - {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected}, - {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req}, - {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf}, - {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate}, -}; -/* *INDENT-ON* */ - -void -l3_msg(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_DATA | REQUEST): - if (st->l3.l3m.state == ST_L3_LC_ESTAB) { - st->l3.l3l2(st, pr, arg); - } else { - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l3.squeue, skb); - FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); - } - break; - case (DL_ESTABLISH | REQUEST): - FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); - break; - case (DL_ESTABLISH | CONFIRM): - FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL); - break; - case (DL_ESTABLISH | INDICATION): - FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL); - break; - case (DL_RELEASE | INDICATION): - FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL); - break; - case (DL_RELEASE | CONFIRM): - FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL); - break; - case (DL_RELEASE | REQUEST): - FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); - break; - } -} - -int __init -Isdnl3New(void) -{ - l3fsm.state_count = L3_STATE_COUNT; - l3fsm.event_count = L3_EVENT_COUNT; - l3fsm.strEvent = strL3Event; - l3fsm.strState = strL3State; - return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList)); -} - -void -Isdnl3Free(void) -{ - FsmFree(&l3fsm); -} diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h deleted file mode 100644 index 0edc99d40dc2..000000000000 --- a/drivers/isdn/hisax/isdnl3.h +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id: isdnl3.h,v 2.6.6.2 2001/09/23 22:24:49 kai Exp $ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define SBIT(state) (1 << state) -#define ALL_STATES 0x03ffffff - -#define PROTO_DIS_EURO 0x08 - -#define L3_DEB_WARN 0x01 -#define L3_DEB_PROTERR 0x02 -#define L3_DEB_STATE 0x04 -#define L3_DEB_CHARGE 0x08 -#define L3_DEB_CHECK 0x10 -#define L3_DEB_SI 0x20 - -struct stateentry { - int state; - int primitive; - void (*rout) (struct l3_process *, u8, void *); -}; - -#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args) - -struct PStack; - -void newl3state(struct l3_process *pc, int state); -void L3InitTimer(struct l3_process *pc, struct L3Timer *t); -void L3DelTimer(struct L3Timer *t); -int L3AddTimer(struct L3Timer *t, int millisec, int event); -void StopAllL3Timer(struct l3_process *pc); -struct sk_buff *l3_alloc_skb(int len); -struct l3_process *new_l3_process(struct PStack *st, int cr); -void release_l3_process(struct l3_process *p); -struct l3_process *getl3proc(struct PStack *st, int cr); -void l3_msg(struct PStack *st, int pr, void *arg); -void setstack_dss1(struct PStack *st); -void setstack_ni1(struct PStack *st); -void setstack_1tr6(struct PStack *st); diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c deleted file mode 100644 index 53e299be4304..000000000000 --- a/drivers/isdn/hisax/isurf.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $ - * - * low level stuff for Siemens I-Surf/I-Talk cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "isar.h" -#include "isdnl1.h" -#include - -static const char *ISurf_revision = "$Revision: 1.12.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ISURF_ISAR_RESET 1 -#define ISURF_ISAC_RESET 2 -#define ISURF_ISAR_EA 4 -#define ISURF_ARCOFI_RESET 8 -#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET) - -#define ISURF_ISAR_OFFSET 0 -#define ISURF_ISAC_OFFSET 0x100 -#define ISURF_IOMEM_SIZE 0x400 -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readb(cs->hw.isurf.isac + offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writeb(value, cs->hw.isurf.isac + offset); mb(); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - register int i; - for (i = 0; i < size; i++) - data[i] = readb(cs->hw.isurf.isac); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - register int i; - for (i = 0; i < size; i++) { - writeb(data[i], cs->hw.isurf.isac); mb(); - } -} - -/* ISAR access routines - * mode = 0 access with IRQ on - * mode = 1 access with IRQ off - * mode = 2 access with IRQ off and using last offset - */ - -static u_char -ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) -{ - return (readb(cs->hw.isurf.isar + offset)); -} - -static void -WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) -{ - writeb(value, cs->hw.isurf.isar + offset); mb(); -} - -static irqreturn_t -isurf_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - int cnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); -Start_ISAR: - if (val & ISAR_IRQSTA) - isar_int_main(cs); - val = readb(cs->hw.isurf.isac + ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); - if ((val & ISAR_IRQSTA) && --cnt) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "ISAR IntStat after IntRoutine"); - goto Start_ISAR; - } - val = readb(cs->hw.isurf.isac + ISAC_ISTA); - if (val && --cnt) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (!cnt) - printk(KERN_WARNING "ISurf IRQ LOOP\n"); - - writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK); mb(); - writeb(0, cs->hw.isurf.isac + ISAC_MASK); mb(); - writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_isurf(struct IsdnCardState *cs) -{ - release_region(cs->hw.isurf.reset, 1); - iounmap(cs->hw.isurf.isar); - release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); -} - -static void -reset_isurf(struct IsdnCardState *cs, u_char chips) -{ - printk(KERN_INFO "ISurf: resetting card\n"); - - byteout(cs->hw.isurf.reset, chips); /* Reset On */ - mdelay(10); - byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ - mdelay(10); -} - -static int -ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_isurf(cs, ISURF_RESET); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_isurf(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_isurf(cs, ISURF_RESET); - clear_pending_isac_ints(cs); - writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - initisac(cs); - initisar(cs); - /* Reenable ISAC IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - /* RESET Receiver and Transmitter */ - cs->writeisac(cs, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int -isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { - int ret; - u_long flags; - - if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) { - ret = isar_auxcmd(cs, ic); - spin_lock_irqsave(&cs->lock, flags); - if (!ret) { - reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | - ISURF_ARCOFI_RESET); - initisac(cs); - cs->writeisac(cs, ISAC_MASK, 0); - cs->writeisac(cs, ISAC_CMDR, 0x41); - } - spin_unlock_irqrestore(&cs->lock, flags); - return (ret); - } - return (isar_auxcmd(cs, ic)); -} - -#ifdef __ISAPNP__ -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_isurf(struct IsdnCard *card) -{ - int ver; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, ISurf_revision); - printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp)); - - if (cs->typ != ISDN_CTYPE_ISURF) - return (0); - if (card->para[1] && card->para[2]) { - cs->hw.isurf.reset = card->para[1]; - cs->hw.isurf.phymem = card->para[2]; - cs->irq = card->para[0]; - } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d = NULL; - int err; - - cs->subtyp = 0; - if ((pnp_c = pnp_find_card( - ISAPNP_VENDOR('S', 'I', 'E'), - ISAPNP_FUNCTION(0x0010), pnp_c))) { - if (!(pnp_d = pnp_find_dev(pnp_c, - ISAPNP_VENDOR('S', 'I', 'E'), - ISAPNP_FUNCTION(0x0010), pnp_d))) { - printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n"); - return (0); - } - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - pr_warn("%s: pnp_activate_dev ret=%d\n", - __func__, err); - return 0; - } - cs->hw.isurf.reset = pnp_port_start(pnp_d, 0); - cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1); - cs->irq = pnp_irq(pnp_d, 0); - if (cs->irq == -1 || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) { - printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n", - cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem); - pnp_disable_dev(pnp_d); - return (0); - } - } else { - printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n"); - return (0); - } - } else { - printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n"); - return (0); - } -#else - printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n"); - return (0); -#endif - } - if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) { - printk(KERN_WARNING - "HiSax: Siemens I-Surf config port %x already in use\n", - cs->hw.isurf.reset); - return (0); - } - if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) { - printk(KERN_WARNING "HiSax: Siemens I-Surf memory region " - "%lx-%lx already in use\n", - cs->hw.isurf.phymem, - cs->hw.isurf.phymem + ISURF_IOMEM_SIZE); - release_region(cs->hw.isurf.reset, 1); - return (0); - } - cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); - cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; - printk(KERN_INFO - "ISurf: defined at 0x%x 0x%lx IRQ %d\n", - cs->hw.isurf.reset, - cs->hw.isurf.phymem, - cs->irq); - - setup_isac(cs); - cs->cardmsg = &ISurf_card_msg; - cs->irq_func = &isurf_interrupt; - cs->auxcmd = &isurf_auxcmd; - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; - cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; - test_and_set_bit(HW_ISAR, &cs->HW_Flags); - ISACVersion(cs, "ISurf:"); - cs->BC_Read_Reg = &ReadISAR; - cs->BC_Write_Reg = &WriteISAR; - cs->BC_Send_Data = &isar_fill_fifo; - ver = ISARVersion(cs, "ISurf:"); - if (ver < 0) { - printk(KERN_WARNING - "ISurf: wrong ISAR version (ret = %d)\n", ver); - release_io_isurf(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c deleted file mode 100644 index bfb79f3f0a49..000000000000 --- a/drivers/isdn/hisax/ix1_micro.c +++ /dev/null @@ -1,316 +0,0 @@ -/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for ITK ix1-micro Rev.2 isdn cards - * derived from the original file teles3.c from Karsten Keil - * - * Author Klaus-Peter Nischke - * Copyright by Klaus-Peter Nischke, ITK AG - * - * by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Klaus-Peter Nischke - * Deusener Str. 287 - * 44369 Dortmund - * Germany - */ - -#include -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *ix1_revision = "$Revision: 2.12.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define SPECIAL_PORT_OFFSET 3 - -#define ISAC_COMMAND_OFFSET 2 -#define ISAC_DATA_OFFSET 0 -#define HSCX_COMMAND_OFFSET 2 -#define HSCX_DATA_OFFSET 1 - -#define TIMEOUT 50 - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.ix1.hscx_ale, - cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.ix1.hscx_ale, - cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); -} - -#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -ix1micro_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_ix1micro(struct IsdnCardState *cs) -{ - if (cs->hw.ix1.cfg_reg) - release_region(cs->hw.ix1.cfg_reg, 4); -} - -static void -ix1_reset(struct IsdnCardState *cs) -{ - int cnt; - - /* reset isac */ - cnt = 3 * (HZ / 10) + 1; - while (cnt--) { - byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1); - HZDELAY(1); /* wait >=10 ms */ - } - byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0); -} - -static int -ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - ix1_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_ix1micro(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - ix1_reset(cs); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id itk_ids[] = { - { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), - ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), - (unsigned long) "ITK micro 2" }, - { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), - ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), - (unsigned long) "ITK micro 2." }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &itk_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - - -int setup_ix1micro(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, ix1_revision); - printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_IX1MICROR2) - return (0); - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - /* IO-Ports */ - cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; - cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; - cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; - cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; - cs->hw.ix1.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (cs->hw.ix1.cfg_reg) { - if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) { - printk(KERN_WARNING - "HiSax: ITK ix1-micro Rev.2 config port " - "%x-%x already in use\n", - cs->hw.ix1.cfg_reg, - cs->hw.ix1.cfg_reg + 4); - return (0); - } - } - printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n", - cs->irq, cs->hw.ix1.cfg_reg); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &ix1_card_msg; - cs->irq_func = &ix1micro_interrupt; - ISACVersion(cs, "ix1-Micro:"); - if (HscxVersion(cs, "ix1-Micro:")) { - printk(KERN_WARNING - "ix1-Micro: wrong HSCX versions check IO address\n"); - release_io_ix1micro(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c deleted file mode 100644 index e2ae7871a209..000000000000 --- a/drivers/isdn/hisax/jade.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $ - * - * JADE stuff (derived from original hscx.c) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include -#include "hisax.h" -#include "hscx.h" -#include "jade.h" -#include "isdnl1.h" -#include -#include - - -int -JadeVersion(struct IsdnCardState *cs, char *s) -{ - int ver; - int to = 50; - cs->BC_Write_Reg(cs, -1, 0x50, 0x19); - while (to) { - udelay(1); - ver = cs->BC_Read_Reg(cs, -1, 0x60); - to--; - if (ver) - break; - if (!to) { - printk(KERN_INFO "%s JADE version not obtainable\n", s); - return (0); - } - } - /* Wait for the JADE */ - udelay(10); - /* Read version */ - ver = cs->BC_Read_Reg(cs, -1, 0x60); - printk(KERN_INFO "%s JADE version: %d\n", s, ver); - return (1); -} - -/* Write to indirect accessible jade register set */ -static void -jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value) -{ - int to = 50; - u_char ret; - - /* Write the data */ - cs->BC_Write_Reg(cs, -1, COMM_JADE + 1, value); - /* Say JADE we wanna write indirect reg 'reg' */ - cs->BC_Write_Reg(cs, -1, COMM_JADE, reg); - to = 50; - /* Wait for RDY goes high */ - while (to) { - udelay(1); - ret = cs->BC_Read_Reg(cs, -1, COMM_JADE); - to--; - if (ret & 1) - /* Got acknowledge */ - break; - if (!to) { - printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value); - return; - } - } -} - - - -static void -modejade(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int jade = bcs->hw.hscx.hscx; - - if (cs->debug & L1_DEB_HSCX) { - debugl1(cs, "jade %c mode %d ichan %d", 'A' + jade, mode, bc); - } - bcs->mode = mode; - bcs->channel = bc; - - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO : 0x00)); - cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU | jadeCCR0_ITF)); - cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00); - - jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08); - jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08); - jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00); - jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00); - - cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07); - cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07); - - if (bc == 0) { - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00); - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00); - } else { - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04); - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04); - } - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO); - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO | jadeMODE_RAC | jadeMODE_XAC)); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC | jadeMODE_XAC)); - break; - } - if (mode) { - cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES | jadeRCMD_RMC)); - cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES); - /* Unmask ints */ - cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8); - } - else - /* Mask ints */ - cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00); -} - -static void -jade_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - modejade(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - modejade(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_jadestate(struct BCState *bcs) -{ - modejade(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_jadestate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hscx.rcvbuf\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - - -static int -setstack_jade(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_jadestate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = jade_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -void -clear_pending_jade_ints(struct IsdnCardState *cs) -{ - int val; - - cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); - cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); - - val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR); - debugl1(cs, "jade B ISTA %x", val); - val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR); - debugl1(cs, "jade A ISTA %x", val); - val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR); - debugl1(cs, "jade B STAR %x", val); - val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR); - debugl1(cs, "jade A STAR %x", val); - /* Unmask ints */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8); - cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8); -} - -void -initjade(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_jade; - cs->bcs[1].BC_SetStack = setstack_jade; - cs->bcs[0].BC_Close = close_jadestate; - cs->bcs[1].BC_Close = close_jadestate; - cs->bcs[0].hw.hscx.hscx = 0; - cs->bcs[1].hw.hscx.hscx = 1; - - /* Stop DSP audio tx/rx */ - jade_write_indirect(cs, 0x11, 0x0f); - jade_write_indirect(cs, 0x17, 0x2f); - - /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO); - cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO); - /* Power down, 1-Idle, RxTx least significant bit first */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00); - cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00); - /* Mask all interrupts */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); - cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); - /* Setup host access to hdlc controller */ - jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1 | jadeINDIRECT_HAH2)); - /* Unmask HDLC int (don't forget DSP int later on)*/ - cs->BC_Write_Reg(cs, -1, jade_INT, (jadeINT_HDLC1 | jadeINT_HDLC2)); - - /* once again TRANSPARENT */ - modejade(cs->bcs, 0, 0); - modejade(cs->bcs + 1, 0, 0); -} diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h deleted file mode 100644 index 4b98096a5858..000000000000 --- a/drivers/isdn/hisax/jade.h +++ /dev/null @@ -1,134 +0,0 @@ -/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $ - * - * JADE specific defines - * - * Author Roland Klabunde - * Copyright by Roland Klabunde - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ -#ifndef __JADE_H__ -#define __JADE_H__ - -/* Special registers for access to indirect accessible JADE regs */ -#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */ -#define COMM_JADE 0x0040 /* Jade communication area */ - -/********************************************************************/ -/* JADE-HDLC registers */ -/********************************************************************/ -#define jade_HDLC_RFIFO 0x00 /* R */ -#define jade_HDLC_XFIFO 0x00 /* W */ - -#define jade_HDLC_STAR 0x20 /* R */ -#define jadeSTAR_XDOV 0x80 -#define jadeSTAR_XFW 0x40 /* Does not work*/ -#define jadeSTAR_XCEC 0x20 -#define jadeSTAR_RCEC 0x10 -#define jadeSTAR_BSY 0x08 -#define jadeSTAR_RNA 0x04 -#define jadeSTAR_STR 0x02 -#define jadeSTAR_STX 0x01 - -#define jade_HDLC_XCMD 0x20 /* W */ -#define jadeXCMD_XF 0x80 -#define jadeXCMD_XME 0x40 -#define jadeXCMD_XRES 0x20 -#define jadeXCMD_STX 0x01 - -#define jade_HDLC_RSTA 0x21 /* R */ -#define jadeRSTA_VFR 0x80 -#define jadeRSTA_RDO 0x40 -#define jadeRSTA_CRC 0x20 -#define jadeRSTA_RAB 0x10 -#define jadeRSTA_MASK 0xF0 - -#define jade_HDLC_MODE 0x22 /* RW*/ -#define jadeMODE_TMO 0x80 -#define jadeMODE_RAC 0x40 -#define jadeMODE_XAC 0x20 -#define jadeMODE_TLP 0x10 -#define jadeMODE_ERFS 0x02 -#define jadeMODE_ETFS 0x01 - -#define jade_HDLC_RBCH 0x24 /* R */ - -#define jade_HDLC_RBCL 0x25 /* R */ -#define jade_HDLC_RCMD 0x25 /* W */ -#define jadeRCMD_RMC 0x80 -#define jadeRCMD_RRES 0x40 -#define jadeRCMD_RMD 0x20 -#define jadeRCMD_STR 0x02 - -#define jade_HDLC_CCR0 0x26 /* RW*/ -#define jadeCCR0_PU 0x80 -#define jadeCCR0_ITF 0x40 -#define jadeCCR0_C32 0x20 -#define jadeCCR0_CRL 0x10 -#define jadeCCR0_RCRC 0x08 -#define jadeCCR0_XCRC 0x04 -#define jadeCCR0_RMSB 0x02 -#define jadeCCR0_XMSB 0x01 - -#define jade_HDLC_CCR1 0x27 /* RW*/ -#define jadeCCR1_RCS0 0x80 -#define jadeCCR1_RCONT 0x40 -#define jadeCCR1_RFDIS 0x20 -#define jadeCCR1_XCS0 0x10 -#define jadeCCR1_XCONT 0x08 -#define jadeCCR1_XFDIS 0x04 - -#define jade_HDLC_TSAR 0x28 /* RW*/ -#define jade_HDLC_TSAX 0x29 /* RW*/ -#define jade_HDLC_RCCR 0x2A /* RW*/ -#define jade_HDLC_XCCR 0x2B /* RW*/ - -#define jade_HDLC_ISR 0x2C /* R */ -#define jade_HDLC_IMR 0x2C /* W */ -#define jadeISR_RME 0x80 -#define jadeISR_RPF 0x40 -#define jadeISR_RFO 0x20 -#define jadeISR_XPR 0x10 -#define jadeISR_XDU 0x08 -#define jadeISR_ALLS 0x04 - -#define jade_INT 0x75 -#define jadeINT_HDLC1 0x02 -#define jadeINT_HDLC2 0x01 -#define jadeINT_DSP 0x04 -#define jade_INTR 0x70 - -/********************************************************************/ -/* Indirect accessible JADE registers of common interest */ -/********************************************************************/ -#define jade_CHIPVERSIONNR 0x00 /* Does not work*/ - -#define jade_HDLCCNTRACCESS 0x10 -#define jadeINDIRECT_HAH1 0x02 -#define jadeINDIRECT_HAH2 0x01 - -#define jade_HDLC1SERRXPATH 0x1D -#define jade_HDLC1SERTXPATH 0x1E -#define jade_HDLC2SERRXPATH 0x1F -#define jade_HDLC2SERTXPATH 0x20 -#define jadeINDIRECT_SLIN1 0x10 -#define jadeINDIRECT_SLIN0 0x08 -#define jadeINDIRECT_LMOD1 0x04 -#define jadeINDIRECT_LMOD0 0x02 -#define jadeINDIRECT_HHR 0x01 -#define jadeINDIRECT_HHX 0x01 - -#define jade_RXAUDIOCH1CFG 0x11 -#define jade_RXAUDIOCH2CFG 0x14 -#define jade_TXAUDIOCH1CFG 0x17 -#define jade_TXAUDIOCH2CFG 0x1A - -extern int JadeVersion(struct IsdnCardState *cs, char *s); -extern void clear_pending_jade_ints(struct IsdnCardState *cs); -extern void initjade(struct IsdnCardState *cs); - -#endif /* __JADE_H__ */ diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c deleted file mode 100644 index a89e2df911c5..000000000000 --- a/drivers/isdn/hisax/jade_irq.c +++ /dev/null @@ -1,238 +0,0 @@ -/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $ - * - * Low level JADE IRQ stuff (derived from original hscx_irq.c) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -static inline void -waitforCEC(struct IsdnCardState *cs, int jade, int reg) -{ - int to = 50; - int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC); - while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n"); -} - - -static inline void -waitforXFW(struct IsdnCardState *cs, int jade) -{ - /* Does not work on older jade versions, don't care */ -} - -static inline void -WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data) -{ - waitforCEC(cs, jade, reg); - WRITEJADE(cs, jade, reg, data); -} - - - -static void -jade_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "jade_empty_fifo"); - - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "jade_empty_fifo: incoming packet too large"); - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); - bcs->hw.hscx.rcvidx = 0; - return; - } - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "jade_empty_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -jade_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count; - int fifo_size = 32; - u_char *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "jade_fill_fifo"); - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > fifo_size) { - more = !0; - count = fifo_size; - } else - count = bcs->tx_skb->len; - - waitforXFW(cs, bcs->hw.hscx.hscx); - ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME)); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "jade_fill_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - - -static void -jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) -{ - u_char r; - struct BCState *bcs = cs->bcs + jade; - struct sk_buff *skb; - int fifo_size = 32; - int count; - int i_jade = (int) jade; /* To satisfy the compiler */ - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - if (val & 0x80) { /* RME */ - r = READJADE(cs, i_jade, jade_HDLC_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!(r & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A")); - if ((r & 0x40) && bcs->mode) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode); - if (!(r & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %c CRC error", 'A' + jade); - WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC); - } else { - count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F; - if (count == 0) - count = fifo_size; - jade_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A")); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - jade_empty_fifo(bcs, fifo_size); - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(fifo_size))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - fifo_size); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & 0x10) { /* XPR */ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - jade_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - jade_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static inline void -jade_int_main(struct IsdnCardState *cs, u_char val, int jade) -{ - struct BCState *bcs; - bcs = cs->bcs + jade; - - if (val & jadeISR_RFO) { - /* handled with RDO */ - val &= ~jadeISR_RFO; - } - if (val & jadeISR_XDU) { - /* relevant in HDLC mode only */ - /* don't reset XPR here */ - if (bcs->mode == 1) - jade_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val); - } - } - if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val); - jade_interrupt(cs, val, jade); - } -} diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c deleted file mode 100644 index 98f60d1523f4..000000000000 --- a/drivers/isdn/hisax/l3_1tr6.c +++ /dev/null @@ -1,932 +0,0 @@ -/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $ - * - * German 1TR6 D-channel protocol - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - */ - -#include "hisax.h" -#include "l3_1tr6.h" -#include "isdnl3.h" -#include - -extern char *HiSax_getrev(const char *revision); -static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $"; - -#define MsgHead(ptr, cref, mty, dis) \ - *ptr++ = dis; \ - *ptr++ = 0x1; \ - *ptr++ = cref ^ 0x80; \ - *ptr++ = mty - -static void -l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd) -{ - struct sk_buff *skb; - u_char *p; - - if (!(skb = l3_alloc_skb(4))) - return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt, pd); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - l3_1tr6_release_req(pc, 0, NULL); -} - -static void -l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb) -{ - dev_kfree_skb(skb); - if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "%s", msg); - l3_1tr6_release_req(pc, 0, NULL); -} - -static void -l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char *teln; - u_char *eaz; - u_char channel = 0; - int l; - - MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1); - teln = pc->para.setup.phone; - pc->para.spv = 0; - if (!isdigit(*teln)) { - switch (0x5f & *teln) { - case 'S': - pc->para.spv = 1; - break; - case 'C': - channel = 0x08; - /* fall through */ - case 'P': - channel |= 0x80; - teln++; - if (*teln == '1') - channel |= 0x01; - else - channel |= 0x02; - break; - default: - if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "Wrong MSN Code"); - break; - } - teln++; - } - if (channel) { - *p++ = 0x18; /* channel indicator */ - *p++ = 1; - *p++ = channel; - } - if (pc->para.spv) { /* SPV ? */ - /* NSF SPV */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_SPV; /* SPV */ - *p++ = pc->para.setup.si1; /* 0 for all Services */ - *p++ = pc->para.setup.si2; /* 0 for all Services */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_Activate; /* aktiviere SPV (default) */ - *p++ = pc->para.setup.si1; /* 0 for all Services */ - *p++ = pc->para.setup.si2; /* 0 for all Services */ - } - eaz = pc->para.setup.eazmsn; - if (*eaz) { - *p++ = WE0_origAddr; - *p++ = strlen(eaz) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*eaz) - *p++ = *eaz++ & 0x7f; - } - *p++ = WE0_destAddr; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - *p++ = WE_Shift_F6; - /* Codesatz 6 fuer Service */ - *p++ = WE6_serviceInd; - *p++ = 2; /* len=2 info,info2 */ - *p++ = pc->para.setup.si1; - *p++ = pc->para.setup.si2; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T303, CC_T303); - newl3state(pc, 1); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int bcfound = 0; - struct sk_buff *skb = arg; - - /* Channel Identification */ - p = findie(skb->data, skb->len, WE0_chanID, 0); - if (p) { - if (p[1] != 1) { - l3_1tr6_error(pc, "setup wrong chanID len", skb); - return; - } - if ((p[2] & 0xf4) != 0x80) { - l3_1tr6_error(pc, "setup wrong WE0_chanID", skb); - return; - } - if ((pc->para.bchannel = p[2] & 0x3)) - bcfound++; - } else { - l3_1tr6_error(pc, "missing setup chanID", skb); - return; - } - - p = skb->data; - if ((p = findie(p, skb->len, WE6_serviceInd, 6))) { - pc->para.setup.si1 = p[2]; - pc->para.setup.si2 = p[3]; - } else { - l3_1tr6_error(pc, "missing setup SI", skb); - return; - } - - p = skb->data; - if ((p = findie(p, skb->len, WE0_destAddr, 0))) - iecpy(pc->para.setup.eazmsn, p, 1); - else - pc->para.setup.eazmsn[0] = 0; - - p = skb->data; - if ((p = findie(p, skb->len, WE0_origAddr, 0))) { - iecpy(pc->para.setup.phone, p, 1); - } else - pc->para.setup.phone[0] = 0; - - p = skb->data; - pc->para.spv = 0; - if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) { - if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) - pc->para.spv = 1; - } - dev_kfree_skb(skb); - - /* Signal all services, linklevel takes care of Service-Indicator */ - if (bcfound) { - if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) { - l3_debug(pc->st, "non-digital call: %s -> %s", - pc->para.setup.phone, - pc->para.setup.eazmsn); - } - newl3state(pc, 6); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); - } else - release_l3_process(pc); -} - -static void -l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - - L3DelTimer(&pc->timer); - p = skb->data; - newl3state(pc, 2); - if ((p = findie(p, skb->len, WE0_chanID, 0))) { - if (p[1] != 1) { - l3_1tr6_error(pc, "setup_ack wrong chanID len", skb); - return; - } - if ((p[2] & 0xf4) != 0x80) { - l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb); - return; - } - pc->para.bchannel = p[2] & 0x3; - } else { - l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb); - return; - } - dev_kfree_skb(skb); - L3AddTimer(&pc->timer, T304, CC_T304); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); -} - -static void -l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, WE0_chanID, 0))) { - if (p[1] != 1) { - l3_1tr6_error(pc, "call sent wrong chanID len", skb); - return; - } - if ((p[2] & 0xf4) != 0x80) { - l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb); - return; - } - if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) { - l3_1tr6_error(pc, "call sent wrong chanID value", skb); - return; - } - pc->para.bchannel = p[2] & 0x3; - } else { - l3_1tr6_error(pc, "missing call sent WE0_chanID", skb); - return; - } - dev_kfree_skb(skb); - L3AddTimer(&pc->timer, T310, CC_T310); - newl3state(pc, 3); - pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); -} - -static void -l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - L3DelTimer(&pc->timer); /* T304 */ - newl3state(pc, 4); - pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); -} - -static void -l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int i, tmpcharge = 0; - char a_charge[8]; - struct sk_buff *skb = arg; - - p = skb->data; - if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { - iecpy(a_charge, p, 1); - for (i = 0; i < strlen(a_charge); i++) { - tmpcharge *= 10; - tmpcharge += a_charge[i] & 0xf; - } - if (tmpcharge > pc->para.chargeinfo) { - pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - l3_debug(pc->st, "charging info %d", - pc->para.chargeinfo); - } - } else if (pc->st->l3.debug & L3_DEB_CHARGE) - l3_debug(pc->st, "charging info not found"); - dev_kfree_skb(skb); - -} - -static void -l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); -} - -static void -l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - L3DelTimer(&pc->timer); /* T310 */ - if (!findie(skb->data, skb->len, WE6_date, 6)) { - l3_1tr6_error(pc, "missing connect date", skb); - return; - } - newl3state(pc, 10); - dev_kfree_skb(skb); - pc->para.chargeinfo = 0; - pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); -} - -static void -l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - - p = skb->data; - if ((p = findie(p, skb->len, WE0_cause, 0))) { - if (p[1] > 0) { - pc->para.cause = p[2]; - if (p[1] > 1) - pc->para.loc = p[3]; - else - pc->para.loc = 0; - } else { - pc->para.cause = 0; - pc->para.loc = 0; - } - } else { - pc->para.cause = NO_CAUSE; - l3_1tr6_error(pc, "missing REL cause", skb); - return; - } - dev_kfree_skb(skb); - StopAllL3Timer(pc); - newl3state(pc, 0); - l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -static void -l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - StopAllL3Timer(pc); - newl3state(pc, 0); - pc->para.cause = NO_CAUSE; - pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); - release_l3_process(pc); -} - -static void -l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int i, tmpcharge = 0; - char a_charge[8]; - - StopAllL3Timer(pc); - p = skb->data; - if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { - iecpy(a_charge, p, 1); - for (i = 0; i < strlen(a_charge); i++) { - tmpcharge *= 10; - tmpcharge += a_charge[i] & 0xf; - } - if (tmpcharge > pc->para.chargeinfo) { - pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - l3_debug(pc->st, "charging info %d", - pc->para.chargeinfo); - } - } else if (pc->st->l3.debug & L3_DEB_CHARGE) - l3_debug(pc->st, "charging info not found"); - - - p = skb->data; - if ((p = findie(p, skb->len, WE0_cause, 0))) { - if (p[1] > 0) { - pc->para.cause = p[2]; - if (p[1] > 1) - pc->para.loc = p[3]; - else - pc->para.loc = 0; - } else { - pc->para.cause = 0; - pc->para.loc = 0; - } - } else { - if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "cause not found"); - pc->para.cause = NO_CAUSE; - } - if (!findie(skb->data, skb->len, WE6_date, 6)) { - l3_1tr6_error(pc, "missing connack date", skb); - return; - } - dev_kfree_skb(skb); - newl3state(pc, 12); - pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); -} - - -static void -l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - if (!findie(skb->data, skb->len, WE6_date, 6)) { - l3_1tr6_error(pc, "missing connack date", skb); - return; - } - dev_kfree_skb(skb); - newl3state(pc, 10); - pc->para.chargeinfo = 0; - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); -} - -static void -l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 7); - l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1); -} - -static void -l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[24]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1); - if (pc->para.spv) { /* SPV ? */ - /* NSF SPV */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_SPV; /* SPV */ - *p++ = pc->para.setup.si1; - *p++ = pc->para.setup.si2; - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_Activate; /* aktiviere SPV */ - *p++ = pc->para.setup.si1; - *p++ = pc->para.setup.si2; - } - newl3state(pc, 8); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg) -{ - release_l3_process(pc); -} - -static void -l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 0x10; - u_char clen = 1; - - if (pc->para.cause > 0) - cause = pc->para.cause; - /* Map DSS1 causes */ - switch (cause & 0x7f) { - case 0x10: - clen = 0; - break; - case 0x11: - cause = CAUSE_UserBusy; - break; - case 0x15: - cause = CAUSE_CallRejected; - break; - } - StopAllL3Timer(pc); - MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1); - *p++ = WE0_cause; - *p++ = clen; /* Laenge */ - if (clen) - *p++ = cause | 0x80; - newl3state(pc, 11); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T305, CC_T305); -} - -static void -l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->N303 > 0) { - pc->N303--; - L3DelTimer(&pc->timer); - l3_1tr6_setup_req(pc, pr, arg); - } else { - L3DelTimer(&pc->timer); - pc->para.cause = 0; - l3_1tr6_disconnect_req(pc, 0, NULL); - } -} - -static void -l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 0x90; - u_char clen = 1; - - L3DelTimer(&pc->timer); - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - /* Map DSS1 causes */ - switch (cause & 0x7f) { - case 0x10: - clen = 0; - break; - case 0x15: - cause = CAUSE_CallRejected; - break; - } - MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1); - *p++ = WE0_cause; - *p++ = clen; /* Laenge */ - if (clen) - *p++ = cause; - newl3state(pc, 19); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); -} - -static void -l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); - L3AddTimer(&pc->timer, T308, CC_T308_2); - newl3state(pc, 19); -} - -static void -l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); - release_l3_process(pc); -} - -static void -l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg) -{ - pc->para.cause = CAUSE_LocalProcErr; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 0); - pc->para.cause = 0x1b; /* Destination out of order */ - pc->para.loc = 0; - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -/* *INDENT-OFF* */ -static struct stateentry downstl[] = -{ - {SBIT(0), - CC_SETUP | REQUEST, l3_1tr6_setup_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | - SBIT(10), - CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req}, - {SBIT(12), - CC_RELEASE | REQUEST, l3_1tr6_release_req}, - {SBIT(6), - CC_IGNORE | REQUEST, l3_1tr6_reset}, - {SBIT(6), - CC_REJECT | REQUEST, l3_1tr6_disconnect_req}, - {SBIT(6), - CC_ALERTING | REQUEST, l3_1tr6_alert_req}, - {SBIT(6) | SBIT(7), - CC_SETUP | RESPONSE, l3_1tr6_setup_rsp}, - {SBIT(1), - CC_T303, l3_1tr6_t303}, - {SBIT(2), - CC_T304, l3_1tr6_t304}, - {SBIT(3), - CC_T310, l3_1tr6_t310}, - {SBIT(8), - CC_T313, l3_1tr6_t313}, - {SBIT(11), - CC_T305, l3_1tr6_t305}, - {SBIT(19), - CC_T308_1, l3_1tr6_t308_1}, - {SBIT(19), - CC_T308_2, l3_1tr6_t308_2}, -}; - -static struct stateentry datastln1[] = -{ - {SBIT(0), - MT_N1_INVALID, l3_1tr6_invalid}, - {SBIT(0), - MT_N1_SETUP, l3_1tr6_setup}, - {SBIT(1), - MT_N1_SETUP_ACK, l3_1tr6_setup_ack}, - {SBIT(1) | SBIT(2), - MT_N1_CALL_SENT, l3_1tr6_call_sent}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), - MT_N1_DISC, l3_1tr6_disc}, - {SBIT(2) | SBIT(3) | SBIT(4), - MT_N1_ALERT, l3_1tr6_alert}, - {SBIT(2) | SBIT(3) | SBIT(4), - MT_N1_CONN, l3_1tr6_connect}, - {SBIT(2), - MT_N1_INFO, l3_1tr6_info_s2}, - {SBIT(8), - MT_N1_CONN_ACK, l3_1tr6_connect_ack}, - {SBIT(10), - MT_N1_INFO, l3_1tr6_info}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | - SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), - MT_N1_REL, l3_1tr6_rel}, - {SBIT(19), - MT_N1_REL, l3_1tr6_rel_ack}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | - SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), - MT_N1_REL_ACK, l3_1tr6_invalid}, - {SBIT(19), - MT_N1_REL_ACK, l3_1tr6_rel_ack} -}; - -static struct stateentry manstatelist[] = -{ - {SBIT(2), - DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset}, - {ALL_STATES, - DL_RELEASE | INDICATION, l3_1tr6_dl_release}, -}; - -/* *INDENT-ON* */ - -static void -up1tr6(struct PStack *st, int pr, void *arg) -{ - int i, mt, cr; - struct l3_process *proc; - struct sk_buff *skb = arg; - - switch (pr) { - case (DL_DATA | INDICATION): - case (DL_UNIT_DATA | INDICATION): - break; - case (DL_ESTABLISH | CONFIRM): - case (DL_ESTABLISH | INDICATION): - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - l3_msg(st, pr, arg); - return; - break; - } - if (skb->len < 4) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 len only %d", skb->len); - } - dev_kfree_skb(skb); - return; - } - if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6%sunexpected discriminator %x message len %d", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - skb->data[0], skb->len); - } - dev_kfree_skb(skb); - return; - } - if (skb->data[1] != 1) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 CR len not 1"); - } - dev_kfree_skb(skb); - return; - } - cr = skb->data[2]; - mt = skb->data[3]; - if (skb->data[0] == PROTO_DIS_N0) { - dev_kfree_skb(skb); - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "up1tr6%s N0 mt %x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt); - } - } else if (skb->data[0] == PROTO_DIS_N1) { - if (!(proc = getl3proc(st, cr))) { - if (mt == MT_N1_SETUP) { - if (cr < 128) { - if (!(proc = new_l3_process(st, cr))) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 no roc mem"); - } - dev_kfree_skb(skb); - return; - } - } else { - dev_kfree_skb(skb); - return; - } - } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) || - (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) || - (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) || - (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) || - (mt == MT_N1_INFO)) { - dev_kfree_skb(skb); - return; - } else { - if (!(proc = new_l3_process(st, cr))) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 no roc mem"); - } - dev_kfree_skb(skb); - return; - } - mt = MT_N1_INVALID; - } - } - for (i = 0; i < ARRAY_SIZE(datastln1); i++) - if ((mt == datastln1[i].primitive) && - ((1 << proc->state) & datastln1[i].state)) - break; - if (i == ARRAY_SIZE(datastln1)) { - dev_kfree_skb(skb); - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "up1tr6%sstate %d mt %x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - return; - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "up1tr6%sstate %d mt %x", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - datastln1[i].rout(proc, pr, skb); - } - } -} - -static void -down1tr6(struct PStack *st, int pr, void *arg) -{ - int i, cr; - struct l3_process *proc; - struct Channel *chan; - - if ((DL_ESTABLISH | REQUEST) == pr) { - l3_msg(st, pr, NULL); - return; - } else if ((CC_SETUP | REQUEST) == pr) { - chan = arg; - cr = newcallref(); - cr |= 0x80; - if (!(proc = new_l3_process(st, cr))) { - return; - } else { - proc->chan = chan; - chan->proc = proc; - memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); - proc->callref = cr; - } - } else { - proc = arg; - } - - for (i = 0; i < ARRAY_SIZE(downstl); i++) - if ((pr == downstl[i].primitive) && - ((1 << proc->state) & downstl[i].state)) - break; - if (i == ARRAY_SIZE(downstl)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "down1tr6 state %d prim %d unhandled", - proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "down1tr6 state %d prim %d", - proc->state, pr); - } - downstl[i].rout(proc, pr, arg); - } -} - -static void -man1tr6(struct PStack *st, int pr, void *arg) -{ - int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < ARRAY_SIZE(manstatelist); i++) - if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == ARRAY_SIZE(manstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d man1tr6 state %d prim %d", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } -} - -void -setstack_1tr6(struct PStack *st) -{ - char tmp[64]; - - st->lli.l4l3 = down1tr6; - st->l2.l2l3 = up1tr6; - st->l3.l3ml3 = man1tr6; - st->l3.N303 = 0; - - strcpy(tmp, l3_1tr6_revision); - printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp)); -} diff --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h deleted file mode 100644 index 43215c00cada..000000000000 --- a/drivers/isdn/hisax/l3_1tr6.h +++ /dev/null @@ -1,164 +0,0 @@ -/* $Id: l3_1tr6.h,v 2.2.6.2 2001/09/23 22:24:49 kai Exp $ - * - * German 1TR6 D-channel protocol defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef l3_1tr6 -#define l3_1tr6 - -#define PROTO_DIS_N0 0x40 -#define PROTO_DIS_N1 0x41 - -/* - * MsgType N0 - */ -#define MT_N0_REG_IND 0x61 -#define MT_N0_CANC_IND 0x62 -#define MT_N0_FAC_STA 0x63 -#define MT_N0_STA_ACK 0x64 -#define MT_N0_STA_REJ 0x65 -#define MT_N0_FAC_INF 0x66 -#define MT_N0_INF_ACK 0x67 -#define MT_N0_INF_REJ 0x68 -#define MT_N0_CLOSE 0x75 -#define MT_N0_CLO_ACK 0x77 - -/* - * MsgType N1 - */ - -#define MT_N1_ESC 0x00 -#define MT_N1_ALERT 0x01 -#define MT_N1_CALL_SENT 0x02 -#define MT_N1_CONN 0x07 -#define MT_N1_CONN_ACK 0x0F -#define MT_N1_SETUP 0x05 -#define MT_N1_SETUP_ACK 0x0D -#define MT_N1_RES 0x26 -#define MT_N1_RES_ACK 0x2E -#define MT_N1_RES_REJ 0x22 -#define MT_N1_SUSP 0x25 -#define MT_N1_SUSP_ACK 0x2D -#define MT_N1_SUSP_REJ 0x21 -#define MT_N1_USER_INFO 0x20 -#define MT_N1_DET 0x40 -#define MT_N1_DISC 0x45 -#define MT_N1_REL 0x4D -#define MT_N1_REL_ACK 0x5A -#define MT_N1_CANC_ACK 0x6E -#define MT_N1_CANC_REJ 0x67 -#define MT_N1_CON_CON 0x69 -#define MT_N1_FAC 0x60 -#define MT_N1_FAC_ACK 0x68 -#define MT_N1_FAC_CAN 0x66 -#define MT_N1_FAC_REG 0x64 -#define MT_N1_FAC_REJ 0x65 -#define MT_N1_INFO 0x6D -#define MT_N1_REG_ACK 0x6C -#define MT_N1_REG_REJ 0x6F -#define MT_N1_STAT 0x63 -#define MT_N1_INVALID 0 - -/* - * W Elemente - */ - -#define WE_Shift_F0 0x90 -#define WE_Shift_F6 0x96 -#define WE_Shift_OF0 0x98 -#define WE_Shift_OF6 0x9E - -#define WE0_cause 0x08 -#define WE0_connAddr 0x0C -#define WE0_callID 0x10 -#define WE0_chanID 0x18 -#define WE0_netSpecFac 0x20 -#define WE0_display 0x28 -#define WE0_keypad 0x2C -#define WE0_origAddr 0x6C -#define WE0_destAddr 0x70 -#define WE0_userInfo 0x7E - -#define WE0_moreData 0xA0 -#define WE0_congestLevel 0xB0 - -#define WE6_serviceInd 0x01 -#define WE6_chargingInfo 0x02 -#define WE6_date 0x03 -#define WE6_facSelect 0x05 -#define WE6_facStatus 0x06 -#define WE6_statusCalled 0x07 -#define WE6_addTransAttr 0x08 - -/* - * FacCodes - */ -#define FAC_Sperre 0x01 -#define FAC_Sperre_All 0x02 -#define FAC_Sperre_Fern 0x03 -#define FAC_Sperre_Intl 0x04 -#define FAC_Sperre_Interk 0x05 - -#define FAC_Forward1 0x02 -#define FAC_Forward2 0x03 -#define FAC_Konferenz 0x06 -#define FAC_GrabBchan 0x0F -#define FAC_Reactivate 0x10 -#define FAC_Konferenz3 0x11 -#define FAC_Dienstwechsel1 0x12 -#define FAC_Dienstwechsel2 0x13 -#define FAC_NummernIdent 0x14 -#define FAC_GBG 0x15 -#define FAC_DisplayUebergeben 0x17 -#define FAC_DisplayUmgeleitet 0x1A -#define FAC_Unterdruecke 0x1B -#define FAC_Deactivate 0x1E -#define FAC_Activate 0x1D -#define FAC_SPV 0x1F -#define FAC_Rueckwechsel 0x23 -#define FAC_Umleitung 0x24 - -/* - * Cause codes - */ -#define CAUSE_InvCRef 0x01 -#define CAUSE_BearerNotImpl 0x03 -#define CAUSE_CIDunknown 0x07 -#define CAUSE_CIDinUse 0x08 -#define CAUSE_NoChans 0x0A -#define CAUSE_FacNotImpl 0x10 -#define CAUSE_FacNotSubscr 0x11 -#define CAUSE_OutgoingBarred 0x20 -#define CAUSE_UserAccessBusy 0x21 -#define CAUSE_NegativeGBG 0x22 -#define CAUSE_UnknownGBG 0x23 -#define CAUSE_NoSPVknown 0x25 -#define CAUSE_DestNotObtain 0x35 -#define CAUSE_NumberChanged 0x38 -#define CAUSE_OutOfOrder 0x39 -#define CAUSE_NoUserResponse 0x3A -#define CAUSE_UserBusy 0x3B -#define CAUSE_IncomingBarred 0x3D -#define CAUSE_CallRejected 0x3E -#define CAUSE_NetworkCongestion 0x59 -#define CAUSE_RemoteUser 0x5A -#define CAUSE_LocalProcErr 0x70 -#define CAUSE_RemoteProcErr 0x71 -#define CAUSE_RemoteUserSuspend 0x72 -#define CAUSE_RemoteUserResumed 0x73 -#define CAUSE_UserInfoDiscarded 0x7F - -#define T303 4000 -#define T304 20000 -#define T305 4000 -#define T308 4000 -#define T310 120000 -#define T313 4000 -#define T318 4000 -#define T319 4000 - -#endif diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c deleted file mode 100644 index 368d152a8f1d..000000000000 --- a/drivers/isdn/hisax/l3dss1.c +++ /dev/null @@ -1,3227 +0,0 @@ -/* $Id: l3dss1.c,v 2.32.2.3 2004/01/13 14:31:25 keil Exp $ - * - * EURO/DSS1 D-channel protocol - * - * German 1TR6 D-channel protocol - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include "hisax.h" -#include "isdnl3.h" -#include "l3dss1.h" -#include -#include - -extern char *HiSax_getrev(const char *revision); -static const char *dss1_revision = "$Revision: 2.32.2.3 $"; - -#define EXT_BEARER_CAPS 1 - -#define MsgHead(ptr, cref, mty) \ - *ptr++ = 0x8; \ - if (cref == -1) { \ - *ptr++ = 0x0; \ - } else { \ - *ptr++ = 0x1; \ - *ptr++ = cref^0x80; \ - } \ - *ptr++ = mty - - -/**********************************************/ -/* get a new invoke id for remote operations. */ -/* Only a return value != 0 is valid */ -/**********************************************/ -static unsigned char new_invoke_id(struct PStack *p) -{ - unsigned char retval; - int i; - - i = 32; /* maximum search depth */ - - retval = p->prot.dss1.last_invoke_id + 1; /* try new id */ - while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) { - p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8; - i--; - } - if (i) { - while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7))) - retval++; - } else - retval = 0; - p->prot.dss1.last_invoke_id = retval; - p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7)); - return (retval); -} /* new_invoke_id */ - -/*************************/ -/* free a used invoke id */ -/*************************/ -static void free_invoke_id(struct PStack *p, unsigned char id) -{ - - if (!id) return; /* 0 = invalid value */ - - p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7)); -} /* free_invoke_id */ - - -/**********************************************************/ -/* create a new l3 process and fill in dss1 specific data */ -/**********************************************************/ -static struct l3_process -*dss1_new_l3_process(struct PStack *st, int cr) -{ struct l3_process *proc; - - if (!(proc = new_l3_process(st, cr))) - return (NULL); - - proc->prot.dss1.invoke_id = 0; - proc->prot.dss1.remote_operation = 0; - proc->prot.dss1.uus1_data[0] = '\0'; - - return (proc); -} /* dss1_new_l3_process */ - -/************************************************/ -/* free a l3 process and all dss1 specific data */ -/************************************************/ -static void -dss1_release_l3_process(struct l3_process *p) -{ - free_invoke_id(p->st, p->prot.dss1.invoke_id); - release_l3_process(p); -} /* dss1_release_l3_process */ - -/********************************************************/ -/* search a process with invoke id id and dummy callref */ -/********************************************************/ -static struct l3_process * -l3dss1_search_dummy_proc(struct PStack *st, int id) -{ struct l3_process *pc = st->l3.proc; /* start of processes */ - - if (!id) return (NULL); - - while (pc) - { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id)) - return (pc); - pc = pc->next; - } - return (NULL); -} /* l3dss1_search_dummy_proc */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return result is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3dss1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_RES; - ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; - ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; - ic.parm.dss1_io.proc = pc->prot.dss1.proc; - ic.parm.dss1_io.timeout = 0; - ic.parm.dss1_io.datalen = nlen; - ic.parm.dss1_io.data = p; - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - pc->prot.dss1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - dss1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen); -} /* l3dss1_dummy_return_result */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return error is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3dss1_dummy_error_return(struct PStack *st, int id, ulong error) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3dss1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_ERR; - ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; - ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; - ic.parm.dss1_io.proc = pc->prot.dss1.proc; - ic.parm.dss1_io.timeout = error; - ic.parm.dss1_io.datalen = 0; - ic.parm.dss1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - pc->prot.dss1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - dss1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error); -} /* l3dss1_error_return */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a invoke is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3dss1_dummy_invoke(struct PStack *st, int cr, int id, - int ident, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - - l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", - (cr == -1) ? "local" : "broadcast", id, ident, nlen); - if (cr >= -1) return; /* ignore local data */ - - cs = st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_BRD; - ic.parm.dss1_io.hl_id = id; - ic.parm.dss1_io.ll_id = 0; - ic.parm.dss1_io.proc = ident; - ic.parm.dss1_io.timeout = 0; - ic.parm.dss1_io.datalen = nlen; - ic.parm.dss1_io.data = p; - - cs->iif.statcallb(&ic); -} /* l3dss1_dummy_invoke */ - -static void -l3dss1_parse_facility(struct PStack *st, struct l3_process *pc, - int cr, u_char *p) -{ - int qd_len = 0; - unsigned char nlen = 0, ilen, cp_tag; - int ident, id; - ulong err_ret; - - if (pc) - st = pc->st; /* valid Stack */ - else - if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ - - p++; - qd_len = *p++; - if (qd_len == 0) { - l3_debug(st, "qd_len == 0"); - return; - } - if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ - l3_debug(st, "supplementary service != 0x11"); - return; - } - while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ - p++; - qd_len--; - } - if (qd_len < 2) { - l3_debug(st, "qd_len < 2"); - return; - } - p++; - qd_len--; - if ((*p & 0xE0) != 0xA0) { /* class and form */ - l3_debug(st, "class and form != 0xA0"); - return; - } - - cp_tag = *p & 0x1F; /* remember tag value */ - - p++; - qd_len--; - if (qd_len < 1) - { l3_debug(st, "qd_len < 1"); - return; - } - if (*p & 0x80) - { /* length format indefinite or limited */ - nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ - if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || - (nlen > 1)) - { l3_debug(st, "length format error or not implemented"); - return; - } - if (nlen == 1) - { nlen = *p++; /* complete length */ - qd_len--; - } - else - { qd_len -= 2; /* trailing null bytes */ - if ((*(p + qd_len)) || (*(p + qd_len + 1))) - { l3_debug(st, "length format indefinite error"); - return; - } - nlen = qd_len; - } - } - else - { nlen = *p++; - qd_len--; - } - if (qd_len < nlen) - { l3_debug(st, "qd_len < nlen"); - return; - } - qd_len -= nlen; - - if (nlen < 2) - { l3_debug(st, "nlen < 2"); - return; - } - if (*p != 0x02) - { /* invoke identifier tag */ - l3_debug(st, "invoke identifier tag !=0x02"); - return; - } - p++; - nlen--; - if (*p & 0x80) - { /* length format */ - l3_debug(st, "invoke id length format 2"); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - id = 0; - while (ilen > 0) - { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ - ilen--; - } - - switch (cp_tag) { /* component tag */ - case 1: /* invoke */ - if (nlen < 2) { - l3_debug(st, "nlen < 2 22"); - return; - } - if (*p != 0x02) { /* operation value */ - l3_debug(st, "operation value !=0x02"); - return; - } - p++; - nlen--; - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) { - l3_debug(st, "ilen > nlen || ilen == 0 22"); - return; - } - nlen -= ilen; - ident = 0; - while (ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); - ilen--; - } - - if (!pc) - { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen); - return; - } -#ifdef CONFIG_DE_AOC - { - -#define FOO1(s, a, b) \ - while (nlen > 1) { \ - int ilen = p[1]; \ - if (nlen < ilen + 2) { \ - l3_debug(st, "FOO1 nlen < ilen+2"); \ - return; \ - } \ - nlen -= ilen + 2; \ - if ((*p & 0xFF) == (a)) { \ - int nlen = ilen; \ - p += 2; \ - b; \ - } else { \ - p += ilen + 2; \ - } \ - } - - switch (ident) { - case 0x22: /* during */ - FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( { - ident = 0; - nlen = (nlen) ? nlen : 0; /* Make gcc happy */ - while (ilen > 0) { - ident = (ident << 8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); - } - if (st->l3.debug & L3_DEB_CHARGE) { - if (*(p + 2) == 0) { - l3_debug(st, "charging info during %d", pc->para.chargeinfo); - } - else { - l3_debug(st, "charging info final %d", pc->para.chargeinfo); - } - } - } - ))))) - break; - case 0x24: /* final */ - FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( { - ident = 0; - nlen = (nlen) ? nlen : 0; /* Make gcc happy */ - while (ilen > 0) { - ident = (ident << 8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); - } - if (st->l3.debug & L3_DEB_CHARGE) { - l3_debug(st, "charging info final %d", pc->para.chargeinfo); - } - } - )))))) - break; - default: - l3_debug(st, "invoke break invalid ident %02x", ident); - break; - } -#undef FOO1 - - } -#else /* not CONFIG_DE_AOC */ - l3_debug(st, "invoke break"); -#endif /* not CONFIG_DE_AOC */ - break; - case 2: /* return result */ - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3dss1_dummy_return_result(st, id, p, nlen); - return; - } - if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) - { /* Diversion successful */ - free_invoke_id(st, pc->prot.dss1.invoke_id); - pc->prot.dss1.remote_result = 0; /* success */ - pc->prot.dss1.invoke_id = 0; - pc->redir_result = pc->prot.dss1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ - else - l3_debug(st, "return error unknown identifier"); - break; - case 3: /* return error */ - err_ret = 0; - if (nlen < 2) - { l3_debug(st, "return error nlen < 2"); - return; - } - if (*p != 0x02) - { /* result tag */ - l3_debug(st, "invoke error tag !=0x02"); - return; - } - p++; - nlen--; - if (*p > 4) - { /* length format */ - l3_debug(st, "invoke return errlen > 4 "); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "error return ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - while (ilen > 0) - { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ - ilen--; - } - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3dss1_dummy_error_return(st, id, err_ret); - return; - } - if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) - { /* Deflection error */ - free_invoke_id(st, pc->prot.dss1.invoke_id); - pc->prot.dss1.remote_result = err_ret; /* result */ - pc->prot.dss1.invoke_id = 0; - pc->redir_result = pc->prot.dss1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); - } /* Deflection error */ - else - l3_debug(st, "return result unknown identifier"); - break; - default: - l3_debug(st, "facility default break tag=0x%02x", cp_tag); - break; - } -} - -static void -l3dss1_message(struct l3_process *pc, u_char mt) -{ - struct sk_buff *skb; - u_char *p; - - if (!(skb = l3_alloc_skb(4))) - return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, mt); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - MsgHead(p, pc->callref, MT_STATUS); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - - *p++ = IE_CALL_STATE; - *p++ = 0x1; - *p++ = pc->state & 0x3f; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) -{ - /* This routine is called if here was no SETUP made (checks in dss1up and in - * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code - * MT_STATUS_ENQUIRE in the NULL state is handled too - */ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - switch (pc->para.cause) { - case 81: /* invalid callreference */ - case 88: /* incomp destination */ - case 96: /* mandory IE missing */ - case 100: /* invalid IE contents */ - case 101: /* incompatible Callstate */ - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - break; - default: - printk(KERN_ERR "HiSax l3dss1_msg_without_setup wrong cause %d\n", - pc->para.cause); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - dss1_release_l3_process(pc); -} - -static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, - IE_USER_USER, -1}; -static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; -static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, - IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, - IE_CALLED_PN, -1}; -static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | - IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; -static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, - IE_SIGNAL, IE_USER_USER, -1}; -/* a RELEASE_COMPLETE with errors don't require special actions - static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -*/ -static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_DISPLAY, -1}; -static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, - IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS, - IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, - IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, - IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | - IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; -static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; -static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -/* not used - * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, - * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; - * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; - * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | - * IE_MANDATORY, -1}; - */ -static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; -static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1}; -static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1}; - -struct ie_len { - int ie; - int len; -}; - -static -struct ie_len max_ie_len[] = { - {IE_SEGMENT, 4}, - {IE_BEARER, 12}, - {IE_CAUSE, 32}, - {IE_CALL_ID, 10}, - {IE_CALL_STATE, 3}, - {IE_CHANNEL_ID, 34}, - {IE_FACILITY, 255}, - {IE_PROGRESS, 4}, - {IE_NET_FAC, 255}, - {IE_NOTIFY, 3}, - {IE_DISPLAY, 82}, - {IE_DATE, 8}, - {IE_KEYPAD, 34}, - {IE_SIGNAL, 3}, - {IE_INFORATE, 6}, - {IE_E2E_TDELAY, 11}, - {IE_TDELAY_SEL, 5}, - {IE_PACK_BINPARA, 3}, - {IE_PACK_WINSIZE, 4}, - {IE_PACK_SIZE, 4}, - {IE_CUG, 7}, - {IE_REV_CHARGE, 3}, - {IE_CALLING_PN, 24}, - {IE_CALLING_SUB, 23}, - {IE_CALLED_PN, 24}, - {IE_CALLED_SUB, 23}, - {IE_REDIR_NR, 255}, - {IE_TRANS_SEL, 255}, - {IE_RESTART_IND, 3}, - {IE_LLC, 18}, - {IE_HLC, 5}, - {IE_USER_USER, 131}, - {-1, 0}, -}; - -static int -getmax_ie_len(u_char ie) { - int i = 0; - while (max_ie_len[i].ie != -1) { - if (max_ie_len[i].ie == ie) - return (max_ie_len[i].len); - i++; - } - return (255); -} - -static int -ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { - int ret = 1; - - while (*checklist != -1) { - if ((*checklist & 0xff) == ie) { - if (ie & 0x80) - return (-ret); - else - return (ret); - } - ret++; - checklist++; - } - return (0); -} - -static int -check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) -{ - int *cl = checklist; - u_char mt; - u_char *p, ie; - int l, newpos, oldpos; - int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - u_char codeset = 0; - u_char old_codeset = 0; - u_char codelock = 1; - - p = skb->data; - /* skip cr */ - p++; - l = (*p++) & 0xf; - p += l; - mt = *p++; - oldpos = 0; - while ((p - skb->data) < skb->len) { - if ((*p & 0xf0) == 0x90) { /* shift codeset */ - old_codeset = codeset; - codeset = *p & 7; - if (*p & 0x08) - codelock = 0; - else - codelock = 1; - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift%scodeset %d->%d", - codelock ? " locking " : " ", old_codeset, codeset); - p++; - continue; - } - if (!codeset) { /* only codeset 0 */ - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; - else - oldpos = newpos; - } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; - } - } - ie = *p++; - if (ie & 0x80) { - l = 1; - } else { - l = *p++; - p += l; - l += 2; - } - if (!codeset && (l > getmax_ie_len(ie))) - err_len++; - if (!codelock) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift back codeset %d->%d", - codeset, old_codeset); - codeset = old_codeset; - codelock = 1; - } - } - if (err_compr | err_ureg | err_len | err_seq) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", - mt, err_compr, err_ureg, err_len, err_seq); - if (err_compr) - return (ERR_IE_COMPREHENSION); - if (err_ureg) - return (ERR_IE_UNRECOGNIZED); - if (err_len) - return (ERR_IE_LENGTH); - if (err_seq) - return (ERR_IE_SEQUENCE); - } - return (0); -} - -/* verify if a message type exists and contain no IE error */ -static int -l3dss1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) -{ - switch (mt) { - case MT_ALERTING: - case MT_CALL_PROCEEDING: - case MT_CONNECT: - case MT_CONNECT_ACKNOWLEDGE: - case MT_DISCONNECT: - case MT_INFORMATION: - case MT_FACILITY: - case MT_NOTIFY: - case MT_PROGRESS: - case MT_RELEASE: - case MT_RELEASE_COMPLETE: - case MT_SETUP: - case MT_SETUP_ACKNOWLEDGE: - case MT_RESUME_ACKNOWLEDGE: - case MT_RESUME_REJECT: - case MT_SUSPEND_ACKNOWLEDGE: - case MT_SUSPEND_REJECT: - case MT_USER_INFORMATION: - case MT_RESTART: - case MT_RESTART_ACKNOWLEDGE: - case MT_CONGESTION_CONTROL: - case MT_STATUS: - case MT_STATUS_ENQUIRY: - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) OK", mt); - break; - case MT_RESUME: /* RESUME only in user->net */ - case MT_SUSPEND: /* SUSPEND only in user->net */ - default: - if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) - l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) fail", mt); - pc->para.cause = 97; - l3dss1_status_send(pc, 0, NULL); - return (1); - } - return (0); -} - -static void -l3dss1_std_ie_err(struct l3_process *pc, int ret) { - - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements ret %d", ret); - switch (ret) { - case 0: - break; - case ERR_IE_COMPREHENSION: - pc->para.cause = 96; - l3dss1_status_send(pc, 0, NULL); - break; - case ERR_IE_UNRECOGNIZED: - pc->para.cause = 99; - l3dss1_status_send(pc, 0, NULL); - break; - case ERR_IE_LENGTH: - pc->para.cause = 100; - l3dss1_status_send(pc, 0, NULL); - break; - case ERR_IE_SEQUENCE: - default: - break; - } -} - -static int -l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { - u_char *p; - - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - p++; - if (*p != 1) { /* len for BRI = 1 */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid len %d", *p); - return (-2); - } - p++; - if (*p & 0x60) { /* only base rate interface */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid %x", *p); - return (-3); - } - return (*p & 0x3); - } else - return (-1); -} - -static int -l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) { - u_char l, i = 0; - u_char *p; - - p = skb->data; - pc->para.cause = 31; - pc->para.loc = 0; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - l = *p++; - if (l > 30) - return (1); - if (l) { - pc->para.loc = *p++; - l--; - } else { - return (2); - } - if (l && !(pc->para.loc & 0x80)) { - l--; - p++; /* skip recommendation */ - } - if (l) { - pc->para.cause = *p++; - l--; - if (!(pc->para.cause & 0x80)) - return (3); - } else - return (4); - while (l && (i < 6)) { - pc->para.diag[i++] = *p++; - l--; - } - } else - return (-1); - return (0); -} - -static void -l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, cmd); - - if (pc->prot.dss1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.dss1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.dss1.uus1_data); - p += strlen(pc->prot.dss1.uus1_data); - pc->prot.dss1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3dss1_msg_with_uus */ - -static void -l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - if (!pc->prot.dss1.uus1_data[0]) - l3dss1_message(pc, MT_RELEASE); - else - l3dss1_msg_with_uus(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3dss1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - StopAllL3Timer(pc); - newl3state(pc, 0); - pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); - dss1_release_l3_process(pc); -} - -#ifdef EXT_BEARER_CAPS - -static u_char * -EncodeASyncParams(u_char *p, u_char si2) -{ // 7c 06 88 90 21 42 00 bb - - p[0] = 0; - p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 - p[2] = 0x80; - if (si2 & 32) // 7 data bits - - p[2] += 16; - else // 8 data bits - - p[2] += 24; - - if (si2 & 16) // 2 stop bits - - p[2] += 96; - else // 1 stop bit - - p[2] += 32; - - if (si2 & 8) // even parity - - p[2] += 2; - else // no parity - - p[2] += 3; - - switch (si2 & 0x07) { - case 0: - p[0] = 66; // 1200 bit/s - - break; - case 1: - p[0] = 88; // 1200/75 bit/s - - break; - case 2: - p[0] = 87; // 75/1200 bit/s - - break; - case 3: - p[0] = 67; // 2400 bit/s - - break; - case 4: - p[0] = 69; // 4800 bit/s - - break; - case 5: - p[0] = 72; // 9600 bit/s - - break; - case 6: - p[0] = 73; // 14400 bit/s - - break; - case 7: - p[0] = 75; // 19200 bit/s - - break; - } - return p + 3; -} - -static u_char -EncodeSyncParams(u_char si2, u_char ai) -{ - - switch (si2) { - case 0: - return ai + 2; // 1200 bit/s - - case 1: - return ai + 24; // 1200/75 bit/s - - case 2: - return ai + 23; // 75/1200 bit/s - - case 3: - return ai + 3; // 2400 bit/s - - case 4: - return ai + 5; // 4800 bit/s - - case 5: - return ai + 8; // 9600 bit/s - - case 6: - return ai + 9; // 14400 bit/s - - case 7: - return ai + 11; // 19200 bit/s - - case 8: - return ai + 14; // 48000 bit/s - - case 9: - return ai + 15; // 56000 bit/s - - case 15: - return ai + 40; // negotiate bit/s - - default: - break; - } - return ai; -} - - -static u_char -DecodeASyncParams(u_char si2, u_char *p) -{ - u_char info; - - switch (p[5]) { - case 66: // 1200 bit/s - - break; // si2 don't change - - case 88: // 1200/75 bit/s - - si2 += 1; - break; - case 87: // 75/1200 bit/s - - si2 += 2; - break; - case 67: // 2400 bit/s - - si2 += 3; - break; - case 69: // 4800 bit/s - - si2 += 4; - break; - case 72: // 9600 bit/s - - si2 += 5; - break; - case 73: // 14400 bit/s - - si2 += 6; - break; - case 75: // 19200 bit/s - - si2 += 7; - break; - } - - info = p[7] & 0x7f; - if ((info & 16) && (!(info & 8))) // 7 data bits - - si2 += 32; // else 8 data bits - - if ((info & 96) == 96) // 2 stop bits - - si2 += 16; // else 1 stop bit - - if ((info & 2) && (!(info & 1))) // even parity - - si2 += 8; // else no parity - - return si2; -} - - -static u_char -DecodeSyncParams(u_char si2, u_char info) -{ - info &= 0x7f; - switch (info) { - case 40: // bit/s negotiation failed ai := 165 not 175! - - return si2 + 15; - case 15: // 56000 bit/s failed, ai := 0 not 169 ! - - return si2 + 9; - case 14: // 48000 bit/s - - return si2 + 8; - case 11: // 19200 bit/s - - return si2 + 7; - case 9: // 14400 bit/s - - return si2 + 6; - case 8: // 9600 bit/s - - return si2 + 5; - case 5: // 4800 bit/s - - return si2 + 4; - case 3: // 2400 bit/s - - return si2 + 3; - case 23: // 75/1200 bit/s - - return si2 + 2; - case 24: // 1200/75 bit/s - - return si2 + 1; - default: // 1200 bit/s - - return si2; - } -} - -static u_char -DecodeSI2(struct sk_buff *skb) -{ - u_char *p; //, *pend=skb->data + skb->len; - - if ((p = findie(skb->data, skb->len, 0x7c, 0))) { - switch (p[4] & 0x0f) { - case 0x01: - if (p[1] == 0x04) // sync. Bitratenadaption - - return DecodeSyncParams(160, p[5]); // V.110/X.30 - - else if (p[1] == 0x06) // async. Bitratenadaption - - return DecodeASyncParams(192, p); // V.110/X.30 - - break; - case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption - if (p[1] > 3) - return DecodeSyncParams(176, p[5]); // V.120 - break; - } - } - return 0; -} - -#endif - - -static void -l3dss1_setup_req(struct l3_process *pc, u_char pr, - void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char channel = 0; - - u_char send_keypad; - u_char screen = 0x80; - u_char *teln; - u_char *msn; - u_char *sub; - u_char *sp; - int l; - - MsgHead(p, pc->callref, MT_SETUP); - - teln = pc->para.setup.phone; -#ifndef CONFIG_HISAX_NO_KEYPAD - send_keypad = (strchr(teln, '*') || strchr(teln, '#')) ? 1 : 0; -#else - send_keypad = 0; -#endif -#ifndef CONFIG_HISAX_NO_SENDCOMPLETE - if (!send_keypad) - *p++ = 0xa1; /* complete indicator */ -#endif - /* - * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 - */ - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_BEARER; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_BEARER; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - - if (send_keypad) { - *p++ = IE_KEYPAD; - *p++ = strlen(teln); - while (*teln) - *p++ = (*teln++) & 0x7F; - } - - /* - * What about info2? Mapping to High-Layer-Compatibility? - */ - if ((*teln) && (!send_keypad)) { - /* parse number for special things */ - if (!isdigit(*teln)) { - switch (0x5f & *teln) { - case 'C': - channel = 0x08; - /* fall through */ - case 'P': - channel |= 0x80; - teln++; - if (*teln == '1') - channel |= 0x01; - else - channel |= 0x02; - break; - case 'R': - screen = 0xA0; - break; - case 'D': - screen = 0x80; - break; - - default: - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "Wrong MSN Code"); - break; - } - teln++; - } - } - if (channel) { - *p++ = IE_CHANNEL_ID; - *p++ = 1; - *p++ = channel; - } - msn = pc->para.setup.eazmsn; - sub = NULL; - sp = msn; - while (*sp) { - if ('.' == *sp) { - sub = sp; - *sp = 0; - } else - sp++; - } - if (*msn) { - *p++ = IE_CALLING_PN; - *p++ = strlen(msn) + (screen ? 2 : 1); - /* Classify as AnyPref. */ - if (screen) { - *p++ = 0x01; /* Ext = '0'B, Type = '000'B, Plan = '0001'B. */ - *p++ = screen; - } else - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*msn) - *p++ = *msn++ & 0x7f; - } - if (sub) { - *sub++ = '.'; - *p++ = IE_CALLING_SUB; - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } - sub = NULL; - sp = teln; - while (*sp) { - if ('.' == *sp) { - sub = sp; - *sp = 0; - } else - sp++; - } - - if (!send_keypad) { - *p++ = IE_CALLED_PN; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - if (sub) { - *sub++ = '.'; - *p++ = IE_CALLED_SUB; - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } - } -#ifdef EXT_BEARER_CAPS - if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x04; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); - } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 - - *p++ = IE_LLC; - *p++ = 0x05; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x28; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); - *p++ = 0x82; - } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x06; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - p = EncodeASyncParams(p, pc->para.setup.si2 - 192); -#ifndef CONFIG_HISAX_NO_LLC - } else { - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_LLC; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_LLC; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } -#endif - } -#endif - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T303, CC_T303); - newl3state(pc, 1); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 3); - L3AddTimer(&pc->timer, T310, CC_T310); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); -} - -static void -l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 2); - L3AddTimer(&pc->timer, T304, CC_T304); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); -} - -static void -l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret; - u_char cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "DISC get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3dss1_parse_facility(pc->st, pc, pc->callref, p); - ret = check_infoelements(pc, skb, ie_DISCONNECT); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) - cause = 99; - ret = pc->state; - newl3state(pc, 12); - if (cause) - newl3state(pc, 19); - if (11 != ret) - pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); - else if (!cause) - l3dss1_release_req(pc, pr, NULL); - if (cause) { - l3dss1_message_cause(pc, MT_RELEASE, cause); - L3AddTimer(&pc->timer, T308, CC_T308_1); - } -} - -static void -l3dss1_connect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T310 */ - newl3state(pc, 10); - pc->para.chargeinfo = 0; - /* here should inserted COLP handling KKe */ - if (ret) - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); -} - -static void -l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_ALERTING); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T304 */ - newl3state(pc, 4); - if (ret) - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); -} - -static void -l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int bcfound = 0; - char tmp[80]; - struct sk_buff *skb = arg; - int id; - int err = 0; - - /* - * Bearer Capabilities - */ - p = skb->data; - /* only the first occurrence 'll be detected ! */ - if ((p = findie(p, skb->len, 0x04, 0))) { - if ((p[1] < 2) || (p[1] > 11)) - err = 1; - else { - pc->para.setup.si2 = 0; - switch (p[2] & 0x7f) { - case 0x00: /* Speech */ - case 0x10: /* 3.1 Khz audio */ - pc->para.setup.si1 = 1; - break; - case 0x08: /* Unrestricted digital information */ - pc->para.setup.si1 = 7; -/* JIM, 05.11.97 I wanna set service indicator 2 */ -#ifdef EXT_BEARER_CAPS - pc->para.setup.si2 = DecodeSI2(skb); -#endif - break; - case 0x09: /* Restricted digital information */ - pc->para.setup.si1 = 2; - break; - case 0x11: - /* Unrestr. digital information with - * tones/announcements ( or 7 kHz audio - */ - pc->para.setup.si1 = 3; - break; - case 0x18: /* Video */ - pc->para.setup.si1 = 4; - break; - default: - err = 2; - break; - } - switch (p[3] & 0x7f) { - case 0x40: /* packed mode */ - pc->para.setup.si1 = 8; - break; - case 0x10: /* 64 kbit */ - case 0x11: /* 2*64 kbit */ - case 0x13: /* 384 kbit */ - case 0x15: /* 1536 kbit */ - case 0x17: /* 1920 kbit */ - pc->para.moderate = p[3] & 0x7f; - break; - default: - err = 3; - break; - } - } - if (pc->debug & L3_DEB_SI) - l3_debug(pc->st, "SI=%d, AI=%d", - pc->para.setup.si1, pc->para.setup.si2); - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", - p[1], p[2], p[3]); - pc->para.cause = 100; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bearer capabilities"); - /* ETS 300-104 1.3.3 */ - pc->para.cause = 96; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - /* - * Channel Identification - */ - if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { - if ((pc->para.bchannel = id)) { - if ((3 == id) && (0x10 == pc->para.moderate)) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid %x", - id); - pc->para.cause = 100; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - bcfound++; - } else - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel, call waiting"); - bcfound++; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid ret %d", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_SETUP); - if (ERR_IE_COMPREHENSION == err) { - pc->para.cause = 96; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) - iecpy(pc->para.setup.eazmsn, p, 1); - else - pc->para.setup.eazmsn[0] = 0; - - p = skb->data; - if ((p = findie(p, skb->len, 0x71, 0))) { - /* Called party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.eazmsn, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong called subaddress"); - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6c, 0))) { - pc->para.setup.plan = p[2]; - if (p[2] & 0x80) { - iecpy(pc->para.setup.phone, p, 1); - pc->para.setup.screen = 0; - } else { - iecpy(pc->para.setup.phone, p, 2); - pc->para.setup.screen = p[3]; - } - } else { - pc->para.setup.phone[0] = 0; - pc->para.setup.plan = 0; - pc->para.setup.screen = 0; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6d, 0))) { - /* Calling party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.phone, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong calling subaddress"); - } - newl3state(pc, 6); - if (err) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, err); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); -} - -static void -l3dss1_reset(struct l3_process *pc, u_char pr, void *arg) -{ - dss1_release_l3_process(pc); -} - -static void -l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - u_char cause = 16; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - StopAllL3Timer(pc); - - MsgHead(p, pc->callref, MT_DISCONNECT); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - if (pc->prot.dss1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.dss1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.dss1.uus1_data); - p += strlen(pc->prot.dss1.uus1_data); - pc->prot.dss1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 11); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T305, CC_T305); -} - -static void -l3dss1_setup_rsp(struct l3_process *pc, u_char pr, - void *arg) -{ - if (!pc->para.bchannel) - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "D-chan connect for waiting call"); - l3dss1_disconnect_req(pc, pr, arg); - return; - } - newl3state(pc, 8); - l3dss1_message(pc, MT_CONNECT); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - newl3state(pc, 10); - L3DelTimer(&pc->timer); - if (ret) - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); -} - -static void -l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 21; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); -} - -static void -l3dss1_release(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret, cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3dss1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "REL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3dss1_parse_facility(pc->st, pc, pc->callref, p); - } - if ((ret < 0) && (pc->state != 11)) - cause = 96; - else if (ret > 0) - cause = 100; - ret = check_infoelements(pc, skb, ie_RELEASE); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) - cause = 99; - if (cause) - l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause); - else - l3dss1_message(pc, MT_RELEASE_COMPLETE); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); -} - -static void -l3dss1_alert_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 7); - if (!pc->prot.dss1.uus1_data[0]) - l3dss1_message(pc, MT_ALERTING); - else - l3dss1_msg_with_uus(pc, MT_ALERTING); -} - -static void -l3dss1_proceed_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 9); - l3dss1_message(pc, MT_CALL_PROCEEDING); - pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); -} - -static void -l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 25); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T302, CC_T302); - l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE); -} - -/********************************************/ -/* deliver a incoming display message to HL */ -/********************************************/ -static void -l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp) -{ u_char len; - isdn_ctrl ic; - struct IsdnCardState *cs; - char *p; - - if (*infp++ != IE_DISPLAY) return; - if ((len = *infp++) > 80) return; /* total length <= 82 */ - if (!pc->chan) return; - - p = ic.parm.display; - while (len--) - *p++ = *infp++; - *p = '\0'; - ic.command = ISDN_STAT_DISPLAY; - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.arg = pc->chan->chan; - cs->iif.statcallb(&ic); -} /* l3dss1_deliver_display */ - - -static void -l3dss1_progress(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { - if (p[1] != 2) { - err = 1; - pc->para.cause = 100; - } else if (!(p[2] & 0x70)) { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - case 0x84: - case 0x85: - case 0x87: - case 0x8a: - switch (p[3]) { - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x88: - break; - default: - err = 2; - pc->para.cause = 100; - break; - } - break; - default: - err = 3; - pc->para.cause = 100; - break; - } - } - } else { - pc->para.cause = 96; - err = 4; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "progress error %d", err); - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_PROGRESS); - if (err) - l3dss1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); -} - -static void -l3dss1_notify(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { - if (p[1] != 1) { - err = 1; - pc->para.cause = 100; - } else { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - break; - default: - pc->para.cause = 100; - err = 2; - break; - } - } - } else { - pc->para.cause = 96; - err = 3; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "notify error %d", err); - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_NOTIFY); - if (err) - l3dss1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); -} - -static void -l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - - ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); - l3dss1_std_ie_err(pc, ret); - pc->para.cause = 30; /* response to STATUS_ENQUIRY */ - l3dss1_status_send(pc, pr, NULL); -} - -static void -l3dss1_information(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - u_char *p; - char tmp[32]; - - ret = check_infoelements(pc, skb, ie_INFORMATION); - if (ret) - l3dss1_std_ie_err(pc, ret); - if (pc->state == 25) { /* overlap receiving */ - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) { - iecpy(tmp, p, 1); - strcat(pc->para.setup.eazmsn, tmp); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); - } - L3AddTimer(&pc->timer, T302, CC_T302); - } -} - -/******************************/ -/* handle deflection requests */ -/******************************/ -static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char *subp; - u_char len_phone = 0; - u_char len_sub = 0; - int l; - - - strcpy(pc->prot.dss1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */ - if (!pc->chan->setup.phone[0]) - { pc->para.cause = -1; - l3dss1_disconnect_req(pc, pr, arg); /* disconnect immediately */ - return; - } /* only uus */ - - if (pc->prot.dss1.invoke_id) - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - - if (!(pc->prot.dss1.invoke_id = new_invoke_id(pc->st))) - return; - - MsgHead(p, pc->callref, MT_FACILITY); - - for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ - if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ - - *p++ = 0x1c; /* Facility info element */ - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ - *p++ = 0x91; /* remote operations protocol */ - *p++ = 0xa1; /* invoke component */ - - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ - *p++ = 0x02; /* invoke id tag, integer */ - *p++ = 0x01; /* length */ - *p++ = pc->prot.dss1.invoke_id; /* invoke id */ - *p++ = 0x02; /* operation value tag, integer */ - *p++ = 0x01; /* length */ - *p++ = 0x0D; /* Call Deflect */ - - *p++ = 0x30; /* sequence phone number */ - *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ - - *p++ = 0x30; /* Deflected to UserNumber */ - *p++ = len_phone + 2 + len_sub; /* length */ - *p++ = 0x80; /* NumberDigits */ - *p++ = len_phone; /* length */ - for (l = 0; l < len_phone; l++) - *p++ = pc->chan->setup.phone[l]; - - if (len_sub) - { *p++ = 0x04; /* called party subaddress */ - *p++ = len_sub - 2; - while (*subp) *p++ = *subp++; - } - - *p++ = 0x01; /* screening identifier */ - *p++ = 0x01; - *p++ = pc->chan->setup.screen; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) return; - skb_put_data(skb, tmp, l); - - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3dss1_redir_req */ - -/********************************************/ -/* handle deflection request in early state */ -/********************************************/ -static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) -{ - l3dss1_proceed_req(pc, pr, arg); - l3dss1_redir_req(pc, pr, arg); -} /* l3dss1_redir_req_early */ - -/***********************************************/ -/* handle special commands for this protocol. */ -/* Examples are call independent services like */ -/* remote operations with dummy callref. */ -/***********************************************/ -static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic) -{ u_char id; - u_char temp[265]; - u_char *p = temp; - int i, l, proc_len; - struct sk_buff *skb; - struct l3_process *pc = NULL; - - switch (ic->arg) - { case DSS1_CMD_INVOKE: - if (ic->parm.dss1_io.datalen < 0) return (-2); /* invalid parameter */ - - for (proc_len = 1, i = ic->parm.dss1_io.proc >> 8; i; i++) - i = i >> 8; /* add one byte */ - l = ic->parm.dss1_io.datalen + proc_len + 8; /* length excluding ie header */ - if (l > 255) - return (-2); /* too long */ - - if (!(id = new_invoke_id(st))) - return (0); /* first get a invoke id -> return if no available */ - - i = -1; - MsgHead(p, i, MT_FACILITY); /* build message head */ - *p++ = 0x1C; /* Facility IE */ - *p++ = l; /* length of ie */ - *p++ = 0x91; /* remote operations */ - *p++ = 0xA1; /* invoke */ - *p++ = l - 3; /* length of invoke */ - *p++ = 0x02; /* invoke id tag */ - *p++ = 0x01; /* length is 1 */ - *p++ = id; /* invoke id */ - *p++ = 0x02; /* operation */ - *p++ = proc_len; /* length of operation */ - - for (i = proc_len; i; i--) - *p++ = (ic->parm.dss1_io.proc >> (i - 1)) & 0xFF; - memcpy(p, ic->parm.dss1_io.data, ic->parm.dss1_io.datalen); /* copy data */ - l = (p - temp) + ic->parm.dss1_io.datalen; /* total length */ - - if (ic->parm.dss1_io.timeout > 0) - if (!(pc = dss1_new_l3_process(st, -1))) - { free_invoke_id(st, id); - return (-2); - } - pc->prot.dss1.ll_id = ic->parm.dss1_io.ll_id; /* remember id */ - pc->prot.dss1.proc = ic->parm.dss1_io.proc; /* and procedure */ - - if (!(skb = l3_alloc_skb(l))) - { free_invoke_id(st, id); - if (pc) dss1_release_l3_process(pc); - return (-2); - } - skb_put_data(skb, temp, l); - - if (pc) - { pc->prot.dss1.invoke_id = id; /* remember id */ - L3AddTimer(&pc->timer, ic->parm.dss1_io.timeout, CC_TDSS1_IO | REQUEST); - } - - l3_msg(st, DL_DATA | REQUEST, skb); - ic->parm.dss1_io.hl_id = id; /* return id */ - return (0); - - case DSS1_CMD_INVOKE_ABORT: - if ((pc = l3dss1_search_dummy_proc(st, ic->parm.dss1_io.hl_id))) - { L3DelTimer(&pc->timer); /* remove timer */ - dss1_release_l3_process(pc); - return (0); - } - else - { l3_debug(st, "l3dss1_cmd_global abort unknown id"); - return (-2); - } - break; - - default: - l3_debug(st, "l3dss1_cmd_global unknown cmd 0x%lx", ic->arg); - return (-1); - } /* switch ic-> arg */ - return (-1); -} /* l3dss1_cmd_global */ - -static void -l3dss1_io_timer(struct l3_process *pc) -{ isdn_ctrl ic; - struct IsdnCardState *cs = pc->st->l1.hardware; - - L3DelTimer(&pc->timer); /* remove timer */ - - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_ERR; - ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; - ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; - ic.parm.dss1_io.proc = pc->prot.dss1.proc; - ic.parm.dss1_io.timeout = -1; - ic.parm.dss1_io.datalen = 0; - ic.parm.dss1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - pc->prot.dss1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - - dss1_release_l3_process(pc); -} /* l3dss1_io_timer */ - -static void -l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int callState = 0; - p = skb->data; - - if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) - callState = *p; - } - if (callState == 0) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 - * set down layer 3 without sending any message - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); - } else { - pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); - } -} - -static void -l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg) -{ -} - -static void -l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 28; /* invalid number */ - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->N303 > 0) { - pc->N303--; - L3DelTimer(&pc->timer); - l3dss1_setup_req(pc, pr, arg); - } else { - L3DelTimer(&pc->timer); - l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102); - pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); - dss1_release_l3_process(pc); - } -} - -static void -l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); - -} - -static void -l3dss1_t305(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - u_char cause = 16; - - L3DelTimer(&pc->timer); - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 19); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); -} - -static void -l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 19); - L3DelTimer(&pc->timer); - l3dss1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_2); -} - -static void -l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); - dss1_release_l3_process(pc); -} - -static void -l3dss1_t318(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 19); - l3dss1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3dss1_t319(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); -} - -static void -l3dss1_restart(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - dss1_release_l3_process(pc); -} - -static void -l3dss1_status(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int ret; - u_char cause = 0, callState = 0; - - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) { - callState = *p; - if (!ie_in_set(pc, *p, l3_valid_states)) - cause = 100; - } else - cause = 100; - } else - cause = 96; - if (!cause) { /* no error before */ - ret = check_infoelements(pc, skb, ie_STATUS); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if (ERR_IE_UNRECOGNIZED == ret) - cause = 99; - } - if (cause) { - u_char tmp; - - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause); - tmp = pc->para.cause; - pc->para.cause = cause; - l3dss1_status_send(pc, 0, NULL); - if (cause == 99) - pc->para.cause = tmp; - else - return; - } - cause = pc->para.cause; - if (((cause & 0x7f) == 111) && (callState == 0)) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... - * if received MT_STATUS with cause == 111 and call - * state == 0, then we must set down layer 3 - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); - } -} - -static void -l3dss1_facility(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_FACILITY); - l3dss1_std_ie_err(pc, ret); - { - u_char *p; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3dss1_parse_facility(pc->st, pc, pc->callref, p); - } -} - -static void -l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->chan->setup.phone; - - MsgHead(p, pc->callref, MT_SUSPEND); - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 15); - L3AddTimer(&pc->timer, T319, CC_T319); -} - -static void -l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - L3DelTimer(&pc->timer); - newl3state(pc, 0); - pc->para.cause = NO_CAUSE; - pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); - /* We don't handle suspend_ack for IE errors now */ - if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSPACK check ie(%d)", ret); - dss1_release_l3_process(pc); -} - -static void -l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); -} - -static void -l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->para.setup.phone; - - MsgHead(p, pc->callref, MT_RESUME); - - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "RES wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 17); - L3AddTimer(&pc->timer, T318, CC_T318); -} - -static void -l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3dss1_get_channel_id(pc, skb)) > 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack with wrong chid %x", id); - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack without chid (ret %d)", id); - pc->para.cause = 96; - l3dss1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); -} - -static void -l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 0); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); - dss1_release_l3_process(pc); -} - -static void -l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[32]; - u_char *p; - u_char ri, ch = 0, chan = 0; - int l; - struct sk_buff *skb = arg; - struct l3_process *up; - - newl3state(pc, 2); - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { - ri = p[2]; - l3_debug(pc->st, "Restart %x", ri); - } else { - l3_debug(pc->st, "Restart without restart IE"); - ri = 0x86; - } - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - chan = p[2] & 3; - ch = p[2]; - if (pc->st->l3.debug) - l3_debug(pc->st, "Restart for channel %d", chan); - } - newl3state(pc, 2); - up = pc->st->l3.proc; - while (up) { - if ((ri & 7) == 7) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - else if (up->para.bchannel == chan) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - up = up->next; - } - p = tmp; - MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); - if (chan) { - *p++ = IE_CHANNEL_ID; - *p++ = 1; - *p++ = ch | 0x80; - } - *p++ = 0x79; /* RESTART Ind */ - *p++ = 1; - *p++ = ri; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 0); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg) -{ - pc->para.cause = 0x29; /* Temporary failure */ - pc->para.loc = 0; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 0); - pc->para.cause = 0x1b; /* Destination out of order */ - pc->para.loc = 0; - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -static void -l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T309, CC_T309); - l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - - pc->para.cause = 0x1F; /* normal, unspecified */ - l3dss1_status_send(pc, 0, NULL); -} - -/* *INDENT-OFF* */ -static struct stateentry downstatelist[] = -{ - {SBIT(0), - CC_SETUP | REQUEST, l3dss1_setup_req}, - {SBIT(0), - CC_RESUME | REQUEST, l3dss1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), - CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, - {SBIT(12), - CC_RELEASE | REQUEST, l3dss1_release_req}, - {ALL_STATES, - CC_RESTART | REQUEST, l3dss1_restart}, - {SBIT(6) | SBIT(25), - CC_IGNORE | REQUEST, l3dss1_reset}, - {SBIT(6) | SBIT(25), - CC_REJECT | REQUEST, l3dss1_reject_req}, - {SBIT(6) | SBIT(25), - CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(6), - CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req}, - {SBIT(25), - CC_MORE_INFO | REQUEST, l3dss1_dummy}, - {SBIT(6) | SBIT(9) | SBIT(25), - CC_ALERTING | REQUEST, l3dss1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), - CC_SETUP | RESPONSE, l3dss1_setup_rsp}, - {SBIT(10), - CC_SUSPEND | REQUEST, l3dss1_suspend_req}, - {SBIT(7) | SBIT(9) | SBIT(25), - CC_REDIR | REQUEST, l3dss1_redir_req}, - {SBIT(6), - CC_REDIR | REQUEST, l3dss1_redir_req_early}, - {SBIT(9) | SBIT(25), - CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, - {SBIT(25), - CC_T302, l3dss1_t302}, - {SBIT(1), - CC_T303, l3dss1_t303}, - {SBIT(2), - CC_T304, l3dss1_t304}, - {SBIT(3), - CC_T310, l3dss1_t310}, - {SBIT(8), - CC_T313, l3dss1_t313}, - {SBIT(11), - CC_T305, l3dss1_t305}, - {SBIT(15), - CC_T319, l3dss1_t319}, - {SBIT(17), - CC_T318, l3dss1_t318}, - {SBIT(19), - CC_T308_1, l3dss1_t308_1}, - {SBIT(19), - CC_T308_2, l3dss1_t308_2}, - {SBIT(10), - CC_T309, l3dss1_dl_release}, -}; - -static struct stateentry datastatelist[] = -{ - {ALL_STATES, - MT_STATUS_ENQUIRY, l3dss1_status_enq}, - {ALL_STATES, - MT_FACILITY, l3dss1_facility}, - {SBIT(19), - MT_STATUS, l3dss1_release_ind}, - {ALL_STATES, - MT_STATUS, l3dss1_status}, - {SBIT(0), - MT_SETUP, l3dss1_setup}, - {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | - SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_SETUP, l3dss1_dummy}, - {SBIT(1) | SBIT(2), - MT_CALL_PROCEEDING, l3dss1_call_proc}, - {SBIT(1), - MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack}, - {SBIT(2) | SBIT(3), - MT_ALERTING, l3dss1_alerting}, - {SBIT(2) | SBIT(3), - MT_PROGRESS, l3dss1_progress}, - {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_INFORMATION, l3dss1_information}, - {SBIT(10) | SBIT(11) | SBIT(15), - MT_NOTIFY, l3dss1_notify}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_RELEASE_COMPLETE, l3dss1_release_cmpl}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), - MT_RELEASE, l3dss1_release}, - {SBIT(19), MT_RELEASE, l3dss1_release_ind}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), - MT_DISCONNECT, l3dss1_disconnect}, - {SBIT(19), - MT_DISCONNECT, l3dss1_dummy}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), - MT_CONNECT, l3dss1_connect}, - {SBIT(8), - MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack}, - {SBIT(15), - MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack}, - {SBIT(15), - MT_SUSPEND_REJECT, l3dss1_suspend_rej}, - {SBIT(17), - MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack}, - {SBIT(17), - MT_RESUME_REJECT, l3dss1_resume_rej}, -}; - -static struct stateentry globalmes_list[] = -{ - {ALL_STATES, - MT_STATUS, l3dss1_status}, - {SBIT(0), - MT_RESTART, l3dss1_global_restart}, -/* {SBIT(1), - MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, -*/ -}; - -static struct stateentry manstatelist[] = -{ - {SBIT(2), - DL_ESTABLISH | INDICATION, l3dss1_dl_reset}, - {SBIT(10), - DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status}, - {SBIT(10), - DL_RELEASE | INDICATION, l3dss1_dl_reestablish}, - {ALL_STATES, - DL_RELEASE | INDICATION, l3dss1_dl_release}, -}; - -/* *INDENT-ON* */ - - -static void -global_handler(struct PStack *st, int mt, struct sk_buff *skb) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - int i; - struct l3_process *proc = st->l3.global; - - proc->callref = skb->data[2]; /* cr flag */ - for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) - if ((mt == globalmes_list[i].primitive) && - ((1 << proc->state) & globalmes_list[i].state)) - break; - if (i == ARRAY_SIZE(globalmes_list)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1 global state %d mt %x unhandled", - proc->state, mt); - } - MsgHead(p, proc->callref, MT_STATUS); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 81 | 0x80; /* invalid cr */ - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = proc->state & 0x3f; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(proc->st, DL_DATA | REQUEST, skb); - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1 global %d mt %x", - proc->state, mt); - } - globalmes_list[i].rout(proc, mt, skb); - } -} - -static void -dss1up(struct PStack *st, int pr, void *arg) -{ - int i, mt, cr, callState; - char *ptr; - u_char *p; - struct sk_buff *skb = arg; - struct l3_process *proc; - - switch (pr) { - case (DL_DATA | INDICATION): - case (DL_UNIT_DATA | INDICATION): - break; - case (DL_ESTABLISH | CONFIRM): - case (DL_ESTABLISH | INDICATION): - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - l3_msg(st, pr, arg); - return; - break; - default: - printk(KERN_ERR "HiSax dss1up unknown pr=%04x\n", pr); - return; - } - if (skb->len < 3) { - l3_debug(st, "dss1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - - if (skb->data[0] != PROTO_DIS_EURO) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "dss1up%sunexpected discriminator %x message len %d", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - skb->data[0], skb->len); - } - dev_kfree_skb(skb); - return; - } - cr = getcallref(skb->data); - if (skb->len < ((skb->data[1] & 0x0f) + 3)) { - l3_debug(st, "dss1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - mt = skb->data[skb->data[1] + 2]; - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "dss1up cr %d", cr); - if (cr == -2) { /* wrong Callref */ - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "dss1up wrong Callref"); - dev_kfree_skb(skb); - return; - } else if (cr == -1) { /* Dummy Callref */ - if (mt == MT_FACILITY) - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3dss1_parse_facility(st, NULL, - (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); - dev_kfree_skb(skb); - return; - } - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "dss1up dummy Callref (no facility msg or ie)"); - dev_kfree_skb(skb); - return; - } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) || - (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "dss1up Global CallRef"); - global_handler(st, mt, skb); - dev_kfree_skb(skb); - return; - } else if (!(proc = getl3proc(st, cr))) { - /* No transaction process exist, that means no call with - * this callreference is active - */ - if (mt == MT_SETUP) { - /* Setup creates a new transaction process */ - if (skb->data[2] & 0x80) { - /* Setup with wrong CREF flag */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "dss1up wrong CRef flag"); - dev_kfree_skb(skb); - return; - } - if (!(proc = dss1_new_l3_process(st, cr))) { - /* May be to answer with RELEASE_COMPLETE and - * CAUSE 0x2f "Resource unavailable", but this - * need a new_l3_process too ... arghh - */ - dev_kfree_skb(skb); - return; - } - } else if (mt == MT_STATUS) { - if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - } - callState = 0; - if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - callState = *ptr; - } - /* ETS 300-104 part 2.4.1 - * if setup has not been made and a message type - * MT_STATUS is received with call state == 0, - * we must send nothing - */ - if (callState != 0) { - /* ETS 300-104 part 2.4.2 - * if setup has not been made and a message type - * MT_STATUS is received with call state != 0, - * we must send MT_RELEASE_COMPLETE cause 101 - */ - if ((proc = dss1_new_l3_process(st, cr))) { - proc->para.cause = 101; - l3dss1_msg_without_setup(proc, 0, NULL); - } - } - dev_kfree_skb(skb); - return; - } else if (mt == MT_RELEASE_COMPLETE) { - dev_kfree_skb(skb); - return; - } else { - /* ETS 300-104 part 2 - * if setup has not been made and a message type - * (except MT_SETUP and RELEASE_COMPLETE) is received, - * we must send MT_RELEASE_COMPLETE cause 81 */ - dev_kfree_skb(skb); - if ((proc = dss1_new_l3_process(st, cr))) { - proc->para.cause = 81; - l3dss1_msg_without_setup(proc, 0, NULL); - } - return; - } - } - if (l3dss1_check_messagetype_validity(proc, mt, skb)) { - dev_kfree_skb(skb); - return; - } - if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) - l3dss1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < ARRAY_SIZE(datastatelist); i++) - if ((mt == datastatelist[i].primitive) && - ((1 << proc->state) & datastatelist[i].state)) - break; - if (i == ARRAY_SIZE(datastatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1up%sstate %d mt %#x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { - proc->para.cause = 101; - l3dss1_status_send(proc, pr, skb); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1up%sstate %d mt %x", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - datastatelist[i].rout(proc, pr, skb); - } - dev_kfree_skb(skb); - return; -} - -static void -dss1down(struct PStack *st, int pr, void *arg) -{ - int i, cr; - struct l3_process *proc; - struct Channel *chan; - - if ((DL_ESTABLISH | REQUEST) == pr) { - l3_msg(st, pr, NULL); - return; - } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { - chan = arg; - cr = newcallref(); - cr |= 0x80; - if ((proc = dss1_new_l3_process(st, cr))) { - proc->chan = chan; - chan->proc = proc; - memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); - proc->callref = cr; - } - } else { - proc = arg; - } - if (!proc) { - printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr); - return; - } - - if (pr == (CC_TDSS1_IO | REQUEST)) { - l3dss1_io_timer(proc); /* timer expires */ - return; - } - - for (i = 0; i < ARRAY_SIZE(downstatelist); i++) - if ((pr == downstatelist[i].primitive) && - ((1 << proc->state) & downstatelist[i].state)) - break; - if (i == ARRAY_SIZE(downstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1down state %d prim %#x unhandled", - proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1down state %d prim %#x", - proc->state, pr); - } - downstatelist[i].rout(proc, pr, arg); - } -} - -static void -dss1man(struct PStack *st, int pr, void *arg) -{ - int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < ARRAY_SIZE(manstatelist); i++) - if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == ARRAY_SIZE(manstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d dss1man state %d prim %#x", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } -} - -void -setstack_dss1(struct PStack *st) -{ - char tmp[64]; - int i; - - st->lli.l4l3 = dss1down; - st->lli.l4l3_proto = l3dss1_cmd_global; - st->l2.l2l3 = dss1up; - st->l3.l3ml3 = dss1man; - st->l3.N303 = 1; - st->prot.dss1.last_invoke_id = 0; - st->prot.dss1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ - i = 1; - while (i < 32) - st->prot.dss1.invoke_used[i++] = 0; - - if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { - printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n"); - } else { - st->l3.global->state = 0; - st->l3.global->callref = 0; - st->l3.global->next = NULL; - st->l3.global->debug = L3_DEB_WARN; - st->l3.global->st = st; - st->l3.global->N303 = 1; - st->l3.global->prot.dss1.invoke_id = 0; - - L3InitTimer(st->l3.global, &st->l3.global->timer); - } - strcpy(tmp, dss1_revision); - printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp)); -} diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h deleted file mode 100644 index a7807e8a94f1..000000000000 --- a/drivers/isdn/hisax/l3dss1.h +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id: l3dss1.h,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $ - * - * DSS1 (Euro) D-channel protocol defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef l3dss1_process - -#define T302 15000 -#define T303 4000 -#define T304 30000 -#define T305 30000 -#define T308 4000 -/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ -/* This makes some tests easier and quicker */ -#define T309 40000 -#define T310 30000 -#define T313 4000 -#define T318 4000 -#define T319 4000 - -/* - * Message-Types - */ - -#define MT_ALERTING 0x01 -#define MT_CALL_PROCEEDING 0x02 -#define MT_CONNECT 0x07 -#define MT_CONNECT_ACKNOWLEDGE 0x0f -#define MT_PROGRESS 0x03 -#define MT_SETUP 0x05 -#define MT_SETUP_ACKNOWLEDGE 0x0d -#define MT_RESUME 0x26 -#define MT_RESUME_ACKNOWLEDGE 0x2e -#define MT_RESUME_REJECT 0x22 -#define MT_SUSPEND 0x25 -#define MT_SUSPEND_ACKNOWLEDGE 0x2d -#define MT_SUSPEND_REJECT 0x21 -#define MT_USER_INFORMATION 0x20 -#define MT_DISCONNECT 0x45 -#define MT_RELEASE 0x4d -#define MT_RELEASE_COMPLETE 0x5a -#define MT_RESTART 0x46 -#define MT_RESTART_ACKNOWLEDGE 0x4e -#define MT_SEGMENT 0x60 -#define MT_CONGESTION_CONTROL 0x79 -#define MT_INFORMATION 0x7b -#define MT_FACILITY 0x62 -#define MT_NOTIFY 0x6e -#define MT_STATUS 0x7d -#define MT_STATUS_ENQUIRY 0x75 - -#define IE_SEGMENT 0x00 -#define IE_BEARER 0x04 -#define IE_CAUSE 0x08 -#define IE_CALL_ID 0x10 -#define IE_CALL_STATE 0x14 -#define IE_CHANNEL_ID 0x18 -#define IE_FACILITY 0x1c -#define IE_PROGRESS 0x1e -#define IE_NET_FAC 0x20 -#define IE_NOTIFY 0x27 -#define IE_DISPLAY 0x28 -#define IE_DATE 0x29 -#define IE_KEYPAD 0x2c -#define IE_SIGNAL 0x34 -#define IE_INFORATE 0x40 -#define IE_E2E_TDELAY 0x42 -#define IE_TDELAY_SEL 0x43 -#define IE_PACK_BINPARA 0x44 -#define IE_PACK_WINSIZE 0x45 -#define IE_PACK_SIZE 0x46 -#define IE_CUG 0x47 -#define IE_REV_CHARGE 0x4a -#define IE_CONNECT_PN 0x4c -#define IE_CONNECT_SUB 0x4d -#define IE_CALLING_PN 0x6c -#define IE_CALLING_SUB 0x6d -#define IE_CALLED_PN 0x70 -#define IE_CALLED_SUB 0x71 -#define IE_REDIR_NR 0x74 -#define IE_TRANS_SEL 0x78 -#define IE_RESTART_IND 0x79 -#define IE_LLC 0x7c -#define IE_HLC 0x7d -#define IE_USER_USER 0x7e -#define IE_ESCAPE 0x7f -#define IE_SHIFT 0x90 -#define IE_MORE_DATA 0xa0 -#define IE_COMPLETE 0xa1 -#define IE_CONGESTION 0xb0 -#define IE_REPEAT 0xd0 - -#define IE_MANDATORY 0x0100 -/* mandatory not in every case */ -#define IE_MANDATORY_1 0x0200 - -#define ERR_IE_COMPREHENSION 1 -#define ERR_IE_UNRECOGNIZED -1 -#define ERR_IE_LENGTH -2 -#define ERR_IE_SEQUENCE -3 - -#else /* only l3dss1_process */ - -/* l3dss1 specific data in l3 process */ -typedef struct -{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ - ulong ll_id; /* remebered ll id */ - u8 remote_operation; /* handled remote operation, 0 = not active */ - int proc; /* rememered procedure */ - ulong remote_result; /* result of remote operation for statcallb */ - char uus1_data[35]; /* data send during alerting or disconnect */ -} dss1_proc_priv; - -/* l3dss1 specific data in protocol stack */ -typedef struct -{ unsigned char last_invoke_id; /* last used value for invoking */ - unsigned char invoke_used[32]; /* 256 bits for 256 values */ -} dss1_stk_priv; - -#endif /* only l3dss1_process */ diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c deleted file mode 100644 index ea311e7df48e..000000000000 --- a/drivers/isdn/hisax/l3ni1.c +++ /dev/null @@ -1,3182 +0,0 @@ -/* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $ - * - * NI1 D-channel protocol - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 2000.6.6 Initial implementation of routines for US NI1 - * Layer 3 protocol based on the EURO/DSS1 D-channel protocol - * driver written by Karsten Keil et al. - * NI-1 Hall of Fame - Thanks to.... - * Ragnar Paulson - for some handy code fragments - * Will Scales - beta tester extraordinaire - * Brett Whittacre - beta tester and remote devel system in Vegas - * - */ - -#include "hisax.h" -#include "isdnl3.h" -#include "l3ni1.h" -#include -#include - -extern char *HiSax_getrev(const char *revision); -static const char *ni1_revision = "$Revision: 2.8.2.3 $"; - -#define EXT_BEARER_CAPS 1 - -#define MsgHead(ptr, cref, mty) \ - *ptr++ = 0x8; \ - if (cref == -1) { \ - *ptr++ = 0x0; \ - } else { \ - *ptr++ = 0x1; \ - *ptr++ = cref^0x80; \ - } \ - *ptr++ = mty - - -/**********************************************/ -/* get a new invoke id for remote operations. */ -/* Only a return value != 0 is valid */ -/**********************************************/ -static unsigned char new_invoke_id(struct PStack *p) -{ - unsigned char retval; - int i; - - i = 32; /* maximum search depth */ - - retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ - while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { - p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; - i--; - } - if (i) { - while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) - retval++; - } else - retval = 0; - p->prot.ni1.last_invoke_id = retval; - p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); - return (retval); -} /* new_invoke_id */ - -/*************************/ -/* free a used invoke id */ -/*************************/ -static void free_invoke_id(struct PStack *p, unsigned char id) -{ - - if (!id) return; /* 0 = invalid value */ - - p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); -} /* free_invoke_id */ - - -/**********************************************************/ -/* create a new l3 process and fill in ni1 specific data */ -/**********************************************************/ -static struct l3_process -*ni1_new_l3_process(struct PStack *st, int cr) -{ struct l3_process *proc; - - if (!(proc = new_l3_process(st, cr))) - return (NULL); - - proc->prot.ni1.invoke_id = 0; - proc->prot.ni1.remote_operation = 0; - proc->prot.ni1.uus1_data[0] = '\0'; - - return (proc); -} /* ni1_new_l3_process */ - -/************************************************/ -/* free a l3 process and all ni1 specific data */ -/************************************************/ -static void -ni1_release_l3_process(struct l3_process *p) -{ - free_invoke_id(p->st, p->prot.ni1.invoke_id); - release_l3_process(p); -} /* ni1_release_l3_process */ - -/********************************************************/ -/* search a process with invoke id id and dummy callref */ -/********************************************************/ -static struct l3_process * -l3ni1_search_dummy_proc(struct PStack *st, int id) -{ struct l3_process *pc = st->l3.proc; /* start of processes */ - - if (!id) return (NULL); - - while (pc) - { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) - return (pc); - pc = pc->next; - } - return (NULL); -} /* l3ni1_search_dummy_proc */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return result is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3ni1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_RES; - ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; - ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; - ic.parm.ni1_io.proc = pc->prot.ni1.proc; - ic.parm.ni1_io.timeout = 0; - ic.parm.ni1_io.datalen = nlen; - ic.parm.ni1_io.data = p; - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - pc->prot.ni1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - ni1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen); -} /* l3ni1_dummy_return_result */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return error is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3ni1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_ERR; - ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; - ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; - ic.parm.ni1_io.proc = pc->prot.ni1.proc; - ic.parm.ni1_io.timeout = error; - ic.parm.ni1_io.datalen = 0; - ic.parm.ni1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - pc->prot.ni1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - ni1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error); -} /* l3ni1_error_return */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a invoke is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3ni1_dummy_invoke(struct PStack *st, int cr, int id, - int ident, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - - l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", - (cr == -1) ? "local" : "broadcast", id, ident, nlen); - if (cr >= -1) return; /* ignore local data */ - - cs = st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_BRD; - ic.parm.ni1_io.hl_id = id; - ic.parm.ni1_io.ll_id = 0; - ic.parm.ni1_io.proc = ident; - ic.parm.ni1_io.timeout = 0; - ic.parm.ni1_io.datalen = nlen; - ic.parm.ni1_io.data = p; - - cs->iif.statcallb(&ic); -} /* l3ni1_dummy_invoke */ - -static void -l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, - int cr, u_char *p) -{ - int qd_len = 0; - unsigned char nlen = 0, ilen, cp_tag; - int ident, id; - ulong err_ret; - - if (pc) - st = pc->st; /* valid Stack */ - else - if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ - - p++; - qd_len = *p++; - if (qd_len == 0) { - l3_debug(st, "qd_len == 0"); - return; - } - if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ - l3_debug(st, "supplementary service != 0x11"); - return; - } - while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ - p++; - qd_len--; - } - if (qd_len < 2) { - l3_debug(st, "qd_len < 2"); - return; - } - p++; - qd_len--; - if ((*p & 0xE0) != 0xA0) { /* class and form */ - l3_debug(st, "class and form != 0xA0"); - return; - } - - cp_tag = *p & 0x1F; /* remember tag value */ - - p++; - qd_len--; - if (qd_len < 1) - { l3_debug(st, "qd_len < 1"); - return; - } - if (*p & 0x80) - { /* length format indefinite or limited */ - nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ - if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || - (nlen > 1)) - { l3_debug(st, "length format error or not implemented"); - return; - } - if (nlen == 1) - { nlen = *p++; /* complete length */ - qd_len--; - } - else - { qd_len -= 2; /* trailing null bytes */ - if ((*(p + qd_len)) || (*(p + qd_len + 1))) - { l3_debug(st, "length format indefinite error"); - return; - } - nlen = qd_len; - } - } - else - { nlen = *p++; - qd_len--; - } - if (qd_len < nlen) - { l3_debug(st, "qd_len < nlen"); - return; - } - qd_len -= nlen; - - if (nlen < 2) - { l3_debug(st, "nlen < 2"); - return; - } - if (*p != 0x02) - { /* invoke identifier tag */ - l3_debug(st, "invoke identifier tag !=0x02"); - return; - } - p++; - nlen--; - if (*p & 0x80) - { /* length format */ - l3_debug(st, "invoke id length format 2"); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - id = 0; - while (ilen > 0) - { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ - ilen--; - } - - switch (cp_tag) { /* component tag */ - case 1: /* invoke */ - if (nlen < 2) { - l3_debug(st, "nlen < 2 22"); - return; - } - if (*p != 0x02) { /* operation value */ - l3_debug(st, "operation value !=0x02"); - return; - } - p++; - nlen--; - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) { - l3_debug(st, "ilen > nlen || ilen == 0 22"); - return; - } - nlen -= ilen; - ident = 0; - while (ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); - ilen--; - } - - if (!pc) - { - l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); - return; - } - l3_debug(st, "invoke break"); - break; - case 2: /* return result */ - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3ni1_dummy_return_result(st, id, p, nlen); - return; - } - if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) - { /* Diversion successful */ - free_invoke_id(st, pc->prot.ni1.invoke_id); - pc->prot.ni1.remote_result = 0; /* success */ - pc->prot.ni1.invoke_id = 0; - pc->redir_result = pc->prot.ni1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ - else - l3_debug(st, "return error unknown identifier"); - break; - case 3: /* return error */ - err_ret = 0; - if (nlen < 2) - { l3_debug(st, "return error nlen < 2"); - return; - } - if (*p != 0x02) - { /* result tag */ - l3_debug(st, "invoke error tag !=0x02"); - return; - } - p++; - nlen--; - if (*p > 4) - { /* length format */ - l3_debug(st, "invoke return errlen > 4 "); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "error return ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - while (ilen > 0) - { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ - ilen--; - } - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3ni1_dummy_error_return(st, id, err_ret); - return; - } - if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) - { /* Deflection error */ - free_invoke_id(st, pc->prot.ni1.invoke_id); - pc->prot.ni1.remote_result = err_ret; /* result */ - pc->prot.ni1.invoke_id = 0; - pc->redir_result = pc->prot.ni1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); - } /* Deflection error */ - else - l3_debug(st, "return result unknown identifier"); - break; - default: - l3_debug(st, "facility default break tag=0x%02x", cp_tag); - break; - } -} - -static void -l3ni1_message(struct l3_process *pc, u_char mt) -{ - struct sk_buff *skb; - u_char *p; - - if (!(skb = l3_alloc_skb(4))) - return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_message_plus_chid(struct l3_process *pc, u_char mt) -/* sends an l3 messages plus channel id - added GE 05/09/00 */ -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - u_char chid; - - chid = (u_char)(pc->para.bchannel & 0x03) | 0x88; - MsgHead(p, pc->callref, mt); - *p++ = IE_CHANNEL_ID; - *p++ = 0x01; - *p++ = chid; - - if (!(skb = l3_alloc_skb(7))) - return; - skb_put_data(skb, tmp, 7); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, mt); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - MsgHead(p, pc->callref, MT_STATUS); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - - *p++ = IE_CALL_STATE; - *p++ = 0x1; - *p++ = pc->state & 0x3f; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) -{ - /* This routine is called if here was no SETUP made (checks in ni1up and in - * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code - * MT_STATUS_ENQUIRE in the NULL state is handled too - */ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - switch (pc->para.cause) { - case 81: /* invalid callreference */ - case 88: /* incomp destination */ - case 96: /* mandory IE missing */ - case 100: /* invalid IE contents */ - case 101: /* incompatible Callstate */ - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - break; - default: - printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", - pc->para.cause); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - ni1_release_l3_process(pc); -} - -static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, - IE_USER_USER, -1}; -static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; -static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, - IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, - IE_CALLED_PN, -1}; -static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | - IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; -static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, - IE_SIGNAL, IE_USER_USER, -1}; -/* a RELEASE_COMPLETE with errors don't require special actions - static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -*/ -static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_DISPLAY, -1}; -static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, - IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS, - IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, - IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, - IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | - IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; -static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; -static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -/* not used - * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, - * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; - * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; - * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | - * IE_MANDATORY, -1}; - */ -static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; -static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1}; -static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1}; - -struct ie_len { - int ie; - int len; -}; - -static -struct ie_len max_ie_len[] = { - {IE_SEGMENT, 4}, - {IE_BEARER, 12}, - {IE_CAUSE, 32}, - {IE_CALL_ID, 10}, - {IE_CALL_STATE, 3}, - {IE_CHANNEL_ID, 34}, - {IE_FACILITY, 255}, - {IE_PROGRESS, 4}, - {IE_NET_FAC, 255}, - {IE_NOTIFY, 3}, - {IE_DISPLAY, 82}, - {IE_DATE, 8}, - {IE_KEYPAD, 34}, - {IE_SIGNAL, 3}, - {IE_INFORATE, 6}, - {IE_E2E_TDELAY, 11}, - {IE_TDELAY_SEL, 5}, - {IE_PACK_BINPARA, 3}, - {IE_PACK_WINSIZE, 4}, - {IE_PACK_SIZE, 4}, - {IE_CUG, 7}, - {IE_REV_CHARGE, 3}, - {IE_CALLING_PN, 24}, - {IE_CALLING_SUB, 23}, - {IE_CALLED_PN, 24}, - {IE_CALLED_SUB, 23}, - {IE_REDIR_NR, 255}, - {IE_TRANS_SEL, 255}, - {IE_RESTART_IND, 3}, - {IE_LLC, 18}, - {IE_HLC, 5}, - {IE_USER_USER, 131}, - {-1, 0}, -}; - -static int -getmax_ie_len(u_char ie) { - int i = 0; - while (max_ie_len[i].ie != -1) { - if (max_ie_len[i].ie == ie) - return (max_ie_len[i].len); - i++; - } - return (255); -} - -static int -ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { - int ret = 1; - - while (*checklist != -1) { - if ((*checklist & 0xff) == ie) { - if (ie & 0x80) - return (-ret); - else - return (ret); - } - ret++; - checklist++; - } - return (0); -} - -static int -check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) -{ - int *cl = checklist; - u_char mt; - u_char *p, ie; - int l, newpos, oldpos; - int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - u_char codeset = 0; - u_char old_codeset = 0; - u_char codelock = 1; - - p = skb->data; - /* skip cr */ - p++; - l = (*p++) & 0xf; - p += l; - mt = *p++; - oldpos = 0; - while ((p - skb->data) < skb->len) { - if ((*p & 0xf0) == 0x90) { /* shift codeset */ - old_codeset = codeset; - codeset = *p & 7; - if (*p & 0x08) - codelock = 0; - else - codelock = 1; - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift%scodeset %d->%d", - codelock ? " locking " : " ", old_codeset, codeset); - p++; - continue; - } - if (!codeset) { /* only codeset 0 */ - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; - else - oldpos = newpos; - } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; - } - } - ie = *p++; - if (ie & 0x80) { - l = 1; - } else { - l = *p++; - p += l; - l += 2; - } - if (!codeset && (l > getmax_ie_len(ie))) - err_len++; - if (!codelock) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift back codeset %d->%d", - codeset, old_codeset); - codeset = old_codeset; - codelock = 1; - } - } - if (err_compr | err_ureg | err_len | err_seq) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", - mt, err_compr, err_ureg, err_len, err_seq); - if (err_compr) - return (ERR_IE_COMPREHENSION); - if (err_ureg) - return (ERR_IE_UNRECOGNIZED); - if (err_len) - return (ERR_IE_LENGTH); - if (err_seq) - return (ERR_IE_SEQUENCE); - } - return (0); -} - -/* verify if a message type exists and contain no IE error */ -static int -l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) -{ - switch (mt) { - case MT_ALERTING: - case MT_CALL_PROCEEDING: - case MT_CONNECT: - case MT_CONNECT_ACKNOWLEDGE: - case MT_DISCONNECT: - case MT_INFORMATION: - case MT_FACILITY: - case MT_NOTIFY: - case MT_PROGRESS: - case MT_RELEASE: - case MT_RELEASE_COMPLETE: - case MT_SETUP: - case MT_SETUP_ACKNOWLEDGE: - case MT_RESUME_ACKNOWLEDGE: - case MT_RESUME_REJECT: - case MT_SUSPEND_ACKNOWLEDGE: - case MT_SUSPEND_REJECT: - case MT_USER_INFORMATION: - case MT_RESTART: - case MT_RESTART_ACKNOWLEDGE: - case MT_CONGESTION_CONTROL: - case MT_STATUS: - case MT_STATUS_ENQUIRY: - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); - break; - case MT_RESUME: /* RESUME only in user->net */ - case MT_SUSPEND: /* SUSPEND only in user->net */ - default: - if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) - l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); - pc->para.cause = 97; - l3ni1_status_send(pc, 0, NULL); - return (1); - } - return (0); -} - -static void -l3ni1_std_ie_err(struct l3_process *pc, int ret) { - - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements ret %d", ret); - switch (ret) { - case 0: - break; - case ERR_IE_COMPREHENSION: - pc->para.cause = 96; - l3ni1_status_send(pc, 0, NULL); - break; - case ERR_IE_UNRECOGNIZED: - pc->para.cause = 99; - l3ni1_status_send(pc, 0, NULL); - break; - case ERR_IE_LENGTH: - pc->para.cause = 100; - l3ni1_status_send(pc, 0, NULL); - break; - case ERR_IE_SEQUENCE: - default: - break; - } -} - -static int -l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { - u_char *p; - - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - p++; - if (*p != 1) { /* len for BRI = 1 */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid len %d", *p); - return (-2); - } - p++; - if (*p & 0x60) { /* only base rate interface */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid %x", *p); - return (-3); - } - return (*p & 0x3); - } else - return (-1); -} - -static int -l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { - u_char l, i = 0; - u_char *p; - - p = skb->data; - pc->para.cause = 31; - pc->para.loc = 0; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - l = *p++; - if (l > 30) - return (1); - if (l) { - pc->para.loc = *p++; - l--; - } else { - return (2); - } - if (l && !(pc->para.loc & 0x80)) { - l--; - p++; /* skip recommendation */ - } - if (l) { - pc->para.cause = *p++; - l--; - if (!(pc->para.cause & 0x80)) - return (3); - } else - return (4); - while (l && (i < 6)) { - pc->para.diag[i++] = *p++; - l--; - } - } else - return (-1); - return (0); -} - -static void -l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, cmd); - - if (pc->prot.ni1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.ni1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.ni1.uus1_data); - p += strlen(pc->prot.ni1.uus1_data); - pc->prot.ni1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3ni1_msg_with_uus */ - -static void -l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - if (!pc->prot.ni1.uus1_data[0]) - l3ni1_message(pc, MT_RELEASE); - else - l3ni1_msg_with_uus(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3ni1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - StopAllL3Timer(pc); - newl3state(pc, 0); - pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); - ni1_release_l3_process(pc); -} - -#if EXT_BEARER_CAPS - -static u_char * -EncodeASyncParams(u_char *p, u_char si2) -{ // 7c 06 88 90 21 42 00 bb - - p[0] = 0; - p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 - p[2] = 0x80; - if (si2 & 32) // 7 data bits - - p[2] += 16; - else // 8 data bits - - p[2] += 24; - - if (si2 & 16) // 2 stop bits - - p[2] += 96; - else // 1 stop bit - - p[2] += 32; - - if (si2 & 8) // even parity - - p[2] += 2; - else // no parity - - p[2] += 3; - - switch (si2 & 0x07) { - case 0: - p[0] = 66; // 1200 bit/s - - break; - case 1: - p[0] = 88; // 1200/75 bit/s - - break; - case 2: - p[0] = 87; // 75/1200 bit/s - - break; - case 3: - p[0] = 67; // 2400 bit/s - - break; - case 4: - p[0] = 69; // 4800 bit/s - - break; - case 5: - p[0] = 72; // 9600 bit/s - - break; - case 6: - p[0] = 73; // 14400 bit/s - - break; - case 7: - p[0] = 75; // 19200 bit/s - - break; - } - return p + 3; -} - -static u_char -EncodeSyncParams(u_char si2, u_char ai) -{ - - switch (si2) { - case 0: - return ai + 2; // 1200 bit/s - - case 1: - return ai + 24; // 1200/75 bit/s - - case 2: - return ai + 23; // 75/1200 bit/s - - case 3: - return ai + 3; // 2400 bit/s - - case 4: - return ai + 5; // 4800 bit/s - - case 5: - return ai + 8; // 9600 bit/s - - case 6: - return ai + 9; // 14400 bit/s - - case 7: - return ai + 11; // 19200 bit/s - - case 8: - return ai + 14; // 48000 bit/s - - case 9: - return ai + 15; // 56000 bit/s - - case 15: - return ai + 40; // negotiate bit/s - - default: - break; - } - return ai; -} - - -static u_char -DecodeASyncParams(u_char si2, u_char *p) -{ - u_char info; - - switch (p[5]) { - case 66: // 1200 bit/s - - break; // si2 don't change - - case 88: // 1200/75 bit/s - - si2 += 1; - break; - case 87: // 75/1200 bit/s - - si2 += 2; - break; - case 67: // 2400 bit/s - - si2 += 3; - break; - case 69: // 4800 bit/s - - si2 += 4; - break; - case 72: // 9600 bit/s - - si2 += 5; - break; - case 73: // 14400 bit/s - - si2 += 6; - break; - case 75: // 19200 bit/s - - si2 += 7; - break; - } - - info = p[7] & 0x7f; - if ((info & 16) && (!(info & 8))) // 7 data bits - - si2 += 32; // else 8 data bits - - if ((info & 96) == 96) // 2 stop bits - - si2 += 16; // else 1 stop bit - - if ((info & 2) && (!(info & 1))) // even parity - - si2 += 8; // else no parity - - return si2; -} - - -static u_char -DecodeSyncParams(u_char si2, u_char info) -{ - info &= 0x7f; - switch (info) { - case 40: // bit/s negotiation failed ai := 165 not 175! - - return si2 + 15; - case 15: // 56000 bit/s failed, ai := 0 not 169 ! - - return si2 + 9; - case 14: // 48000 bit/s - - return si2 + 8; - case 11: // 19200 bit/s - - return si2 + 7; - case 9: // 14400 bit/s - - return si2 + 6; - case 8: // 9600 bit/s - - return si2 + 5; - case 5: // 4800 bit/s - - return si2 + 4; - case 3: // 2400 bit/s - - return si2 + 3; - case 23: // 75/1200 bit/s - - return si2 + 2; - case 24: // 1200/75 bit/s - - return si2 + 1; - default: // 1200 bit/s - - return si2; - } -} - -static u_char -DecodeSI2(struct sk_buff *skb) -{ - u_char *p; //, *pend=skb->data + skb->len; - - if ((p = findie(skb->data, skb->len, 0x7c, 0))) { - switch (p[4] & 0x0f) { - case 0x01: - if (p[1] == 0x04) // sync. Bitratenadaption - - return DecodeSyncParams(160, p[5]); // V.110/X.30 - - else if (p[1] == 0x06) // async. Bitratenadaption - - return DecodeASyncParams(192, p); // V.110/X.30 - - break; - case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption - if (p[1] > 3) - return DecodeSyncParams(176, p[5]); // V.120 - break; - } - } - return 0; -} - -#endif - - -static void -l3ni1_setup_req(struct l3_process *pc, u_char pr, - void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - - u_char *teln; - u_char *sub; - u_char *sp; - int l; - - MsgHead(p, pc->callref, MT_SETUP); - - teln = pc->para.setup.phone; - - *p++ = 0xa1; /* complete indicator */ - /* - * Set Bearer Capability, Map info from 1TR6-convention to NI1 - */ - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_BEARER; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* 3.1khz Audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa2; /* u-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_BEARER; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - - sub = NULL; - sp = teln; - while (*sp) { - if ('.' == *sp) { - sub = sp; - *sp = 0; - } else - sp++; - } - - *p++ = IE_KEYPAD; - *p++ = strlen(teln); - while (*teln) - *p++ = (*teln++) & 0x7F; - - if (sub) - *sub++ = '.'; - -#if EXT_BEARER_CAPS - if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x04; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); - } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 - - *p++ = IE_LLC; - *p++ = 0x05; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x28; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); - *p++ = 0x82; - } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x06; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - p = EncodeASyncParams(p, pc->para.setup.si2 - 192); - } else { - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_LLC; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa2; /* u-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_LLC; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - } -#endif - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - { - return; - } - skb_put_data(skb, tmp, l); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T303, CC_T303); - newl3state(pc, 1); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 3); - L3AddTimer(&pc->timer, T310, CC_T310); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); -} - -static void -l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 2); - L3AddTimer(&pc->timer, T304, CC_T304); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); -} - -static void -l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret; - u_char cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "DISC get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3ni1_parse_facility(pc->st, pc, pc->callref, p); - ret = check_infoelements(pc, skb, ie_DISCONNECT); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) - cause = 99; - ret = pc->state; - newl3state(pc, 12); - if (cause) - newl3state(pc, 19); - if (11 != ret) - pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); - else if (!cause) - l3ni1_release_req(pc, pr, NULL); - if (cause) { - l3ni1_message_cause(pc, MT_RELEASE, cause); - L3AddTimer(&pc->timer, T308, CC_T308_1); - } -} - -static void -l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T310 */ - newl3state(pc, 10); - pc->para.chargeinfo = 0; - /* here should inserted COLP handling KKe */ - if (ret) - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); -} - -static void -l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_ALERTING); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T304 */ - newl3state(pc, 4); - if (ret) - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); -} - -static void -l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int bcfound = 0; - char tmp[80]; - struct sk_buff *skb = arg; - int id; - int err = 0; - - /* - * Bearer Capabilities - */ - p = skb->data; - /* only the first occurrence 'll be detected ! */ - if ((p = findie(p, skb->len, 0x04, 0))) { - if ((p[1] < 2) || (p[1] > 11)) - err = 1; - else { - pc->para.setup.si2 = 0; - switch (p[2] & 0x7f) { - case 0x00: /* Speech */ - case 0x10: /* 3.1 Khz audio */ - pc->para.setup.si1 = 1; - break; - case 0x08: /* Unrestricted digital information */ - pc->para.setup.si1 = 7; -/* JIM, 05.11.97 I wanna set service indicator 2 */ -#if EXT_BEARER_CAPS - pc->para.setup.si2 = DecodeSI2(skb); -#endif - break; - case 0x09: /* Restricted digital information */ - pc->para.setup.si1 = 2; - break; - case 0x11: - /* Unrestr. digital information with - * tones/announcements ( or 7 kHz audio - */ - pc->para.setup.si1 = 3; - break; - case 0x18: /* Video */ - pc->para.setup.si1 = 4; - break; - default: - err = 2; - break; - } - switch (p[3] & 0x7f) { - case 0x40: /* packed mode */ - pc->para.setup.si1 = 8; - break; - case 0x10: /* 64 kbit */ - case 0x11: /* 2*64 kbit */ - case 0x13: /* 384 kbit */ - case 0x15: /* 1536 kbit */ - case 0x17: /* 1920 kbit */ - pc->para.moderate = p[3] & 0x7f; - break; - default: - err = 3; - break; - } - } - if (pc->debug & L3_DEB_SI) - l3_debug(pc->st, "SI=%d, AI=%d", - pc->para.setup.si1, pc->para.setup.si2); - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", - p[1], p[2], p[3]); - pc->para.cause = 100; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bearer capabilities"); - /* ETS 300-104 1.3.3 */ - pc->para.cause = 96; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - /* - * Channel Identification - */ - if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { - if ((pc->para.bchannel = id)) { - if ((3 == id) && (0x10 == pc->para.moderate)) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid %x", - id); - pc->para.cause = 100; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - bcfound++; - } else - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel, call waiting"); - bcfound++; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid ret %d", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_SETUP); - if (ERR_IE_COMPREHENSION == err) { - pc->para.cause = 96; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) - iecpy(pc->para.setup.eazmsn, p, 1); - else - pc->para.setup.eazmsn[0] = 0; - - p = skb->data; - if ((p = findie(p, skb->len, 0x71, 0))) { - /* Called party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.eazmsn, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong called subaddress"); - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6c, 0))) { - pc->para.setup.plan = p[2]; - if (p[2] & 0x80) { - iecpy(pc->para.setup.phone, p, 1); - pc->para.setup.screen = 0; - } else { - iecpy(pc->para.setup.phone, p, 2); - pc->para.setup.screen = p[3]; - } - } else { - pc->para.setup.phone[0] = 0; - pc->para.setup.plan = 0; - pc->para.setup.screen = 0; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6d, 0))) { - /* Calling party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.phone, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong calling subaddress"); - } - newl3state(pc, 6); - if (err) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, err); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); -} - -static void -l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) -{ - ni1_release_l3_process(pc); -} - -static void -l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - u_char cause = 16; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - StopAllL3Timer(pc); - - MsgHead(p, pc->callref, MT_DISCONNECT); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - if (pc->prot.ni1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.ni1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.ni1.uus1_data); - p += strlen(pc->prot.ni1.uus1_data); - pc->prot.ni1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 11); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T305, CC_T305); -} - -static void -l3ni1_setup_rsp(struct l3_process *pc, u_char pr, - void *arg) -{ - if (!pc->para.bchannel) - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "D-chan connect for waiting call"); - l3ni1_disconnect_req(pc, pr, arg); - return; - } - newl3state(pc, 8); - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "D-chan connect for waiting call"); - l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */ - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - newl3state(pc, 10); - L3DelTimer(&pc->timer); - if (ret) - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); -} - -static void -l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 21; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); -} - -static void -l3ni1_release(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret, cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3ni1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "REL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3ni1_parse_facility(pc->st, pc, pc->callref, p); - } - if ((ret < 0) && (pc->state != 11)) - cause = 96; - else if (ret > 0) - cause = 100; - ret = check_infoelements(pc, skb, ie_RELEASE); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) - cause = 99; - if (cause) - l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); - else - l3ni1_message(pc, MT_RELEASE_COMPLETE); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); -} - -static void -l3ni1_alert_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 7); - if (!pc->prot.ni1.uus1_data[0]) - l3ni1_message(pc, MT_ALERTING); - else - l3ni1_msg_with_uus(pc, MT_ALERTING); -} - -static void -l3ni1_proceed_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 9); - l3ni1_message(pc, MT_CALL_PROCEEDING); - pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); -} - -static void -l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 25); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T302, CC_T302); - l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); -} - -/********************************************/ -/* deliver a incoming display message to HL */ -/********************************************/ -static void -l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) -{ u_char len; - isdn_ctrl ic; - struct IsdnCardState *cs; - char *p; - - if (*infp++ != IE_DISPLAY) return; - if ((len = *infp++) > 80) return; /* total length <= 82 */ - if (!pc->chan) return; - - p = ic.parm.display; - while (len--) - *p++ = *infp++; - *p = '\0'; - ic.command = ISDN_STAT_DISPLAY; - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.arg = pc->chan->chan; - cs->iif.statcallb(&ic); -} /* l3ni1_deliver_display */ - - -static void -l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { - if (p[1] != 2) { - err = 1; - pc->para.cause = 100; - } else if (!(p[2] & 0x70)) { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - case 0x84: - case 0x85: - case 0x87: - case 0x8a: - switch (p[3]) { - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x88: - break; - default: - err = 2; - pc->para.cause = 100; - break; - } - break; - default: - err = 3; - pc->para.cause = 100; - break; - } - } - } else { - pc->para.cause = 96; - err = 4; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "progress error %d", err); - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_PROGRESS); - if (err) - l3ni1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); -} - -static void -l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { - if (p[1] != 1) { - err = 1; - pc->para.cause = 100; - } else { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - break; - default: - pc->para.cause = 100; - err = 2; - break; - } - } - } else { - pc->para.cause = 96; - err = 3; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "notify error %d", err); - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_NOTIFY); - if (err) - l3ni1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); -} - -static void -l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - - ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); - l3ni1_std_ie_err(pc, ret); - pc->para.cause = 30; /* response to STATUS_ENQUIRY */ - l3ni1_status_send(pc, pr, NULL); -} - -static void -l3ni1_information(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - u_char *p; - char tmp[32]; - - ret = check_infoelements(pc, skb, ie_INFORMATION); - if (ret) - l3ni1_std_ie_err(pc, ret); - if (pc->state == 25) { /* overlap receiving */ - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) { - iecpy(tmp, p, 1); - strcat(pc->para.setup.eazmsn, tmp); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); - } - L3AddTimer(&pc->timer, T302, CC_T302); - } -} - -/******************************/ -/* handle deflection requests */ -/******************************/ -static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char *subp; - u_char len_phone = 0; - u_char len_sub = 0; - int l; - - - strcpy(pc->prot.ni1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */ - if (!pc->chan->setup.phone[0]) - { pc->para.cause = -1; - l3ni1_disconnect_req(pc, pr, arg); /* disconnect immediately */ - return; - } /* only uus */ - - if (pc->prot.ni1.invoke_id) - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - - if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) - return; - - MsgHead(p, pc->callref, MT_FACILITY); - - for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ - if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ - - *p++ = 0x1c; /* Facility info element */ - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ - *p++ = 0x91; /* remote operations protocol */ - *p++ = 0xa1; /* invoke component */ - - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ - *p++ = 0x02; /* invoke id tag, integer */ - *p++ = 0x01; /* length */ - *p++ = pc->prot.ni1.invoke_id; /* invoke id */ - *p++ = 0x02; /* operation value tag, integer */ - *p++ = 0x01; /* length */ - *p++ = 0x0D; /* Call Deflect */ - - *p++ = 0x30; /* sequence phone number */ - *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ - - *p++ = 0x30; /* Deflected to UserNumber */ - *p++ = len_phone + 2 + len_sub; /* length */ - *p++ = 0x80; /* NumberDigits */ - *p++ = len_phone; /* length */ - for (l = 0; l < len_phone; l++) - *p++ = pc->chan->setup.phone[l]; - - if (len_sub) - { *p++ = 0x04; /* called party subaddress */ - *p++ = len_sub - 2; - while (*subp) *p++ = *subp++; - } - - *p++ = 0x01; /* screening identifier */ - *p++ = 0x01; - *p++ = pc->chan->setup.screen; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) return; - skb_put_data(skb, tmp, l); - - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3ni1_redir_req */ - -/********************************************/ -/* handle deflection request in early state */ -/********************************************/ -static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) -{ - l3ni1_proceed_req(pc, pr, arg); - l3ni1_redir_req(pc, pr, arg); -} /* l3ni1_redir_req_early */ - -/***********************************************/ -/* handle special commands for this protocol. */ -/* Examples are call independent services like */ -/* remote operations with dummy callref. */ -/***********************************************/ -static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) -{ u_char id; - u_char temp[265]; - u_char *p = temp; - int i, l, proc_len; - struct sk_buff *skb; - struct l3_process *pc = NULL; - - switch (ic->arg) - { case NI1_CMD_INVOKE: - if (ic->parm.ni1_io.datalen < 0) return (-2); /* invalid parameter */ - - for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) - i = i >> 8; /* add one byte */ - l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ - if (l > 255) - return (-2); /* too long */ - - if (!(id = new_invoke_id(st))) - return (0); /* first get a invoke id -> return if no available */ - - i = -1; - MsgHead(p, i, MT_FACILITY); /* build message head */ - *p++ = 0x1C; /* Facility IE */ - *p++ = l; /* length of ie */ - *p++ = 0x91; /* remote operations */ - *p++ = 0xA1; /* invoke */ - *p++ = l - 3; /* length of invoke */ - *p++ = 0x02; /* invoke id tag */ - *p++ = 0x01; /* length is 1 */ - *p++ = id; /* invoke id */ - *p++ = 0x02; /* operation */ - *p++ = proc_len; /* length of operation */ - - for (i = proc_len; i; i--) - *p++ = (ic->parm.ni1_io.proc >> (i - 1)) & 0xFF; - memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ - l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */ - - if (ic->parm.ni1_io.timeout > 0) { - pc = ni1_new_l3_process(st, -1); - if (!pc) { - free_invoke_id(st, id); - return (-2); - } - /* remember id */ - pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; - /* and procedure */ - pc->prot.ni1.proc = ic->parm.ni1_io.proc; - } - - if (!(skb = l3_alloc_skb(l))) - { free_invoke_id(st, id); - if (pc) ni1_release_l3_process(pc); - return (-2); - } - skb_put_data(skb, temp, l); - - if (pc) - { pc->prot.ni1.invoke_id = id; /* remember id */ - L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); - } - - l3_msg(st, DL_DATA | REQUEST, skb); - ic->parm.ni1_io.hl_id = id; /* return id */ - return (0); - - case NI1_CMD_INVOKE_ABORT: - if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) - { L3DelTimer(&pc->timer); /* remove timer */ - ni1_release_l3_process(pc); - return (0); - } - else - { l3_debug(st, "l3ni1_cmd_global abort unknown id"); - return (-2); - } - break; - - default: - l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); - return (-1); - } /* switch ic-> arg */ - return (-1); -} /* l3ni1_cmd_global */ - -static void -l3ni1_io_timer(struct l3_process *pc) -{ isdn_ctrl ic; - struct IsdnCardState *cs = pc->st->l1.hardware; - - L3DelTimer(&pc->timer); /* remove timer */ - - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_ERR; - ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; - ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; - ic.parm.ni1_io.proc = pc->prot.ni1.proc; - ic.parm.ni1_io.timeout = -1; - ic.parm.ni1_io.datalen = 0; - ic.parm.ni1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - pc->prot.ni1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - - ni1_release_l3_process(pc); -} /* l3ni1_io_timer */ - -static void -l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int callState = 0; - p = skb->data; - - if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) - callState = *p; - } - if (callState == 0) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 - * set down layer 3 without sending any message - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); - } else { - pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); - } -} - -static void -l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) -{ -} - -static void -l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 28; /* invalid number */ - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->N303 > 0) { - pc->N303--; - L3DelTimer(&pc->timer); - l3ni1_setup_req(pc, pr, arg); - } else { - L3DelTimer(&pc->timer); - l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); - pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); - ni1_release_l3_process(pc); - } -} - -static void -l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); - -} - -static void -l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - u_char cause = 16; - - L3DelTimer(&pc->timer); - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 19); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); -} - -static void -l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 19); - L3DelTimer(&pc->timer); - l3ni1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_2); -} - -static void -l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); - ni1_release_l3_process(pc); -} - -static void -l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 19); - l3ni1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); -} - -static void -l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - ni1_release_l3_process(pc); -} - -static void -l3ni1_status(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int ret; - u_char cause = 0, callState = 0; - - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) { - callState = *p; - if (!ie_in_set(pc, *p, l3_valid_states)) - cause = 100; - } else - cause = 100; - } else - cause = 96; - if (!cause) { /* no error before */ - ret = check_infoelements(pc, skb, ie_STATUS); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if (ERR_IE_UNRECOGNIZED == ret) - cause = 99; - } - if (cause) { - u_char tmp; - - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause); - tmp = pc->para.cause; - pc->para.cause = cause; - l3ni1_status_send(pc, 0, NULL); - if (cause == 99) - pc->para.cause = tmp; - else - return; - } - cause = pc->para.cause; - if (((cause & 0x7f) == 111) && (callState == 0)) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... - * if received MT_STATUS with cause == 111 and call - * state == 0, then we must set down layer 3 - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); - } -} - -static void -l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_FACILITY); - l3ni1_std_ie_err(pc, ret); - { - u_char *p; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3ni1_parse_facility(pc->st, pc, pc->callref, p); - } -} - -static void -l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->chan->setup.phone; - - MsgHead(p, pc->callref, MT_SUSPEND); - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 15); - L3AddTimer(&pc->timer, T319, CC_T319); -} - -static void -l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - L3DelTimer(&pc->timer); - newl3state(pc, 0); - pc->para.cause = NO_CAUSE; - pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); - /* We don't handle suspend_ack for IE errors now */ - if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSPACK check ie(%d)", ret); - ni1_release_l3_process(pc); -} - -static void -l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); -} - -static void -l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->para.setup.phone; - - MsgHead(p, pc->callref, MT_RESUME); - - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "RES wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 17); - L3AddTimer(&pc->timer, T318, CC_T318); -} - -static void -l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack with wrong chid %x", id); - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack without chid (ret %d)", id); - pc->para.cause = 96; - l3ni1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); -} - -static void -l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 0); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); - ni1_release_l3_process(pc); -} - -static void -l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[32]; - u_char *p; - u_char ri, ch = 0, chan = 0; - int l; - struct sk_buff *skb = arg; - struct l3_process *up; - - newl3state(pc, 2); - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { - ri = p[2]; - l3_debug(pc->st, "Restart %x", ri); - } else { - l3_debug(pc->st, "Restart without restart IE"); - ri = 0x86; - } - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - chan = p[2] & 3; - ch = p[2]; - if (pc->st->l3.debug) - l3_debug(pc->st, "Restart for channel %d", chan); - } - newl3state(pc, 2); - up = pc->st->l3.proc; - while (up) { - if ((ri & 7) == 7) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - else if (up->para.bchannel == chan) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - - up = up->next; - } - p = tmp; - MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); - if (chan) { - *p++ = IE_CHANNEL_ID; - *p++ = 1; - *p++ = ch | 0x80; - } - *p++ = 0x79; /* RESTART Ind */ - *p++ = 1; - *p++ = ri; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 0); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) -{ - pc->para.cause = 0x29; /* Temporary failure */ - pc->para.loc = 0; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 0); - pc->para.cause = 0x1b; /* Destination out of order */ - pc->para.loc = 0; - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -static void -l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T309, CC_T309); - l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - - pc->para.cause = 0x1F; /* normal, unspecified */ - l3ni1_status_send(pc, 0, NULL); -} - -static void l3ni1_SendSpid(struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState) -{ - u_char *p; - char *pSPID; - struct Channel *pChan = pc->st->lli.userdata; - int l; - - if (skb) - dev_kfree_skb(skb); - - if (!(pSPID = strchr(pChan->setup.eazmsn, ':'))) - { - printk(KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn); - newl3state(pc, 0); - pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL); - return; - } - - l = strlen(++pSPID); - if (!(skb = l3_alloc_skb(5 + l))) - { - printk(KERN_ERR "HiSax can't get memory to send SPID\n"); - return; - } - - p = skb_put(skb, 5); - *p++ = PROTO_DIS_EURO; - *p++ = 0; - *p++ = MT_INFORMATION; - *p++ = IE_SPID; - *p++ = l; - - skb_put_data(skb, pSPID, l); - - newl3state(pc, iNewState); - - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, TSPID, CC_TSPID); - - pc->st->l3.l3l2(pc->st, DL_DATA | REQUEST, skb); -} - -static void l3ni1_spid_send(struct l3_process *pc, u_char pr, void *arg) -{ - l3ni1_SendSpid(pc, pr, arg, 20); -} - -static void l3ni1_spid_epid(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - if (skb->data[1] == 0) - if (skb->data[3] == IE_ENDPOINT_ID) - { - L3DelTimer(&pc->timer); - newl3state(pc, 0); - l3_msg(pc->st, DL_ESTABLISH | CONFIRM, NULL); - } - dev_kfree_skb(skb); -} - -static void l3ni1_spid_tout(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->state < 22) - l3ni1_SendSpid(pc, pr, arg, pc->state + 1); - else - { - L3DelTimer(&pc->timer); - dev_kfree_skb(arg); - - printk(KERN_ERR "SPID not accepted\n"); - newl3state(pc, 0); - pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL); - } -} - -/* *INDENT-OFF* */ -static struct stateentry downstatelist[] = -{ - {SBIT(0), - CC_SETUP | REQUEST, l3ni1_setup_req}, - {SBIT(0), - CC_RESUME | REQUEST, l3ni1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), - CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, - {SBIT(12), - CC_RELEASE | REQUEST, l3ni1_release_req}, - {ALL_STATES, - CC_RESTART | REQUEST, l3ni1_restart}, - {SBIT(6) | SBIT(25), - CC_IGNORE | REQUEST, l3ni1_reset}, - {SBIT(6) | SBIT(25), - CC_REJECT | REQUEST, l3ni1_reject_req}, - {SBIT(6) | SBIT(25), - CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, - {SBIT(6), - CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, - {SBIT(25), - CC_MORE_INFO | REQUEST, l3ni1_dummy}, - {SBIT(6) | SBIT(9) | SBIT(25), - CC_ALERTING | REQUEST, l3ni1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), - CC_SETUP | RESPONSE, l3ni1_setup_rsp}, - {SBIT(10), - CC_SUSPEND | REQUEST, l3ni1_suspend_req}, - {SBIT(7) | SBIT(9) | SBIT(25), - CC_REDIR | REQUEST, l3ni1_redir_req}, - {SBIT(6), - CC_REDIR | REQUEST, l3ni1_redir_req_early}, - {SBIT(9) | SBIT(25), - CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, - {SBIT(25), - CC_T302, l3ni1_t302}, - {SBIT(1), - CC_T303, l3ni1_t303}, - {SBIT(2), - CC_T304, l3ni1_t304}, - {SBIT(3), - CC_T310, l3ni1_t310}, - {SBIT(8), - CC_T313, l3ni1_t313}, - {SBIT(11), - CC_T305, l3ni1_t305}, - {SBIT(15), - CC_T319, l3ni1_t319}, - {SBIT(17), - CC_T318, l3ni1_t318}, - {SBIT(19), - CC_T308_1, l3ni1_t308_1}, - {SBIT(19), - CC_T308_2, l3ni1_t308_2}, - {SBIT(10), - CC_T309, l3ni1_dl_release}, - { SBIT(20) | SBIT(21) | SBIT(22), - CC_TSPID, l3ni1_spid_tout }, -}; - -static struct stateentry datastatelist[] = -{ - {ALL_STATES, - MT_STATUS_ENQUIRY, l3ni1_status_enq}, - {ALL_STATES, - MT_FACILITY, l3ni1_facility}, - {SBIT(19), - MT_STATUS, l3ni1_release_ind}, - {ALL_STATES, - MT_STATUS, l3ni1_status}, - {SBIT(0), - MT_SETUP, l3ni1_setup}, - {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | - SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_SETUP, l3ni1_dummy}, - {SBIT(1) | SBIT(2), - MT_CALL_PROCEEDING, l3ni1_call_proc}, - {SBIT(1), - MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, - {SBIT(2) | SBIT(3), - MT_ALERTING, l3ni1_alerting}, - {SBIT(2) | SBIT(3), - MT_PROGRESS, l3ni1_progress}, - {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_INFORMATION, l3ni1_information}, - {SBIT(10) | SBIT(11) | SBIT(15), - MT_NOTIFY, l3ni1_notify}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), - MT_RELEASE, l3ni1_release}, - {SBIT(19), MT_RELEASE, l3ni1_release_ind}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), - MT_DISCONNECT, l3ni1_disconnect}, - {SBIT(19), - MT_DISCONNECT, l3ni1_dummy}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), - MT_CONNECT, l3ni1_connect}, - {SBIT(8), - MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, - {SBIT(15), - MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, - {SBIT(15), - MT_SUSPEND_REJECT, l3ni1_suspend_rej}, - {SBIT(17), - MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, - {SBIT(17), - MT_RESUME_REJECT, l3ni1_resume_rej}, -}; - -static struct stateentry globalmes_list[] = -{ - {ALL_STATES, - MT_STATUS, l3ni1_status}, - {SBIT(0), - MT_RESTART, l3ni1_global_restart}, -/* {SBIT(1), - MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, -*/ - { SBIT(0), MT_DL_ESTABLISHED, l3ni1_spid_send }, - { SBIT(20) | SBIT(21) | SBIT(22), MT_INFORMATION, l3ni1_spid_epid }, -}; - -static struct stateentry manstatelist[] = -{ - {SBIT(2), - DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, - {SBIT(10), - DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, - {SBIT(10), - DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, - {ALL_STATES, - DL_RELEASE | INDICATION, l3ni1_dl_release}, -}; - -/* *INDENT-ON* */ - - -static void -global_handler(struct PStack *st, int mt, struct sk_buff *skb) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - int i; - struct l3_process *proc = st->l3.global; - - if (skb) - proc->callref = skb->data[2]; /* cr flag */ - else - proc->callref = 0; - for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) - if ((mt == globalmes_list[i].primitive) && - ((1 << proc->state) & globalmes_list[i].state)) - break; - if (i == ARRAY_SIZE(globalmes_list)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1 global state %d mt %x unhandled", - proc->state, mt); - } - MsgHead(p, proc->callref, MT_STATUS); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 81 | 0x80; /* invalid cr */ - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = proc->state & 0x3f; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(proc->st, DL_DATA | REQUEST, skb); - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1 global %d mt %x", - proc->state, mt); - } - globalmes_list[i].rout(proc, mt, skb); - } -} - -static void -ni1up(struct PStack *st, int pr, void *arg) -{ - int i, mt, cr, callState; - char *ptr; - u_char *p; - struct sk_buff *skb = arg; - struct l3_process *proc; - - switch (pr) { - case (DL_DATA | INDICATION): - case (DL_UNIT_DATA | INDICATION): - break; - case (DL_ESTABLISH | INDICATION): - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - l3_msg(st, pr, arg); - return; - break; - - case (DL_ESTABLISH | CONFIRM): - global_handler(st, MT_DL_ESTABLISHED, NULL); - return; - - default: - printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); - return; - } - if (skb->len < 3) { - l3_debug(st, "ni1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - - if (skb->data[0] != PROTO_DIS_EURO) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - skb->data[0], skb->len); - } - dev_kfree_skb(skb); - return; - } - cr = getcallref(skb->data); - if (skb->len < ((skb->data[1] & 0x0f) + 3)) { - l3_debug(st, "ni1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - mt = skb->data[skb->data[1] + 2]; - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "ni1up cr %d", cr); - if (cr == -2) { /* wrong Callref */ - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "ni1up wrong Callref"); - dev_kfree_skb(skb); - return; - } else if (cr == -1) { /* Dummy Callref */ - if (mt == MT_FACILITY) - { - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3ni1_parse_facility(st, NULL, - (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); - dev_kfree_skb(skb); - return; - } - } - else - { - global_handler(st, mt, skb); - return; - } - - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); - dev_kfree_skb(skb); - return; - } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) || - (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "ni1up Global CallRef"); - global_handler(st, mt, skb); - dev_kfree_skb(skb); - return; - } else if (!(proc = getl3proc(st, cr))) { - /* No transaction process exist, that means no call with - * this callreference is active - */ - if (mt == MT_SETUP) { - /* Setup creates a new transaction process */ - if (skb->data[2] & 0x80) { - /* Setup with wrong CREF flag */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "ni1up wrong CRef flag"); - dev_kfree_skb(skb); - return; - } - if (!(proc = ni1_new_l3_process(st, cr))) { - /* May be to answer with RELEASE_COMPLETE and - * CAUSE 0x2f "Resource unavailable", but this - * need a new_l3_process too ... arghh - */ - dev_kfree_skb(skb); - return; - } - } else if (mt == MT_STATUS) { - if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - } - callState = 0; - if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - callState = *ptr; - } - /* ETS 300-104 part 2.4.1 - * if setup has not been made and a message type - * MT_STATUS is received with call state == 0, - * we must send nothing - */ - if (callState != 0) { - /* ETS 300-104 part 2.4.2 - * if setup has not been made and a message type - * MT_STATUS is received with call state != 0, - * we must send MT_RELEASE_COMPLETE cause 101 - */ - if ((proc = ni1_new_l3_process(st, cr))) { - proc->para.cause = 101; - l3ni1_msg_without_setup(proc, 0, NULL); - } - } - dev_kfree_skb(skb); - return; - } else if (mt == MT_RELEASE_COMPLETE) { - dev_kfree_skb(skb); - return; - } else { - /* ETS 300-104 part 2 - * if setup has not been made and a message type - * (except MT_SETUP and RELEASE_COMPLETE) is received, - * we must send MT_RELEASE_COMPLETE cause 81 */ - dev_kfree_skb(skb); - if ((proc = ni1_new_l3_process(st, cr))) { - proc->para.cause = 81; - l3ni1_msg_without_setup(proc, 0, NULL); - } - return; - } - } - if (l3ni1_check_messagetype_validity(proc, mt, skb)) { - dev_kfree_skb(skb); - return; - } - if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) - l3ni1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < ARRAY_SIZE(datastatelist); i++) - if ((mt == datastatelist[i].primitive) && - ((1 << proc->state) & datastatelist[i].state)) - break; - if (i == ARRAY_SIZE(datastatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1up%sstate %d mt %#x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { - proc->para.cause = 101; - l3ni1_status_send(proc, pr, skb); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1up%sstate %d mt %x", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - datastatelist[i].rout(proc, pr, skb); - } - dev_kfree_skb(skb); - return; -} - -static void -ni1down(struct PStack *st, int pr, void *arg) -{ - int i, cr; - struct l3_process *proc; - struct Channel *chan; - - if ((DL_ESTABLISH | REQUEST) == pr) { - l3_msg(st, pr, NULL); - return; - } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { - chan = arg; - cr = newcallref(); - cr |= 0x80; - if ((proc = ni1_new_l3_process(st, cr))) { - proc->chan = chan; - chan->proc = proc; - memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); - proc->callref = cr; - } - } else { - proc = arg; - } - if (!proc) { - printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); - return; - } - - if (pr == (CC_TNI1_IO | REQUEST)) { - l3ni1_io_timer(proc); /* timer expires */ - return; - } - - for (i = 0; i < ARRAY_SIZE(downstatelist); i++) - if ((pr == downstatelist[i].primitive) && - ((1 << proc->state) & downstatelist[i].state)) - break; - if (i == ARRAY_SIZE(downstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1down state %d prim %#x unhandled", - proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1down state %d prim %#x", - proc->state, pr); - } - downstatelist[i].rout(proc, pr, arg); - } -} - -static void -ni1man(struct PStack *st, int pr, void *arg) -{ - int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < ARRAY_SIZE(manstatelist); i++) - if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == ARRAY_SIZE(manstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d ni1man state %d prim %#x", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } -} - -void -setstack_ni1(struct PStack *st) -{ - char tmp[64]; - int i; - - st->lli.l4l3 = ni1down; - st->lli.l4l3_proto = l3ni1_cmd_global; - st->l2.l2l3 = ni1up; - st->l3.l3ml3 = ni1man; - st->l3.N303 = 1; - st->prot.ni1.last_invoke_id = 0; - st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ - i = 1; - while (i < 32) - st->prot.ni1.invoke_used[i++] = 0; - - if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { - printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); - } else { - st->l3.global->state = 0; - st->l3.global->callref = 0; - st->l3.global->next = NULL; - st->l3.global->debug = L3_DEB_WARN; - st->l3.global->st = st; - st->l3.global->N303 = 1; - st->l3.global->prot.ni1.invoke_id = 0; - - L3InitTimer(st->l3.global, &st->l3.global->timer); - } - strcpy(tmp, ni1_revision); - printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); -} diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h deleted file mode 100644 index 99d37d2cea4f..000000000000 --- a/drivers/isdn/hisax/l3ni1.h +++ /dev/null @@ -1,136 +0,0 @@ -/* $Id: l3ni1.h,v 2.3.6.2 2001/09/23 22:24:50 kai Exp $ - * - * NI1 D-channel protocol - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 2000.6.6 Initial implementation of routines for US NI1 - * Layer 3 protocol based on the EURO/DSS1 D-channel protocol - * driver written by Karsten Keil et al. Thanks also for the - * code provided by Ragnar Paulson. - * - */ - -#ifndef l3ni1_process - -#define T302 15000 -#define T303 4000 -#define T304 30000 -#define T305 30000 -#define T308 4000 -/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ -/* This makes some tests easier and quicker */ -#define T309 40000 -#define T310 30000 -#define T313 4000 -#define T318 4000 -#define T319 4000 -#define TSPID 5000 /* was 2000 - Guy Ellis */ - -/* - * Message-Types - */ - -#define MT_ALERTING 0x01 -#define MT_CALL_PROCEEDING 0x02 -#define MT_CONNECT 0x07 -#define MT_CONNECT_ACKNOWLEDGE 0x0f -#define MT_PROGRESS 0x03 -#define MT_SETUP 0x05 -#define MT_SETUP_ACKNOWLEDGE 0x0d -#define MT_RESUME 0x26 -#define MT_RESUME_ACKNOWLEDGE 0x2e -#define MT_RESUME_REJECT 0x22 -#define MT_SUSPEND 0x25 -#define MT_SUSPEND_ACKNOWLEDGE 0x2d -#define MT_SUSPEND_REJECT 0x21 -#define MT_USER_INFORMATION 0x20 -#define MT_DISCONNECT 0x45 -#define MT_RELEASE 0x4d -#define MT_RELEASE_COMPLETE 0x5a -#define MT_RESTART 0x46 -#define MT_RESTART_ACKNOWLEDGE 0x4e -#define MT_SEGMENT 0x60 -#define MT_CONGESTION_CONTROL 0x79 -#define MT_INFORMATION 0x7b -#define MT_FACILITY 0x62 -#define MT_NOTIFY 0x6e -#define MT_STATUS 0x7d -#define MT_STATUS_ENQUIRY 0x75 -#define MT_DL_ESTABLISHED 0xfe - -#define IE_SEGMENT 0x00 -#define IE_BEARER 0x04 -#define IE_CAUSE 0x08 -#define IE_CALL_ID 0x10 -#define IE_CALL_STATE 0x14 -#define IE_CHANNEL_ID 0x18 -#define IE_FACILITY 0x1c -#define IE_PROGRESS 0x1e -#define IE_NET_FAC 0x20 -#define IE_NOTIFY 0x27 -#define IE_DISPLAY 0x28 -#define IE_DATE 0x29 -#define IE_KEYPAD 0x2c -#define IE_SIGNAL 0x34 -#define IE_SPID 0x3a -#define IE_ENDPOINT_ID 0x3b -#define IE_INFORATE 0x40 -#define IE_E2E_TDELAY 0x42 -#define IE_TDELAY_SEL 0x43 -#define IE_PACK_BINPARA 0x44 -#define IE_PACK_WINSIZE 0x45 -#define IE_PACK_SIZE 0x46 -#define IE_CUG 0x47 -#define IE_REV_CHARGE 0x4a -#define IE_CONNECT_PN 0x4c -#define IE_CONNECT_SUB 0x4d -#define IE_CALLING_PN 0x6c -#define IE_CALLING_SUB 0x6d -#define IE_CALLED_PN 0x70 -#define IE_CALLED_SUB 0x71 -#define IE_REDIR_NR 0x74 -#define IE_TRANS_SEL 0x78 -#define IE_RESTART_IND 0x79 -#define IE_LLC 0x7c -#define IE_HLC 0x7d -#define IE_USER_USER 0x7e -#define IE_ESCAPE 0x7f -#define IE_SHIFT 0x90 -#define IE_MORE_DATA 0xa0 -#define IE_COMPLETE 0xa1 -#define IE_CONGESTION 0xb0 -#define IE_REPEAT 0xd0 - -#define IE_MANDATORY 0x0100 -/* mandatory not in every case */ -#define IE_MANDATORY_1 0x0200 - -#define ERR_IE_COMPREHENSION 1 -#define ERR_IE_UNRECOGNIZED -1 -#define ERR_IE_LENGTH -2 -#define ERR_IE_SEQUENCE -3 - -#else /* only l3ni1_process */ - -/* l3ni1 specific data in l3 process */ -typedef struct -{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ - ulong ll_id; /* remebered ll id */ - u8 remote_operation; /* handled remote operation, 0 = not active */ - int proc; /* rememered procedure */ - ulong remote_result; /* result of remote operation for statcallb */ - char uus1_data[35]; /* data send during alerting or disconnect */ -} ni1_proc_priv; - -/* l3dni1 specific data in protocol stack */ -typedef struct -{ unsigned char last_invoke_id; /* last used value for invoking */ - unsigned char invoke_used[32]; /* 256 bits for 256 values */ -} ni1_stk_priv; - -#endif /* only l3dni1_process */ diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c deleted file mode 100644 index 5b63eb6601aa..000000000000 --- a/drivers/isdn/hisax/lmgr.c +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id: lmgr.c,v 1.7.6.2 2001/09/23 22:24:50 kai Exp $ - * - * Layermanagement module - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include "hisax.h" - -static void -error_handling_dchan(struct PStack *st, int Error) -{ - switch (Error) { - case 'C': - case 'D': - case 'G': - case 'H': - st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL); - break; - } -} - -static void -hisax_manager(struct PStack *st, int pr, void *arg) -{ - long Code; - - switch (pr) { - case (MDL_ERROR | INDICATION): - Code = (long) arg; - HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR", - " %c %s", (char)Code, - test_bit(FLG_LAPD, &st->l2.flag) ? - "D-channel" : "B-channel"); - if (test_bit(FLG_LAPD, &st->l2.flag)) - error_handling_dchan(st, Code); - break; - } -} - -void -setstack_manager(struct PStack *st) -{ - st->ma.layer = hisax_manager; -} diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c deleted file mode 100644 index 93398676f78f..000000000000 --- a/drivers/isdn/hisax/mic.c +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for mic cards - * - * Author Stephan von Krawczynski - * Copyright by Stephan von Krawczynski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *mic_revision = "$Revision: 1.12.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define MIC_ISAC 2 -#define MIC_HSCX 1 -#define MIC_ADR 7 - -/* CARD_ADR (Write) */ -#define MIC_RESET 0x3 /* same as DOS driver */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.mic.adr, - cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.mic.adr, - cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \ - cs->hw.mic.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \ - cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \ - cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \ - cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -mic_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_mic(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - if (cs->hw.mic.cfg_reg) - release_region(cs->hw.mic.cfg_reg, bytecnt); -} - -static int -mic_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - return (0); - case CARD_RELEASE: - release_io_mic(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscx(cs); /* /RTSA := ISAC RST */ - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_mic(struct IsdnCard *card) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, mic_revision); - printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_MIC) - return (0); - - bytecnt = 8; - cs->hw.mic.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR; - cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; - cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; - - if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) { - printk(KERN_WARNING - "HiSax: ith mic config port %x-%x already in use\n", - cs->hw.mic.cfg_reg, - cs->hw.mic.cfg_reg + bytecnt); - return (0); - } - printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n", - cs->hw.mic.cfg_reg, cs->irq); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &mic_card_msg; - cs->irq_func = &mic_interrupt; - ISACVersion(cs, "mic:"); - if (HscxVersion(cs, "mic:")) { - printk(KERN_WARNING - "mic: wrong HSCX versions check IO address\n"); - release_io_mic(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c deleted file mode 100644 index d7b011c8d692..000000000000 --- a/drivers/isdn/hisax/netjet.c +++ /dev/null @@ -1,985 +0,0 @@ -/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $ - * - * low level stuff for Traverse Technologie NETJet ISDN cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Traverse Technologies Australia for documents and information - * - * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au) - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include -#include -#include -#include -#include "netjet.h" - -/* Interface functions */ - -u_char -NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) -{ - u_char ret; - - cs->hw.njet.auxd &= 0xfc; - cs->hw.njet.auxd |= (offset >> 4) & 3; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - ret = bytein(cs->hw.njet.isac + ((offset & 0xf) << 2)); - return (ret); -} - -void -NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - cs->hw.njet.auxd &= 0xfc; - cs->hw.njet.auxd |= (offset >> 4) & 3; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - byteout(cs->hw.njet.isac + ((offset & 0xf) << 2), value); -} - -void -NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.njet.auxd &= 0xfc; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - insb(cs->hw.njet.isac, data, size); -} - -void -NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.njet.auxd &= 0xfc; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - outsb(cs->hw.njet.isac, data, size); -} - -static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) -{ - u_int mask = 0x000000ff, val = 0, *p = pos; - u_int i; - - val |= fill; - if (chan) { - val <<= 8; - mask <<= 8; - } - mask ^= 0xffffffff; - for (i = 0; i < cnt; i++) { - *p &= mask; - *p++ |= val; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - } -} - -static void -mode_tiger(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - u_char led; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "Tiger mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - switch (mode) { - case (L1_MODE_NULL): - fill_mem(bcs, bcs->hw.tiger.send, - NETJET_DMA_TXSIZE, bc, 0xff); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "Tiger stat rec %d/%d send %d", - bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err, - bcs->hw.tiger.s_tot); - if ((cs->bcs[0].mode == L1_MODE_NULL) && - (cs->bcs[1].mode == L1_MODE_NULL)) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } - if (cs->typ == ISDN_CTYPE_NETJET_S) - { - // led off - led = bc & 0x01; - led = 0x01 << (6 + led); // convert to mask - led = ~led; - cs->hw.njet.auxd &= led; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - } - break; - case (L1_MODE_TRANS): - break; - case (L1_MODE_HDLC_56K): - case (L1_MODE_HDLC): - fill_mem(bcs, bcs->hw.tiger.send, - NETJET_DMA_TXSIZE, bc, 0xff); - bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH; - bcs->hw.tiger.r_tot = 0; - bcs->hw.tiger.r_bitcnt = 0; - bcs->hw.tiger.r_one = 0; - bcs->hw.tiger.r_err = 0; - bcs->hw.tiger.s_tot = 0; - if (!cs->hw.njet.dmactrl) { - fill_mem(bcs, bcs->hw.tiger.send, - NETJET_DMA_TXSIZE, !bc, 0xff); - cs->hw.njet.dmactrl = 1; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f); - /* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */ - } - bcs->hw.tiger.sendp = bcs->hw.tiger.send; - bcs->hw.tiger.free = NETJET_DMA_TXSIZE; - test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); - if (cs->typ == ISDN_CTYPE_NETJET_S) - { - // led on - led = bc & 0x01; - led = 0x01 << (6 + led); // convert to mask - cs->hw.njet.auxd |= led; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - } - break; - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d", - bytein(cs->hw.njet.base + NETJET_DMACTRL), - bytein(cs->hw.njet.base + NETJET_IRQMASK0), - bytein(cs->hw.njet.base + NETJET_IRQSTAT0), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); -} - -static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { - char tmp[128]; - char *t = tmp; - int i = count, j; - u_char *p = buf; - - t += sprintf(t, "tiger %s(%4d)", s, count); - while (i > 0) { - if (i > 16) - j = 16; - else - j = i; - QuickHex(t, p, j); - debugl1(cs, "%s", tmp); - p += j; - i -= j; - t = tmp; - t += sprintf(t, "tiger %s ", s); - } -} - -// macro for 64k - -#define MAKE_RAW_BYTE for (j = 0; j < 8; j++) { \ - bitcnt++; \ - s_val >>= 1; \ - if (val & 1) { \ - s_one++; \ - s_val |= 0x80; \ - } else { \ - s_one = 0; \ - s_val &= 0x7f; \ - } \ - if (bitcnt == 8) { \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - if (s_one == 5) { \ - s_val >>= 1; \ - s_val &= 0x7f; \ - bitcnt++; \ - s_one = 0; \ - } \ - if (bitcnt == 8) { \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - val >>= 1; \ - } - -static int make_raw_data(struct BCState *bcs) { -// this make_raw is for 64k - register u_int i, s_cnt = 0; - register u_char j; - register u_char val; - register u_char s_one = 0; - register u_char s_val = 0; - register u_char bitcnt = 0; - u_int fcs; - - if (!bcs->tx_skb) { - debugl1(bcs->cs, "tiger make_raw: NULL skb"); - return (1); - } - bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE; - fcs = PPP_INITFCS; - for (i = 0; i < bcs->tx_skb->len; i++) { - val = bcs->tx_skb->data[i]; - fcs = PPP_FCS(fcs, val); - MAKE_RAW_BYTE; - } - fcs ^= 0xffff; - val = fcs & 0xff; - MAKE_RAW_BYTE; - val = (fcs >> 8) & 0xff; - MAKE_RAW_BYTE; - val = HDLC_FLAG_VALUE; - for (j = 0; j < 8; j++) { - bitcnt++; - s_val >>= 1; - if (val & 1) - s_val |= 0x80; - else - s_val &= 0x7f; - if (bitcnt == 8) { - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bitcnt = 0; - } - val >>= 1; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger make_raw: in %u out %d.%d", - bcs->tx_skb->len, s_cnt, bitcnt); - if (bitcnt) { - while (8 > bitcnt++) { - s_val >>= 1; - s_val |= 0x80; - } - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix - } - bcs->hw.tiger.sendcnt = s_cnt; - bcs->tx_cnt -= bcs->tx_skb->len; - bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; - return (0); -} - -// macro for 56k - -#define MAKE_RAW_BYTE_56K for (j = 0; j < 8; j++) { \ - bitcnt++; \ - s_val >>= 1; \ - if (val & 1) { \ - s_one++; \ - s_val |= 0x80; \ - } else { \ - s_one = 0; \ - s_val &= 0x7f; \ - } \ - if (bitcnt == 7) { \ - s_val >>= 1; \ - s_val |= 0x80; \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - if (s_one == 5) { \ - s_val >>= 1; \ - s_val &= 0x7f; \ - bitcnt++; \ - s_one = 0; \ - } \ - if (bitcnt == 7) { \ - s_val >>= 1; \ - s_val |= 0x80; \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - val >>= 1; \ - } - -static int make_raw_data_56k(struct BCState *bcs) { -// this make_raw is for 56k - register u_int i, s_cnt = 0; - register u_char j; - register u_char val; - register u_char s_one = 0; - register u_char s_val = 0; - register u_char bitcnt = 0; - u_int fcs; - - if (!bcs->tx_skb) { - debugl1(bcs->cs, "tiger make_raw_56k: NULL skb"); - return (1); - } - val = HDLC_FLAG_VALUE; - for (j = 0; j < 8; j++) { - bitcnt++; - s_val >>= 1; - if (val & 1) - s_val |= 0x80; - else - s_val &= 0x7f; - if (bitcnt == 7) { - s_val >>= 1; - s_val |= 0x80; - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bitcnt = 0; - } - val >>= 1; - } - fcs = PPP_INITFCS; - for (i = 0; i < bcs->tx_skb->len; i++) { - val = bcs->tx_skb->data[i]; - fcs = PPP_FCS(fcs, val); - MAKE_RAW_BYTE_56K; - } - fcs ^= 0xffff; - val = fcs & 0xff; - MAKE_RAW_BYTE_56K; - val = (fcs >> 8) & 0xff; - MAKE_RAW_BYTE_56K; - val = HDLC_FLAG_VALUE; - for (j = 0; j < 8; j++) { - bitcnt++; - s_val >>= 1; - if (val & 1) - s_val |= 0x80; - else - s_val &= 0x7f; - if (bitcnt == 7) { - s_val >>= 1; - s_val |= 0x80; - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bitcnt = 0; - } - val >>= 1; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger make_raw_56k: in %u out %d.%d", - bcs->tx_skb->len, s_cnt, bitcnt); - if (bitcnt) { - while (8 > bitcnt++) { - s_val >>= 1; - s_val |= 0x80; - } - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix - } - bcs->hw.tiger.sendcnt = s_cnt; - bcs->tx_cnt -= bcs->tx_skb->len; - bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; - return (0); -} - -static void got_frame(struct BCState *bcs, int count) { - struct sk_buff *skb; - - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "TIGER: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.tiger.rcvbuf, count); - skb_queue_tail(&bcs->rqueue, skb); - } - test_and_set_bit(B_RCVBUFREADY, &bcs->event); - schedule_work(&bcs->tqueue); - - if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME) - printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec"); -} - - - -static void read_raw(struct BCState *bcs, u_int *buf, int cnt) { - int i; - register u_char j; - register u_char val; - u_int *pend = bcs->hw.tiger.rec + NETJET_DMA_RXSIZE - 1; - register u_char state = bcs->hw.tiger.r_state; - register u_char r_one = bcs->hw.tiger.r_one; - register u_char r_val = bcs->hw.tiger.r_val; - register u_int bitcnt = bcs->hw.tiger.r_bitcnt; - u_int *p = buf; - int bits; - u_char mask; - - if (bcs->mode == L1_MODE_HDLC) { // it's 64k - mask = 0xff; - bits = 8; - } - else { // it's 56K - mask = 0x7f; - bits = 7; - } - for (i = 0; i < cnt; i++) { - val = bcs->channel ? ((*p >> 8) & 0xff) : (*p & 0xff); - p++; - if (p > pend) - p = bcs->hw.tiger.rec; - if ((val & mask) == mask) { - state = HDLC_ZERO_SEARCH; - bcs->hw.tiger.r_tot++; - bitcnt = 0; - r_one = 0; - continue; - } - for (j = 0; j < bits; j++) { - if (state == HDLC_ZERO_SEARCH) { - if (val & 1) { - r_one++; - } else { - r_one = 0; - state = HDLC_FLAG_SEARCH; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger read_raw: zBit(%d,%d,%d) %x", - bcs->hw.tiger.r_tot, i, j, val); - } - } else if (state == HDLC_FLAG_SEARCH) { - if (val & 1) { - r_one++; - if (r_one > 6) { - state = HDLC_ZERO_SEARCH; - } - } else { - if (r_one == 6) { - bitcnt = 0; - r_val = 0; - state = HDLC_FLAG_FOUND; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger read_raw: flag(%d,%d,%d) %x", - bcs->hw.tiger.r_tot, i, j, val); - } - r_one = 0; - } - } else if (state == HDLC_FLAG_FOUND) { - if (val & 1) { - r_one++; - if (r_one > 6) { - state = HDLC_ZERO_SEARCH; - } else { - r_val >>= 1; - r_val |= 0x80; - bitcnt++; - } - } else { - if (r_one == 6) { - bitcnt = 0; - r_val = 0; - r_one = 0; - val >>= 1; - continue; - } else if (r_one != 5) { - r_val >>= 1; - r_val &= 0x7f; - bitcnt++; - } - r_one = 0; - } - if ((state != HDLC_ZERO_SEARCH) && - !(bitcnt & 7)) { - state = HDLC_FRAME_FOUND; - bcs->hw.tiger.r_fcs = PPP_INITFCS; - bcs->hw.tiger.rcvbuf[0] = r_val; - bcs->hw.tiger.r_fcs = PPP_FCS(bcs->hw.tiger.r_fcs, r_val); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", - bcs->hw.tiger.r_tot, i, j, r_val, val, - bcs->cs->hw.njet.irqstat0); - } - } else if (state == HDLC_FRAME_FOUND) { - if (val & 1) { - r_one++; - if (r_one > 6) { - state = HDLC_ZERO_SEARCH; - bitcnt = 0; - } else { - r_val >>= 1; - r_val |= 0x80; - bitcnt++; - } - } else { - if (r_one == 6) { - r_val = 0; - r_one = 0; - bitcnt++; - if (bitcnt & 7) { - debugl1(bcs->cs, "tiger: frame not byte aligned"); - state = HDLC_FLAG_SEARCH; - bcs->hw.tiger.r_err++; -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - } else { - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger frame end(%d,%d): fcs(%x) i %x", - i, j, bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0); - if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) { - got_frame(bcs, (bitcnt >> 3) - 3); - } else { - if (bcs->cs->debug) { - debugl1(bcs->cs, "tiger FCS error"); - printframe(bcs->cs, bcs->hw.tiger.rcvbuf, - (bitcnt >> 3) - 1, "rec"); - bcs->hw.tiger.r_err++; - } -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - state = HDLC_FLAG_FOUND; - } - bitcnt = 0; - } else if (r_one == 5) { - val >>= 1; - r_one = 0; - continue; - } else { - r_val >>= 1; - r_val &= 0x7f; - bitcnt++; - } - r_one = 0; - } - if ((state == HDLC_FRAME_FOUND) && - !(bitcnt & 7)) { - if ((bitcnt >> 3) >= HSCX_BUFMAX) { - debugl1(bcs->cs, "tiger: frame too big"); - r_val = 0; - state = HDLC_FLAG_SEARCH; - bcs->hw.tiger.r_err++; -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - } else { - bcs->hw.tiger.rcvbuf[(bitcnt >> 3) - 1] = r_val; - bcs->hw.tiger.r_fcs = - PPP_FCS(bcs->hw.tiger.r_fcs, r_val); - } - } - } - val >>= 1; - } - bcs->hw.tiger.r_tot++; - } - bcs->hw.tiger.r_state = state; - bcs->hw.tiger.r_one = r_one; - bcs->hw.tiger.r_val = r_val; - bcs->hw.tiger.r_bitcnt = bitcnt; -} - -void read_tiger(struct IsdnCardState *cs) { - u_int *p; - int cnt = NETJET_DMA_RXSIZE / 2; - - if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) { - debugl1(cs, "tiger warn read double dma %x/%x", - cs->hw.njet.irqstat0, cs->hw.njet.last_is0); -#ifdef ERROR_STATISTIC - if (cs->bcs[0].mode) - cs->bcs[0].err_rdo++; - if (cs->bcs[1].mode) - cs->bcs[1].err_rdo++; -#endif - return; - } else { - cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ; - cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ); - } - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1) - p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1; - else - p = cs->bcs[0].hw.tiger.rec + cnt - 1; - if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) - read_raw(cs->bcs, p, cnt); - - if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) - read_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ; -} - -static void write_raw(struct BCState *bcs, u_int *buf, int cnt); - -void netjet_fill_dma(struct BCState *bcs) -{ - register u_int *p, *sp; - register int cnt; - - if (!bcs->tx_skb) - return; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger fill_dma1: c%d %4lx", bcs->channel, - bcs->Flag); - if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) - return; - if (bcs->mode == L1_MODE_HDLC) { // it's 64k - if (make_raw_data(bcs)) - return; - } - else { // it's 56k - if (make_raw_data_56k(bcs)) - return; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger fill_dma2: c%d %4lx", bcs->channel, - bcs->Flag); - if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { - write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); - } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { - p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); - sp = bcs->hw.tiger.sendp; - if (p == bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send - 1; - if (sp == bcs->hw.tiger.s_end) - sp = bcs->hw.tiger.send - 1; - cnt = p - sp; - if (cnt < 0) { - write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); - } else { - p++; - cnt++; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - p++; - cnt++; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - write_raw(bcs, p, bcs->hw.tiger.free - cnt); - } - } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) { - p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); - cnt = bcs->hw.tiger.s_end - p; - if (cnt < 2) { - p = bcs->hw.tiger.send + 1; - cnt = NETJET_DMA_TXSIZE / 2 - 2; - } else { - p++; - p++; - if (cnt <= (NETJET_DMA_TXSIZE / 2)) - cnt += NETJET_DMA_TXSIZE / 2; - cnt--; - cnt--; - } - write_raw(bcs, p, cnt); - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger fill_dma3: c%d %4lx", bcs->channel, - bcs->Flag); -} - -static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { - u_int mask, val, *p = buf; - u_int i, s_cnt; - - if (cnt <= 0) - return; - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { - if (bcs->hw.tiger.sendcnt > cnt) { - s_cnt = cnt; - bcs->hw.tiger.sendcnt -= cnt; - } else { - s_cnt = bcs->hw.tiger.sendcnt; - bcs->hw.tiger.sendcnt = 0; - } - if (bcs->channel) - mask = 0xffff00ff; - else - mask = 0xffffff00; - for (i = 0; i < s_cnt; i++) { - val = bcs->channel ? ((bcs->hw.tiger.sp[i] << 8) & 0xff00) : - (bcs->hw.tiger.sp[i]); - *p &= mask; - *p++ |= val; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - } - bcs->hw.tiger.s_tot += s_cnt; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: c%d %p-%p %d/%d %d %x", bcs->channel, - buf, p, s_cnt, cnt, - bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0); - if (bcs->cs->debug & L1_DEB_HSCX_FIFO) - printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd"); - bcs->hw.tiger.sp += s_cnt; - bcs->hw.tiger.sendp = p; - if (!bcs->hw.tiger.sendcnt) { - if (!bcs->tx_skb) { - debugl1(bcs->cs, "tiger write_raw: NULL skb s_cnt %d", s_cnt); - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.tiger.free = cnt - s_cnt; - if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE / 2)) - test_and_set_bit(BC_FLG_HALF, &bcs->Flag); - else { - test_and_clear_bit(BC_FLG_HALF, &bcs->Flag); - test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - netjet_fill_dma(bcs); - } else { - mask ^= 0xffffffff; - if (s_cnt < cnt) { - for (i = s_cnt; i < cnt; i++) { - *p++ |= mask; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: fill rest %d", - cnt - s_cnt); - } - test_and_set_bit(B_XMTBUFREADY, &bcs->event); - schedule_work(&bcs->tqueue); - } - } - } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { - test_and_set_bit(BC_FLG_HALF, &bcs->Flag); - fill_mem(bcs, buf, cnt, bcs->channel, 0xff); - bcs->hw.tiger.free += cnt; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: fill half"); - } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { - test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); - fill_mem(bcs, buf, cnt, bcs->channel, 0xff); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: fill full"); - } -} - -void write_tiger(struct IsdnCardState *cs) { - u_int *p, cnt = NETJET_DMA_TXSIZE / 2; - - if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { - debugl1(cs, "tiger warn write double dma %x/%x", - cs->hw.njet.irqstat0, cs->hw.njet.last_is0); -#ifdef ERROR_STATISTIC - if (cs->bcs[0].mode) - cs->bcs[0].err_tx++; - if (cs->bcs[1].mode) - cs->bcs[1].err_tx++; -#endif - return; - } else { - cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE; - cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE); - } - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1) - p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; - else - p = cs->bcs[0].hw.tiger.send + cnt - 1; - if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) - write_raw(cs->bcs, p, cnt); - if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) - write_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE; -} - -static void -tiger_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n"); - } else { - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_tiger(bcs, st->l1.mode, st->l1.bc); - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ - spin_unlock_irqrestore(&bcs->cs->lock, flags); - bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc)); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ - bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc)); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_tiger(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - - -static void -close_tigerstate(struct BCState *bcs) -{ - mode_tiger(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.tiger.rcvbuf); - bcs->hw.tiger.rcvbuf = NULL; - kfree(bcs->hw.tiger.sendbuf); - bcs->hw.tiger.sendbuf = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for tiger.rcvbuf\n"); - return (1); - } - if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for tiger.sendbuf\n"); - return (1); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - bcs->hw.tiger.sendcnt = 0; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_tiger(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_tigerstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = tiger_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - - -void -inittiger(struct IsdnCardState *cs) -{ - cs->bcs[0].hw.tiger.send = kmalloc_array(NETJET_DMA_TXSIZE, - sizeof(unsigned int), - GFP_KERNEL | GFP_DMA); - if (!cs->bcs[0].hw.tiger.send) { - printk(KERN_WARNING - "HiSax: No memory for tiger.send\n"); - return; - } - cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE / 2 - 1; - cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; - cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send; - cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq; - cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; - - memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int)); - debugl1(cs, "tiger: send buf %p - %p", cs->bcs[0].hw.tiger.send, - cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1); - outl(virt_to_bus(cs->bcs[0].hw.tiger.send), - cs->hw.njet.base + NETJET_DMA_READ_START); - outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq), - cs->hw.njet.base + NETJET_DMA_READ_IRQ); - outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end), - cs->hw.njet.base + NETJET_DMA_READ_END); - cs->bcs[0].hw.tiger.rec = kmalloc_array(NETJET_DMA_RXSIZE, - sizeof(unsigned int), - GFP_KERNEL | GFP_DMA); - if (!cs->bcs[0].hw.tiger.rec) { - printk(KERN_WARNING - "HiSax: No memory for tiger.rec\n"); - return; - } - debugl1(cs, "tiger: rec buf %p - %p", cs->bcs[0].hw.tiger.rec, - cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1); - cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec; - memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int)); - outl(virt_to_bus(cs->bcs[0].hw.tiger.rec), - cs->hw.njet.base + NETJET_DMA_WRITE_START); - outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE / 2 - 1), - cs->hw.njet.base + NETJET_DMA_WRITE_IRQ); - outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1), - cs->hw.njet.base + NETJET_DMA_WRITE_END); - debugl1(cs, "tiger: dmacfg %x/%x pulse=%d", - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); - cs->hw.njet.last_is0 = 0; - cs->bcs[0].BC_SetStack = setstack_tiger; - cs->bcs[1].BC_SetStack = setstack_tiger; - cs->bcs[0].BC_Close = close_tigerstate; - cs->bcs[1].BC_Close = close_tigerstate; -} - -static void -releasetiger(struct IsdnCardState *cs) -{ - kfree(cs->bcs[0].hw.tiger.send); - cs->bcs[0].hw.tiger.send = NULL; - cs->bcs[1].hw.tiger.send = NULL; - kfree(cs->bcs[0].hw.tiger.rec); - cs->bcs[0].hw.tiger.rec = NULL; - cs->bcs[1].hw.tiger.rec = NULL; -} - -void -release_io_netjet(struct IsdnCardState *cs) -{ - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0); - releasetiger(cs); - release_region(cs->hw.njet.base, 256); -} diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h deleted file mode 100644 index 70590d5d5e64..000000000000 --- a/drivers/isdn/hisax/netjet.h +++ /dev/null @@ -1,69 +0,0 @@ -/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $ - * - * NETjet common header file - * - * Author Karsten Keil - * Copyright by Karsten Keil - * by Matt Henderson, - * Traverse Technologies P/L www.traverse.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define NETJET_CTRL 0x00 -#define NETJET_DMACTRL 0x01 -#define NETJET_AUXCTRL 0x02 -#define NETJET_AUXDATA 0x03 -#define NETJET_IRQMASK0 0x04 -#define NETJET_IRQMASK1 0x05 -#define NETJET_IRQSTAT0 0x06 -#define NETJET_IRQSTAT1 0x07 -#define NETJET_DMA_READ_START 0x08 -#define NETJET_DMA_READ_IRQ 0x0c -#define NETJET_DMA_READ_END 0x10 -#define NETJET_DMA_READ_ADR 0x14 -#define NETJET_DMA_WRITE_START 0x18 -#define NETJET_DMA_WRITE_IRQ 0x1c -#define NETJET_DMA_WRITE_END 0x20 -#define NETJET_DMA_WRITE_ADR 0x24 -#define NETJET_PULSE_CNT 0x28 - -#define NETJET_ISAC_OFF 0xc0 -#define NETJET_ISACIRQ 0x10 -#define NETJET_IRQM0_READ 0x0c -#define NETJET_IRQM0_READ_1 0x04 -#define NETJET_IRQM0_READ_2 0x08 -#define NETJET_IRQM0_WRITE 0x03 -#define NETJET_IRQM0_WRITE_1 0x01 -#define NETJET_IRQM0_WRITE_2 0x02 - -#define NETJET_DMA_TXSIZE 512 -#define NETJET_DMA_RXSIZE 128 - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e - -u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); -void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); -void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); -void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); - -void read_tiger(struct IsdnCardState *cs); -void write_tiger(struct IsdnCardState *cs); - -void netjet_fill_dma(struct BCState *bcs); -void netjet_interrupt(int intno, void *dev_id); -void inittiger(struct IsdnCardState *cs); -void release_io_netjet(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c deleted file mode 100644 index dfbcd2eaa81a..000000000000 --- a/drivers/isdn/hisax/niccy.c +++ /dev/null @@ -1,380 +0,0 @@ -/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and - * compatible (SAGEM cybermodem) - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Dr. Neuhaus and SAGEM for information - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include -#include - -static const char *niccy_revision = "$Revision: 1.21.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ISAC_PCI_DATA 0 -#define HSCX_PCI_DATA 1 -#define ISAC_PCI_ADDR 2 -#define HSCX_PCI_ADDR 3 -#define ISAC_PNP 0 -#define HSCX_PNP 1 - -/* SUB Types */ -#define NICCY_PNP 1 -#define NICCY_PCI 2 - -/* PCI stuff */ -#define PCI_IRQ_CTRL_REG 0x38 -#define PCI_IRQ_ENABLE 0x1f00 -#define PCI_IRQ_DISABLE 0xff0000 -#define PCI_IRQ_ASSERT 0x800000 - -static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return ret; -} - -static inline void readfifo(unsigned int ale, unsigned int adr, u_char off, - u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - -static inline void writereg(unsigned int ale, unsigned int adr, u_char off, - u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void writefifo(unsigned int ale, unsigned int adr, u_char off, - u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset); -} - -static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value); -} - -static void ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); -} - -static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); -} - -static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return readreg(cs->hw.niccy.hscx_ale, - cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)); -} - -static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, - u_char value) -{ - writereg(cs->hw.niccy.hscx_ale, - cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value); -} - -#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t niccy_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->subtyp == NICCY_PCI) { - int ival; - ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - } - val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, - HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, - HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, - 0xFF); - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void release_io_niccy(struct IsdnCardState *cs) -{ - if (cs->subtyp == NICCY_PCI) { - int val; - - val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - val &= PCI_IRQ_DISABLE; - outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - release_region(cs->hw.niccy.cfg_reg, 0x40); - release_region(cs->hw.niccy.isac, 4); - } else { - release_region(cs->hw.niccy.isac, 2); - release_region(cs->hw.niccy.isac_ale, 2); - } -} - -static void niccy_reset(struct IsdnCardState *cs) -{ - if (cs->subtyp == NICCY_PCI) { - int val; - - val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - val |= PCI_IRQ_ENABLE; - outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - } - inithscxisac(cs, 3); -} - -static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - niccy_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - case CARD_RELEASE: - release_io_niccy(cs); - return 0; - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - niccy_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - case CARD_TEST: - return 0; - } - return 0; -} - -#ifdef __ISAPNP__ -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_niccy(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, niccy_revision); - printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NICCY) - return 0; -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d = NULL; - int err; - - pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pnp_c); - if (pnp_c) { - pnp_d = pnp_find_dev(pnp_c, - ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pnp_d); - if (!pnp_d) { - printk(KERN_ERR "NiccyPnP: PnP error card " - "found, no device\n"); - return 0; - } - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev " - "ret(%d)\n", __func__, err); - return 0; - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[2] = pnp_port_start(pnp_d, 1); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1] || - !card->para[2]) { - printk(KERN_ERR "NiccyPnP:some resources are " - "missing %ld/%lx/%lx\n", - card->para[0], card->para[1], - card->para[2]); - pnp_disable_dev(pnp_d); - return 0; - } - } else - printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n"); - } -#endif - if (card->para[1]) { - cs->hw.niccy.isac = card->para[1] + ISAC_PNP; - cs->hw.niccy.hscx = card->para[1] + HSCX_PNP; - cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP; - cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP; - cs->hw.niccy.cfg_reg = 0; - cs->subtyp = NICCY_PNP; - cs->irq = card->para[0]; - if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) { - printk(KERN_WARNING "HiSax: NICCY data port %x-%x " - "already in use\n", - cs->hw.niccy.isac, cs->hw.niccy.isac + 1); - return 0; - } - if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) { - printk(KERN_WARNING "HiSax: NICCY address port %x-%x " - "already in use\n", - cs->hw.niccy.isac_ale, - cs->hw.niccy.isac_ale + 1); - release_region(cs->hw.niccy.isac, 2); - return 0; - } - } else { -#ifdef CONFIG_PCI - static struct pci_dev *niccy_dev; - - u_int pci_ioaddr; - cs->subtyp = 0; - if ((niccy_dev = hisax_find_pci_device(PCI_VENDOR_ID_SATSAGEM, - PCI_DEVICE_ID_SATSAGEM_NICCY, - niccy_dev))) { - if (pci_enable_device(niccy_dev)) - return 0; - /* get IRQ */ - if (!niccy_dev->irq) { - printk(KERN_WARNING - "Niccy: No IRQ for PCI card found\n"); - return 0; - } - cs->irq = niccy_dev->irq; - cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); - if (!cs->hw.niccy.cfg_reg) { - printk(KERN_WARNING - "Niccy: No IO-Adr for PCI cfg found\n"); - return 0; - } - pci_ioaddr = pci_resource_start(niccy_dev, 1); - if (!pci_ioaddr) { - printk(KERN_WARNING - "Niccy: No IO-Adr for PCI card found\n"); - return 0; - } - cs->subtyp = NICCY_PCI; - } else { - printk(KERN_WARNING "Niccy: No PCI card found\n"); - return 0; - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; - cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR; - cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA; - cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; - if (!request_region(cs->hw.niccy.isac, 4, "niccy")) { - printk(KERN_WARNING - "HiSax: NICCY data port %x-%x already in use\n", - cs->hw.niccy.isac, cs->hw.niccy.isac + 4); - return 0; - } - if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) { - printk(KERN_WARNING - "HiSax: NICCY pci port %x-%x already in use\n", - cs->hw.niccy.cfg_reg, - cs->hw.niccy.cfg_reg + 0x40); - release_region(cs->hw.niccy.isac, 4); - return 0; - } -#else - printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n"); - return 0; -#endif /* CONFIG_PCI */ - } - printk(KERN_INFO "HiSax: NICCY %s config irq:%d data:0x%X ale:0x%X\n", - (cs->subtyp == 1) ? "PnP" : "PCI", - cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &niccy_card_msg; - cs->irq_func = &niccy_interrupt; - ISACVersion(cs, "Niccy:"); - if (HscxVersion(cs, "Niccy:")) { - printk(KERN_WARNING "Niccy: wrong HSCX versions check IO " - "address\n"); - release_io_niccy(cs); - return 0; - } - return 1; -} diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c deleted file mode 100644 index 32b4bbd18eb9..000000000000 --- a/drivers/isdn/hisax/nj_s.c +++ /dev/null @@ -1,294 +0,0 @@ -/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include -#include -#include -#include "netjet.h" - -static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $"; - -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return (5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - -static irqreturn_t -netjet_s_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, s1val, s0val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1); - if (!(s1val & NETJET_ISACIRQ)) { - val = NETjet_ReadIC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", s1val, val); - if (val) { - isac_interrupt(cs, val); - NETjet_WriteIC(cs, ISAC_MASK, 0xFF); - NETjet_WriteIC(cs, ISAC_MASK, 0x0); - } - s1val = 1; - } else - s1val = 0; - /* - * read/write stat0 is better, because lower IRQ rate - * Note the IRQ is on for 125 us if a condition match - * thats long on modern CPU and so the IRQ is reentered - * all the time. - */ - s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0); - if ((s0val | s1val) == 0) { // shared IRQ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (s0val) - byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); - /* start new code 13/07/00 GE */ - /* set bits in sval to indicate which page is free */ - if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) - /* the 2nd write page is free */ - s0val = 0x08; - else /* the 1st write page is free */ - s0val = 0x04; - if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) - /* the 2nd read page is free */ - s0val |= 0x02; - else /* the 1st read page is free */ - s0val |= 0x01; - if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ - { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n", - cs->hw.njet.last_is0, s0val); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - cs->hw.njet.irqstat0 = s0val; - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) - /* we have a read dma int */ - read_tiger(cs); - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) - /* we have a write dma int */ - write_tiger(cs); - /* end new code 13/07/00 GE */ - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -reset_netjet_s(struct IsdnCardState *cs) -{ - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - /* now edge triggered for TJ320 GE 13/07/00 */ - /* see comment in IRQ function */ - if (cs->subtyp) /* TJ320 */ - cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ - else - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - cs->hw.njet.auxd = 0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - -static int -NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_netjet_s(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_netjet(cs); - return (0); - case CARD_INIT: - reset_netjet_s(cs); - inittiger(cs); - spin_lock_irqsave(&cs->lock, flags); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int njs_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) -{ - u32 cfg; - - if (pci_enable_device(dev_netjet)) - return (0); - pci_set_master(dev_netjet); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); - return (0); - } - /* the TJ300 and TJ320 must be detected, the IRQ handling is different - * unfortunately the chips use the same device ID, but the TJ320 has - * the bit20 in status PCI cfg register set - */ - pci_read_config_dword(dev_netjet, 0x04, &cfg); - if (cfg & 0x00100000) - cs->subtyp = 1; /* TJ320 */ - else - cs->subtyp = 0; /* TJ300 */ - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */ - if ((dev_netjet->subsystem_vendor == 0x55) && - (dev_netjet->subsystem_device == 0x02)) { - printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n"); - printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n"); - return (0); - } - /* end new code */ - - return (1); -} - -static int njs_cs_init(struct IsdnCard *card, struct IsdnCardState *cs) -{ - - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - - switch (((NETjet_ReadIC(cs, ISAC_RBCH) >> 5) & 3)) - { - case 0: - return 1; /* end loop */ - - case 3: - printk(KERN_WARNING "NETjet-S: NETspider-U PCI card found\n"); - return -1; /* continue looping */ - - default: - printk(KERN_WARNING "NETjet-S: No PCI card found\n"); - return 0; /* end loop & function */ - } - return 1; /* end loop */ -} - -static int njs_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs) -{ - const int bytecnt = 256; - - printk(KERN_INFO - "NETjet-S: %s card configured at %#lx IRQ %d\n", - cs->subtyp ? "TJ320" : "TJ300", cs->hw.njet.base, cs->irq); - if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) { - printk(KERN_WARNING - "HiSax: NETjet-S config port %#lx-%#lx already in use\n", - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } - cs->readisac = &NETjet_ReadIC; - cs->writeisac = &NETjet_WriteIC; - cs->readisacfifo = &NETjet_ReadICfifo; - cs->writeisacfifo = &NETjet_WriteICfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &netjet_fill_dma; - setup_isac(cs); - cs->cardmsg = &NETjet_S_card_msg; - cs->irq_func = &netjet_s_interrupt; - cs->irq_flags |= IRQF_SHARED; - ISACVersion(cs, "NETjet-S:"); - - return (1); -} - -static struct pci_dev *dev_netjet = NULL; - -int setup_netjet_s(struct IsdnCard *card) -{ - int ret; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif - strcpy(tmp, NETjet_S_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET_S) - return (0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - - for (;;) - { - if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { - ret = njs_pci_probe(dev_netjet, cs); - if (!ret) - return (0); - } else { - printk(KERN_WARNING "NETjet-S: No PCI card found\n"); - return (0); - } - - ret = njs_cs_init(card, cs); - if (!ret) - return (0); - if (ret > 0) - break; - /* otherwise, ret < 0, continue looping */ - } - - return njs_cs_init_rest(card, cs); -} diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c deleted file mode 100644 index 4e8adbede361..000000000000 --- a/drivers/isdn/hisax/nj_u.c +++ /dev/null @@ -1,258 +0,0 @@ -/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "icc.h" -#include "isdnl1.h" -#include -#include -#include -#include "netjet.h" - -static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $"; - -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return (5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - -static irqreturn_t -netjet_u_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { - val = NETjet_ReadIC(cs, ICC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); - if (val) { - icc_interrupt(cs, val); - NETjet_WriteIC(cs, ICC_MASK, 0xFF); - NETjet_WriteIC(cs, ICC_MASK, 0x0); - } - } - /* start new code 13/07/00 GE */ - /* set bits in sval to indicate which page is free */ - if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) - /* the 2nd write page is free */ - sval = 0x08; - else /* the 1st write page is free */ - sval = 0x04; - if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) - /* the 2nd read page is free */ - sval = sval | 0x02; - else /* the 1st read page is free */ - sval = sval | 0x01; - if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */ - { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - cs->hw.njet.irqstat0 = sval; - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) - /* we have a read dma int */ - read_tiger(cs); - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) - /* we have a write dma int */ - write_tiger(cs); - /* end new code 13/07/00 GE */ - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -reset_netjet_u(struct IsdnCardState *cs) -{ - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ - /* now edge triggered for TJ320 GE 13/07/00 */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.auxa, 0); - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - -static int -NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_netjet_u(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_netjet(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inittiger(cs); - reset_netjet_u(cs); - clear_pending_icc_ints(cs); - initicc(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ICC_MASK, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int nju_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) -{ - if (pci_enable_device(dev_netjet)) - return (0); - pci_set_master(dev_netjet); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); - return (0); - } - - return (1); -} - -static int nju_cs_init(struct IsdnCard *card, struct IsdnCardState *cs) -{ - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - mdelay(10); - - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - - byteout(cs->hw.njet.auxa, 0); - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - - switch (((NETjet_ReadIC(cs, ICC_RBCH) >> 5) & 3)) - { - case 3: - return 1; /* end loop */ - - case 0: - printk(KERN_WARNING "NETspider-U: NETjet-S PCI card found\n"); - return -1; /* continue looping */ - - default: - printk(KERN_WARNING "NETspider-U: No PCI card found\n"); - return 0; /* end loop & function */ - } - return 1; /* end loop */ -} - -static int nju_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs) -{ - const int bytecnt = 256; - - printk(KERN_INFO - "NETspider-U: PCI card configured at %#lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) { - printk(KERN_WARNING - "HiSax: NETspider-U config port %#lx-%#lx " - "already in use\n", - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } - setup_icc(cs); - cs->readisac = &NETjet_ReadIC; - cs->writeisac = &NETjet_WriteIC; - cs->readisacfifo = &NETjet_ReadICfifo; - cs->writeisacfifo = &NETjet_WriteICfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &netjet_fill_dma; - cs->cardmsg = &NETjet_U_card_msg; - cs->irq_func = &netjet_u_interrupt; - cs->irq_flags |= IRQF_SHARED; - ICCVersion(cs, "NETspider-U:"); - - return (1); -} - -static struct pci_dev *dev_netjet = NULL; - -int setup_netjet_u(struct IsdnCard *card) -{ - int ret; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif - - strcpy(tmp, NETjet_U_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET_U) - return (0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - - for (;;) - { - if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { - ret = nju_pci_probe(dev_netjet, cs); - if (!ret) - return (0); - } else { - printk(KERN_WARNING "NETspider-U: No PCI card found\n"); - return (0); - } - - ret = nju_cs_init(card, cs); - if (!ret) - return (0); - if (ret > 0) - break; - /* ret < 0 == continue looping */ - } - - return nju_cs_init_rest(card, cs); -} diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c deleted file mode 100644 index 6b8c3fbe3965..000000000000 --- a/drivers/isdn/hisax/q931.c +++ /dev/null @@ -1,1513 +0,0 @@ -/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $ - * - * code to decode ITU Q.931 call control messages - * - * Author Jan den Ouden - * Copyright by Jan den Ouden - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Changelog: - * - * Pauline Middelink general improvements - * Beat Doebeli cause texts, display information element - * Karsten Keil cause texts, display information element for 1TR6 - * - */ - - -#include "hisax.h" -#include "l3_1tr6.h" - -void -iecpy(u_char *dest, u_char *iestart, int ieoffset) -{ - u_char *p; - int l; - - p = iestart + ieoffset + 2; - l = iestart[1] - ieoffset; - while (l--) - *dest++ = *p++; - *dest++ = '\0'; -} - -/* - * According to Table 4-2/Q.931 - */ -static -struct MessageType { - u_char nr; - char *descr; -} mtlist[] = { - - { - 0x1, "ALERTING" - }, - { - 0x2, "CALL PROCEEDING" - }, - { - 0x7, "CONNECT" - }, - { - 0xf, "CONNECT ACKNOWLEDGE" - }, - { - 0x3, "PROGRESS" - }, - { - 0x5, "SETUP" - }, - { - 0xd, "SETUP ACKNOWLEDGE" - }, - { - 0x24, "HOLD" - }, - { - 0x28, "HOLD ACKNOWLEDGE" - }, - { - 0x30, "HOLD REJECT" - }, - { - 0x31, "RETRIEVE" - }, - { - 0x33, "RETRIEVE ACKNOWLEDGE" - }, - { - 0x37, "RETRIEVE REJECT" - }, - { - 0x26, "RESUME" - }, - { - 0x2e, "RESUME ACKNOWLEDGE" - }, - { - 0x22, "RESUME REJECT" - }, - { - 0x25, "SUSPEND" - }, - { - 0x2d, "SUSPEND ACKNOWLEDGE" - }, - { - 0x21, "SUSPEND REJECT" - }, - { - 0x20, "USER INFORMATION" - }, - { - 0x45, "DISCONNECT" - }, - { - 0x4d, "RELEASE" - }, - { - 0x5a, "RELEASE COMPLETE" - }, - { - 0x46, "RESTART" - }, - { - 0x4e, "RESTART ACKNOWLEDGE" - }, - { - 0x60, "SEGMENT" - }, - { - 0x79, "CONGESTION CONTROL" - }, - { - 0x7b, "INFORMATION" - }, - { - 0x62, "FACILITY" - }, - { - 0x6e, "NOTIFY" - }, - { - 0x7d, "STATUS" - }, - { - 0x75, "STATUS ENQUIRY" - } -}; - -#define MTSIZE ARRAY_SIZE(mtlist) - -static -struct MessageType mt_n0[] = -{ - {MT_N0_REG_IND, "REGister INDication"}, - {MT_N0_CANC_IND, "CANCel INDication"}, - {MT_N0_FAC_STA, "FACility STAtus"}, - {MT_N0_STA_ACK, "STAtus ACKnowledge"}, - {MT_N0_STA_REJ, "STAtus REJect"}, - {MT_N0_FAC_INF, "FACility INFormation"}, - {MT_N0_INF_ACK, "INFormation ACKnowledge"}, - {MT_N0_INF_REJ, "INFormation REJect"}, - {MT_N0_CLOSE, "CLOSE"}, - {MT_N0_CLO_ACK, "CLOse ACKnowledge"} -}; - -#define MT_N0_LEN ARRAY_SIZE(mt_n0) - -static -struct MessageType mt_n1[] = -{ - {MT_N1_ESC, "ESCape"}, - {MT_N1_ALERT, "ALERT"}, - {MT_N1_CALL_SENT, "CALL SENT"}, - {MT_N1_CONN, "CONNect"}, - {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, - {MT_N1_SETUP, "SETUP"}, - {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, - {MT_N1_RES, "RESume"}, - {MT_N1_RES_ACK, "RESume ACKnowledge"}, - {MT_N1_RES_REJ, "RESume REJect"}, - {MT_N1_SUSP, "SUSPend"}, - {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, - {MT_N1_SUSP_REJ, "SUSPend REJect"}, - {MT_N1_USER_INFO, "USER INFO"}, - {MT_N1_DET, "DETach"}, - {MT_N1_DISC, "DISConnect"}, - {MT_N1_REL, "RELease"}, - {MT_N1_REL_ACK, "RELease ACKnowledge"}, - {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, - {MT_N1_CANC_REJ, "CANCel REJect"}, - {MT_N1_CON_CON, "CONgestion CONtrol"}, - {MT_N1_FAC, "FACility"}, - {MT_N1_FAC_ACK, "FACility ACKnowledge"}, - {MT_N1_FAC_CAN, "FACility CANcel"}, - {MT_N1_FAC_REG, "FACility REGister"}, - {MT_N1_FAC_REJ, "FACility REJect"}, - {MT_N1_INFO, "INFOrmation"}, - {MT_N1_REG_ACK, "REGister ACKnowledge"}, - {MT_N1_REG_REJ, "REGister REJect"}, - {MT_N1_STAT, "STATus"} -}; - -#define MT_N1_LEN ARRAY_SIZE(mt_n1) - - -static int -prbits(char *dest, u_char b, int start, int len) -{ - char *dp = dest; - - b = b << (8 - start); - while (len--) { - if (b & 0x80) - *dp++ = '1'; - else - *dp++ = '0'; - b = b << 1; - } - return (dp - dest); -} - -static -u_char * -skipext(u_char *p) -{ - while (!(*p++ & 0x80)); - return (p); -} - -/* - * Cause Values According to Q.850 - * edescr: English description - * ddescr: German description used by Swissnet II (Swiss Telecom - * not yet written... - */ - -static -struct CauseValue { - u_char nr; - char *edescr; - char *ddescr; -} cvlist[] = { - - { - 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt" - }, - { - 0x02, "No route to specified transit network", "" - }, - { - 0x03, "No route to destination", "" - }, - { - 0x04, "Send special information tone", "" - }, - { - 0x05, "Misdialled trunk prefix", "" - }, - { - 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar" - }, - { - 0x07, "Channel awarded and being delivered in an established channel", "" - }, - { - 0x08, "Preemption", "" - }, - { - 0x09, "Preemption - circuit reserved for reuse", "" - }, - { - 0x10, "Normal call clearing", "Normale Ausloesung" - }, - { - 0x11, "User busy", "TNB besetzt" - }, - { - 0x12, "No user responding", "" - }, - { - 0x13, "No answer from user (user alerted)", "" - }, - { - 0x14, "Subscriber absent", "" - }, - { - 0x15, "Call rejected", "" - }, - { - 0x16, "Number changed", "" - }, - { - 0x1a, "non-selected user clearing", "" - }, - { - 0x1b, "Destination out of order", "" - }, - { - 0x1c, "Invalid number format (address incomplete)", "" - }, - { - 0x1d, "Facility rejected", "" - }, - { - 0x1e, "Response to Status enquiry", "" - }, - { - 0x1f, "Normal, unspecified", "" - }, - { - 0x22, "No circuit/channel available", "" - }, - { - 0x26, "Network out of order", "" - }, - { - 0x27, "Permanent frame mode connection out-of-service", "" - }, - { - 0x28, "Permanent frame mode connection operational", "" - }, - { - 0x29, "Temporary failure", "" - }, - { - 0x2a, "Switching equipment congestion", "" - }, - { - 0x2b, "Access information discarded", "" - }, - { - 0x2c, "Requested circuit/channel not available", "" - }, - { - 0x2e, "Precedence call blocked", "" - }, - { - 0x2f, "Resource unavailable, unspecified", "" - }, - { - 0x31, "Quality of service unavailable", "" - }, - { - 0x32, "Requested facility not subscribed", "" - }, - { - 0x35, "Outgoing calls barred within CUG", "" - }, - { - 0x37, "Incoming calls barred within CUG", "" - }, - { - 0x39, "Bearer capability not authorized", "" - }, - { - 0x3a, "Bearer capability not presently available", "" - }, - { - 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " " - }, - { - 0x3f, "Service or option not available, unspecified", "" - }, - { - 0x41, "Bearer capability not implemented", "" - }, - { - 0x42, "Channel type not implemented", "" - }, - { - 0x43, "Requested facility not implemented", "" - }, - { - 0x44, "Only restricted digital information bearer capability is available", "" - }, - { - 0x4f, "Service or option not implemented", "" - }, - { - 0x51, "Invalid call reference value", "" - }, - { - 0x52, "Identified channel does not exist", "" - }, - { - 0x53, "A suspended call exists, but this call identity does not", "" - }, - { - 0x54, "Call identity in use", "" - }, - { - 0x55, "No call suspended", "" - }, - { - 0x56, "Call having the requested call identity has been cleared", "" - }, - { - 0x57, "User not member of CUG", "" - }, - { - 0x58, "Incompatible destination", "" - }, - { - 0x5a, "Non-existent CUG", "" - }, - { - 0x5b, "Invalid transit network selection", "" - }, - { - 0x5f, "Invalid message, unspecified", "" - }, - { - 0x60, "Mandatory information element is missing", "" - }, - { - 0x61, "Message type non-existent or not implemented", "" - }, - { - 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " " - }, - { - 0x63, "Information element/parameter non-existent or not implemented", "" - }, - { - 0x64, "Invalid information element contents", "" - }, - { - 0x65, "Message not compatible with call state", "" - }, - { - 0x66, "Recovery on timer expiry", "" - }, - { - 0x67, "Parameter non-existent or not implemented - passed on", "" - }, - { - 0x6e, "Message with unrecognized parameter discarded", "" - }, - { - 0x6f, "Protocol error, unspecified", "" - }, - { - 0x7f, "Interworking, unspecified", "" - }, -}; - -#define CVSIZE ARRAY_SIZE(cvlist) - -static -int -prcause(char *dest, u_char *p) -{ - u_char *end; - char *dp = dest; - int i, cause; - - end = p + p[1] + 1; - p += 2; - dp += sprintf(dp, " coding "); - dp += prbits(dp, *p, 7, 2); - dp += sprintf(dp, " location "); - dp += prbits(dp, *p, 4, 4); - *dp++ = '\n'; - p = skipext(p); - - cause = 0x7f & *p++; - - /* locate cause value */ - for (i = 0; i < CVSIZE; i++) - if (cvlist[i].nr == cause) - break; - - /* display cause value if it exists */ - if (i == CVSIZE) - dp += sprintf(dp, "Unknown cause type %x!\n", cause); - else - dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); - - while (!0) { - if (p > end) - break; - dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f); - dp += sprintf(dp, " rej %d ", *p & 0x7f); - if (*p & 0x80) { - *dp++ = '\n'; - break; - } else - dp += sprintf(dp, " av %d\n", (*++p) & 0x7f); - } - return (dp - dest); - -} - -static -struct MessageType cause_1tr6[] = -{ - {CAUSE_InvCRef, "Invalid Call Reference"}, - {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, - {CAUSE_CIDunknown, "Caller Identity unknown"}, - {CAUSE_CIDinUse, "Caller Identity in Use"}, - {CAUSE_NoChans, "No Channels available"}, - {CAUSE_FacNotImpl, "Facility Not Implemented"}, - {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, - {CAUSE_OutgoingBarred, "Outgoing calls barred"}, - {CAUSE_UserAccessBusy, "User Access Busy"}, - {CAUSE_NegativeGBG, "Negative GBG"}, - {CAUSE_UnknownGBG, "Unknown GBG"}, - {CAUSE_NoSPVknown, "No SPV known"}, - {CAUSE_DestNotObtain, "Destination not obtainable"}, - {CAUSE_NumberChanged, "Number changed"}, - {CAUSE_OutOfOrder, "Out Of Order"}, - {CAUSE_NoUserResponse, "No User Response"}, - {CAUSE_UserBusy, "User Busy"}, - {CAUSE_IncomingBarred, "Incoming Barred"}, - {CAUSE_CallRejected, "Call Rejected"}, - {CAUSE_NetworkCongestion, "Network Congestion"}, - {CAUSE_RemoteUser, "Remote User initiated"}, - {CAUSE_LocalProcErr, "Local Procedure Error"}, - {CAUSE_RemoteProcErr, "Remote Procedure Error"}, - {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, - {CAUSE_RemoteUserResumed, "Remote User Resumed"}, - {CAUSE_UserInfoDiscarded, "User Info Discarded"} -}; - -static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); - -static int -prcause_1tr6(char *dest, u_char *p) -{ - char *dp = dest; - int i, cause; - - p++; - if (0 == *p) { - dp += sprintf(dp, " OK (cause length=0)\n"); - return (dp - dest); - } else if (*p > 1) { - dp += sprintf(dp, " coding "); - dp += prbits(dp, p[2], 7, 2); - dp += sprintf(dp, " location "); - dp += prbits(dp, p[2], 4, 4); - *dp++ = '\n'; - } - p++; - cause = 0x7f & *p; - - /* locate cause value */ - for (i = 0; i < cause_1tr6_len; i++) - if (cause_1tr6[i].nr == cause) - break; - - /* display cause value if it exists */ - if (i == cause_1tr6_len) - dp += sprintf(dp, "Unknown cause type %x!\n", cause); - else - dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); - - return (dp - dest); - -} - -static int -prchident(char *dest, u_char *p) -{ - char *dp = dest; - - p += 2; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - return (dp - dest); -} - -static int -prcalled(char *dest, u_char *p) -{ - int l; - char *dp = dest; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - dp += sprintf(dp, " number digits "); - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -prcalling(char *dest, u_char *p) -{ - int l; - char *dp = dest; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (!(*p & 0x80)) { - dp += sprintf(dp, " octet 3a "); - dp += prbits(dp, *++p, 8, 8); - *dp++ = '\n'; - l--; - } - p++; - - dp += sprintf(dp, " number digits "); - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} - -static -int -prbearer(char *dest, u_char *p) -{ - char *dp = dest, ch; - - p += 2; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if ((*p++ & 0x1f) == 0x18) { - dp += sprintf(dp, " octet 4.1 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - /* check for user information layer 1 */ - if ((*p & 0x60) == 0x20) { - ch = ' '; - do { - dp += sprintf(dp, " octet 5%c ", ch); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (ch == ' ') - ch = 'a'; - else - ch++; - } - while (!(*p++ & 0x80)); - } - /* check for user information layer 2 */ - if ((*p & 0x60) == 0x40) { - dp += sprintf(dp, " octet 6 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - /* check for user information layer 3 */ - if ((*p & 0x60) == 0x60) { - dp += sprintf(dp, " octet 7 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - return (dp - dest); -} - - -static -int -prbearer_ni1(char *dest, u_char *p) -{ - char *dp = dest; - u_char len; - - p++; - len = *p++; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - switch (*p++) { - case 0x80: - dp += sprintf(dp, " Speech"); - break; - case 0x88: - dp += sprintf(dp, " Unrestricted digital information"); - break; - case 0x90: - dp += sprintf(dp, " 3.1 kHz audio"); - break; - default: - dp += sprintf(dp, " Unknown information-transfer capability"); - } - *dp++ = '\n'; - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p, 8, 8); - switch (*p++) { - case 0x90: - dp += sprintf(dp, " 64 kbps, circuit mode"); - break; - case 0xc0: - dp += sprintf(dp, " Packet mode"); - break; - default: - dp += sprintf(dp, " Unknown transfer mode"); - } - *dp++ = '\n'; - if (len > 2) { - dp += sprintf(dp, " octet 5 "); - dp += prbits(dp, *p, 8, 8); - switch (*p++) { - case 0x21: - dp += sprintf(dp, " Rate adaption\n"); - dp += sprintf(dp, " octet 5a "); - dp += prbits(dp, *p, 8, 8); - break; - case 0xa2: - dp += sprintf(dp, " u-law"); - break; - default: - dp += sprintf(dp, " Unknown UI layer 1 protocol"); - } - *dp++ = '\n'; - } - return (dp - dest); -} - -static int -general(char *dest, u_char *p) -{ - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the information element */ - while (l--) { - dp += sprintf(dp, " octet %d%c ", octet, ch); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - - /* last octet in group? */ - if (*p & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - else - ch++; - } - return (dp - dest); -} - -static int -general_ni1(char *dest, u_char *p) -{ - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the information element */ - while (l--) { - dp += sprintf(dp, " octet %d%c ", octet, ch); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - - /* last octet in group? */ - if (*p++ & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - else - ch++; - } - return (dp - dest); -} - -static int -prcharge(char *dest, u_char *p) -{ - char *dp = dest; - int l; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " GEA "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, " Anzahl: "); - /* Iterate over all octets in the * information element */ - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -prtext(char *dest, u_char *p) -{ - char *dp = dest; - int l; - - p++; - l = *p++; - dp += sprintf(dp, " "); - /* Iterate over all octets in the * information element */ - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} - -static int -prfeatureind(char *dest, u_char *p) -{ - char *dp = dest; - - p += 2; /* skip id, len */ - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (!(*p++ & 0x80)) { - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - dp += sprintf(dp, " Status: "); - switch (*p) { - case 0: - dp += sprintf(dp, "Idle"); - break; - case 1: - dp += sprintf(dp, "Active"); - break; - case 2: - dp += sprintf(dp, "Prompt"); - break; - case 3: - dp += sprintf(dp, "Pending"); - break; - default: - dp += sprintf(dp, "(Reserved)"); - break; - } - *dp++ = '\n'; - return (dp - dest); -} - -static -struct DTag { /* Display tags */ - u_char nr; - char *descr; -} dtaglist[] = { - { 0x82, "Continuation" }, - { 0x83, "Called address" }, - { 0x84, "Cause" }, - { 0x85, "Progress indicator" }, - { 0x86, "Notification indicator" }, - { 0x87, "Prompt" }, - { 0x88, "Accumlated digits" }, - { 0x89, "Status" }, - { 0x8a, "Inband" }, - { 0x8b, "Calling address" }, - { 0x8c, "Reason" }, - { 0x8d, "Calling party name" }, - { 0x8e, "Called party name" }, - { 0x8f, "Original called name" }, - { 0x90, "Redirecting name" }, - { 0x91, "Connected name" }, - { 0x92, "Originating restrictions" }, - { 0x93, "Date & time of day" }, - { 0x94, "Call Appearance ID" }, - { 0x95, "Feature address" }, - { 0x96, "Redirection name" }, - { 0x9e, "Text" }, -}; -#define DTAGSIZE ARRAY_SIZE(dtaglist) - -static int -disptext_ni1(char *dest, u_char *p) -{ - char *dp = dest; - int l, tag, len, i; - - p++; - l = *p++ - 1; - if (*p++ != 0x80) { - dp += sprintf(dp, " Unknown display type\n"); - return (dp - dest); - } - /* Iterate over all tag,length,text fields */ - while (l > 0) { - tag = *p++; - len = *p++; - l -= len + 2; - /* Don't space or skip */ - if ((tag == 0x80) || (tag == 0x81)) p++; - else { - for (i = 0; i < DTAGSIZE; i++) - if (tag == dtaglist[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != DTAGSIZE) { - dp += sprintf(dp, " %s: ", dtaglist[i].descr); - while (len--) - *dp++ = *p++; - } else { - dp += sprintf(dp, " (unknown display tag %2x): ", tag); - while (len--) - *dp++ = *p++; - } - dp += sprintf(dp, "\n"); - } - } - return (dp - dest); -} -static int -display(char *dest, u_char *p) -{ - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the * display-information element */ - dp += sprintf(dp, " \""); - while (l--) { - dp += sprintf(dp, "%c", *p++); - - /* last octet in group? */ - if (*p & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - - else - ch++; - } - *dp++ = '\"'; - *dp++ = '\n'; - return (dp - dest); -} - -static int -prfacility(char *dest, u_char *p) -{ - char *dp = dest; - int l, l2; - - p++; - l = *p++; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, "\n"); - l -= 1; - - while (l > 0) { - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, "\n"); - dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f); - l -= 2; - dp += sprintf(dp, " contents "); - while (l2--) { - dp += sprintf(dp, "%2x ", *p++); - l--; - } - dp += sprintf(dp, "\n"); - } - - return (dp - dest); -} - -static -struct InformationElement { - u_char nr; - char *descr; - int (*f) (char *, u_char *); -} ielist[] = { - - { - 0x00, "Segmented message", general - }, - { - 0x04, "Bearer capability", prbearer - }, - { - 0x08, "Cause", prcause - }, - { - 0x10, "Call identity", general - }, - { - 0x14, "Call state", general - }, - { - 0x18, "Channel identification", prchident - }, - { - 0x1c, "Facility", prfacility - }, - { - 0x1e, "Progress indicator", general - }, - { - 0x20, "Network-specific facilities", general - }, - { - 0x27, "Notification indicator", general - }, - { - 0x28, "Display", display - }, - { - 0x29, "Date/Time", general - }, - { - 0x2c, "Keypad facility", general - }, - { - 0x34, "Signal", general - }, - { - 0x40, "Information rate", general - }, - { - 0x42, "End-to-end delay", general - }, - { - 0x43, "Transit delay selection and indication", general - }, - { - 0x44, "Packet layer binary parameters", general - }, - { - 0x45, "Packet layer window size", general - }, - { - 0x46, "Packet size", general - }, - { - 0x47, "Closed user group", general - }, - { - 0x4a, "Reverse charge indication", general - }, - { - 0x6c, "Calling party number", prcalling - }, - { - 0x6d, "Calling party subaddress", general - }, - { - 0x70, "Called party number", prcalled - }, - { - 0x71, "Called party subaddress", general - }, - { - 0x74, "Redirecting number", general - }, - { - 0x78, "Transit network selection", general - }, - { - 0x79, "Restart indicator", general - }, - { - 0x7c, "Low layer compatibility", general - }, - { - 0x7d, "High layer compatibility", general - }, - { - 0x7e, "User-user", general - }, - { - 0x7f, "Escape for extension", general - }, -}; - - -#define IESIZE ARRAY_SIZE(ielist) - -static -struct InformationElement ielist_ni1[] = { - { 0x04, "Bearer Capability", prbearer_ni1 }, - { 0x08, "Cause", prcause }, - { 0x14, "Call State", general_ni1 }, - { 0x18, "Channel Identification", prchident }, - { 0x1e, "Progress Indicator", general_ni1 }, - { 0x27, "Notification Indicator", general_ni1 }, - { 0x2c, "Keypad Facility", prtext }, - { 0x32, "Information Request", general_ni1 }, - { 0x34, "Signal", general_ni1 }, - { 0x38, "Feature Activation", general_ni1 }, - { 0x39, "Feature Indication", prfeatureind }, - { 0x3a, "Service Profile Identification (SPID)", prtext }, - { 0x3b, "Endpoint Identifier", general_ni1 }, - { 0x6c, "Calling Party Number", prcalling }, - { 0x6d, "Calling Party Subaddress", general_ni1 }, - { 0x70, "Called Party Number", prcalled }, - { 0x71, "Called Party Subaddress", general_ni1 }, - { 0x74, "Redirecting Number", general_ni1 }, - { 0x78, "Transit Network Selection", general_ni1 }, - { 0x7c, "Low Layer Compatibility", general_ni1 }, - { 0x7d, "High Layer Compatibility", general_ni1 }, -}; - - -#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) - -static -struct InformationElement ielist_ni1_cs5[] = { - { 0x1d, "Operator system access", general_ni1 }, - { 0x2a, "Display text", disptext_ni1 }, -}; - -#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) - -static -struct InformationElement ielist_ni1_cs6[] = { - { 0x7b, "Call appearance", general_ni1 }, -}; - -#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) - -static struct InformationElement we_0[] = -{ - {WE0_cause, "Cause", prcause_1tr6}, - {WE0_connAddr, "Connecting Address", prcalled}, - {WE0_callID, "Call IDentity", general}, - {WE0_chanID, "Channel IDentity", general}, - {WE0_netSpecFac, "Network Specific Facility", general}, - {WE0_display, "Display", general}, - {WE0_keypad, "Keypad", general}, - {WE0_origAddr, "Origination Address", prcalled}, - {WE0_destAddr, "Destination Address", prcalled}, - {WE0_userInfo, "User Info", general} -}; - -#define WE_0_LEN ARRAY_SIZE(we_0) - -static struct InformationElement we_6[] = -{ - {WE6_serviceInd, "Service Indicator", general}, - {WE6_chargingInfo, "Charging Information", prcharge}, - {WE6_date, "Date", prtext}, - {WE6_facSelect, "Facility Select", general}, - {WE6_facStatus, "Facility Status", general}, - {WE6_statusCalled, "Status Called", general}, - {WE6_addTransAttr, "Additional Transmission Attributes", general} -}; -#define WE_6_LEN ARRAY_SIZE(we_6) - -int -QuickHex(char *txt, u_char *p, int cnt) -{ - register int i; - register char *t = txt; - - for (i = 0; i < cnt; i++) { - *t++ = ' '; - *t++ = hex_asc_hi(p[i]); - *t++ = hex_asc_lo(p[i]); - } - *t++ = 0; - return (t - txt); -} - -void -LogFrame(struct IsdnCardState *cs, u_char *buf, int size) -{ - char *dp; - - if (size < 1) - return; - dp = cs->dlog; - if (size < MAX_DLOG_SPACE / 3 - 10) { - *dp++ = 'H'; - *dp++ = 'E'; - *dp++ = 'X'; - *dp++ = ':'; - dp += QuickHex(dp, buf, size); - dp--; - *dp++ = '\n'; - *dp = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); -} - -void -dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) -{ - u_char *bend, *buf; - char *dp; - unsigned char pd, cr_l, cr, mt; - unsigned char sapi, tei, ftyp; - int i, cset = 0, cs_old = 0, cs_fest = 0; - int size, finish = 0; - - if (skb->len < 3) - return; - /* display header */ - dp = cs->dlog; - dp += jiftime(dp, jiffies); - *dp++ = ' '; - sapi = skb->data[0] >> 2; - tei = skb->data[1] >> 1; - ftyp = skb->data[2]; - buf = skb->data; - dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); - size = skb->len; - - if (tei == GROUP_TEI) { - if (sapi == CTRL_SAPI) { /* sapi 0 */ - if (ftyp == 3) { - dp += sprintf(dp, "broadcast\n"); - buf += 3; - size -= 3; - } else { - dp += sprintf(dp, "no UI broadcast\n"); - finish = 1; - } - } else if (sapi == TEI_SAPI) { - dp += sprintf(dp, "tei management\n"); - finish = 1; - } else { - dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); - finish = 1; - } - } else { - if (sapi == CTRL_SAPI) { - if (!(ftyp & 1)) { /* IFrame */ - dp += sprintf(dp, "with tei %d\n", tei); - buf += 4; - size -= 4; - } else { - dp += sprintf(dp, "SFrame with tei %d\n", tei); - finish = 1; - } - } else { - dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); - finish = 1; - } - } - bend = skb->data + skb->len; - if (buf >= bend) { - dp += sprintf(dp, "frame too short\n"); - finish = 1; - } - if (finish) { - *dp = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - return; - } - if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ - /* locate message type */ - pd = *buf++; - cr_l = *buf++; - if (cr_l) - cr = *buf++; - else - cr = 0; - mt = *buf++; - if (pd == PROTO_DIS_N0) { /* N0 */ - for (i = 0; i < MT_N0_LEN; i++) - if (mt_n0[i].nr == mt) - break; - /* display message type if it exists */ - if (i == MT_N0_LEN) - dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt_n0[i].descr); - } else { /* N1 */ - for (i = 0; i < MT_N1_LEN; i++) - if (mt_n1[i].nr == mt) - break; - /* display message type if it exists */ - if (i == MT_N1_LEN) - dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt_n1[i].descr); - } - - /* display each information element */ - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cset; - cset = *buf & 7; - cs_fest = *buf & 8; - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; - /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - if (cset == 0) { - for (i = 0; i < WE_0_LEN; i++) - if (*buf == we_0[i].nr) - break; - - /* When found, give appropriate msg */ - if (i != WE_0_LEN) { - dp += sprintf(dp, " %s\n", we_0[i].descr); - dp += we_0[i].f(dp, buf); - } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - } else if (cset == 6) { - for (i = 0; i < WE_6_LEN; i++) - if (*buf == we_6[i].nr) - break; - - /* When found, give appropriate msg */ - if (i != WE_6_LEN) { - dp += sprintf(dp, " %s\n", we_6[i].descr); - dp += we_6[i].f(dp, buf); - } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - /* Skip to next element */ - if (cs_fest == 8) { - cset = cs_old; - cs_old = 0; - cs_fest = 0; - } - buf += buf[1] + 2; - } - } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ - /* locate message type */ - buf++; - cr_l = *buf++; - if (cr_l) - cr = *buf++; - else - cr = 0; - mt = *buf++; - for (i = 0; i < MTSIZE; i++) - if (mtlist[i].nr == mt) - break; - - /* display message type if it exists */ - if (i == MTSIZE) - dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mtlist[i].descr); - - /* display each information element */ - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cset; - cset = *buf & 7; - cs_fest = *buf & 8; - break; - default: - dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - if (cset == 0) { - for (i = 0; i < IESIZE_NI1; i++) - if (*buf == ielist_ni1[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE_NI1) { - dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); - dp += ielist_ni1[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - } else if (cset == 5) { - for (i = 0; i < IESIZE_NI1_CS5; i++) - if (*buf == ielist_ni1_cs5[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE_NI1_CS5) { - dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); - dp += ielist_ni1_cs5[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - } else if (cset == 6) { - for (i = 0; i < IESIZE_NI1_CS6; i++) - if (*buf == ielist_ni1_cs6[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE_NI1_CS6) { - dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); - dp += ielist_ni1_cs6[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - - /* Skip to next element */ - if (cs_fest == 8) { - cset = cs_old; - cs_old = 0; - cs_fest = 0; - } - buf += buf[1] + 2; - } - } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ - /* locate message type */ - buf++; - cr_l = *buf++; - if (cr_l) - cr = *buf++; - else - cr = 0; - mt = *buf++; - for (i = 0; i < MTSIZE; i++) - if (mtlist[i].nr == mt) - break; - - /* display message type if it exists */ - if (i == MTSIZE) - dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mtlist[i].descr); - - /* display each information element */ - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 5: - dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; - /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - for (i = 0; i < IESIZE; i++) - if (*buf == ielist[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE) { - dp += sprintf(dp, " %s\n", ielist[i].descr); - dp += ielist[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - - /* Skip to next element */ - buf += buf[1] + 2; - } - } else { - dp += sprintf(dp, "Unknown protocol %x!", buf[0]); - } - *dp = 0; - HiSax_putstatus(cs, NULL, cs->dlog); -} diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c deleted file mode 100644 index 4e7d0aa227ad..000000000000 --- a/drivers/isdn/hisax/s0box.c +++ /dev/null @@ -1,260 +0,0 @@ -/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Creatix S0BOX - * - * Author Enrik Berkhan - * Copyright by Enrik Berkhan - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *s0box_revision = "$Revision: 2.6.2.4 $"; - -static inline void -writereg(unsigned int padr, signed int addr, u_char off, u_char val) { - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p((addr + off) & 0x7f, padr); - outb_p(0x16, padr + 2); - outb_p(val, padr); - outb_p(0x17, padr + 2); - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); -} - -static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 8, 4, 0xc, 2, 0xa, 6, 0xe }; - -static inline u_char -readreg(unsigned int padr, signed int addr, u_char off) { - register u_char n1, n2; - - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p((addr + off) | 0x80, padr); - outb_p(0x16, padr + 2); - outb_p(0x17, padr + 2); - n1 = (inb_p(padr + 1) >> 3) & 0x17; - outb_p(0x16, padr + 2); - n2 = (inb_p(padr + 1) >> 3) & 0x17; - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); - return nibtab[n1] | (nibtab[n2] << 4); -} - -static inline void -read_fifo(unsigned int padr, signed int adr, u_char *data, int size) -{ - int i; - register u_char n1, n2; - - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p(adr | 0x80, padr); - outb_p(0x16, padr + 2); - for (i = 0; i < size; i++) { - outb_p(0x17, padr + 2); - n1 = (inb_p(padr + 1) >> 3) & 0x17; - outb_p(0x16, padr + 2); - n2 = (inb_p(padr + 1) >> 3) & 0x17; - *(data++) = nibtab[n1] | (nibtab[n2] << 4); - } - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); - return; -} - -static inline void -write_fifo(unsigned int padr, signed int adr, u_char *data, int size) -{ - int i; - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p(adr & 0x7f, padr); - for (i = 0; i < size; i++) { - outb_p(0x16, padr + 2); - outb_p(*(data++), padr); - outb_p(0x17, padr + 2); - } - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); - return; -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -s0box_interrupt(int intno, void *dev_id) -{ -#define MAXCOUNT 5 - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - int count = 0; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (count >= MAXCOUNT) - printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_s0box(struct IsdnCardState *cs) -{ - release_region(cs->hw.teles3.cfg_reg, 8); -} - -static int -S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - break; - case CARD_RELEASE: - release_io_s0box(cs); - break; - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case CARD_TEST: - break; - } - return (0); -} - -int setup_s0box(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, s0box_revision); - printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_S0BOX) - return (0); - - cs->hw.teles3.cfg_reg = card->para[1]; - cs->hw.teles3.hscx[0] = -0x20; - cs->hw.teles3.hscx[1] = 0x0; - cs->hw.teles3.isac = 0x20; - cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; - cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; - cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; - cs->irq = card->para[0]; - if (!request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) { - printk(KERN_WARNING "HiSax: S0Box ports %x-%x already in use\n", - cs->hw.teles3.cfg_reg, - cs->hw.teles3.cfg_reg + 7); - return 0; - } - printk(KERN_INFO "HiSax: S0Box config irq:%d isac:0x%x cfg:0x%x\n", - cs->irq, - cs->hw.teles3.isac, cs->hw.teles3.cfg_reg); - printk(KERN_INFO "HiSax: hscx A:0x%x hscx B:0x%x\n", - cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &S0Box_card_msg; - cs->irq_func = &s0box_interrupt; - ISACVersion(cs, "S0Box:"); - if (HscxVersion(cs, "S0Box:")) { - printk(KERN_WARNING - "S0Box: wrong HSCX versions check IO address\n"); - release_io_s0box(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c deleted file mode 100644 index db906cb37a3f..000000000000 --- a/drivers/isdn/hisax/saphir.c +++ /dev/null @@ -1,296 +0,0 @@ -/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for HST Saphir 1 - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to HST High Soft Tech GmbH - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static char *saphir_rev = "$Revision: 1.10.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ISAC_DATA 0 -#define HSCX_DATA 1 -#define ADDRESS_REG 2 -#define IRQ_REG 3 -#define SPARE_REG 4 -#define RESET_REG 5 - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, - offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, - offset + (hscx ? 0x40 : 0), value); -} - -#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -saphir_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - /* Watchdog */ - if (cs->hw.saphir.timer.function) - mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); - else - printk(KERN_WARNING "saphir: Spurious timer!\n"); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -SaphirWatchDog(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.saphir.timer); - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - /* 5 sec WatchDog, so read at least every 4 sec */ - cs->readisac(cs, ISAC_RBCH); - spin_unlock_irqrestore(&cs->lock, flags); - mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); -} - -static void -release_io_saphir(struct IsdnCardState *cs) -{ - byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); - del_timer(&cs->hw.saphir.timer); - cs->hw.saphir.timer.function = NULL; - if (cs->hw.saphir.cfg_reg) - release_region(cs->hw.saphir.cfg_reg, 6); -} - -static int -saphir_reset(struct IsdnCardState *cs) -{ - u_char irq_val; - - switch (cs->irq) { - case 5: irq_val = 0; - break; - case 3: irq_val = 1; - break; - case 11: - irq_val = 2; - break; - case 12: - irq_val = 3; - break; - case 15: - irq_val = 4; - break; - default: - printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n", - cs->irq); - return (1); - } - byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); - byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); - mdelay(10); - byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); - mdelay(10); - byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); - byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02); - return (0); -} - -static int -saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - saphir_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_saphir(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - - -int setup_saphir(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, saphir_rev); - printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_HSTSAPHIR) - return (0); - - /* IO-Ports */ - cs->hw.saphir.cfg_reg = card->para[1]; - cs->hw.saphir.isac = card->para[1] + ISAC_DATA; - cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; - cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; - cs->irq = card->para[0]; - if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) { - printk(KERN_WARNING - "HiSax: HST Saphir config port %x-%x already in use\n", - cs->hw.saphir.cfg_reg, - cs->hw.saphir.cfg_reg + 5); - return (0); - } - - printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n", - cs->irq, cs->hw.saphir.cfg_reg); - - setup_isac(cs); - timer_setup(&cs->hw.saphir.timer, SaphirWatchDog, 0); - cs->hw.saphir.timer.expires = jiffies + 4 * HZ; - add_timer(&cs->hw.saphir.timer); - if (saphir_reset(cs)) { - release_io_saphir(cs); - return (0); - } - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &saphir_card_msg; - cs->irq_func = &saphir_interrupt; - ISACVersion(cs, "saphir:"); - if (HscxVersion(cs, "saphir:")) { - printk(KERN_WARNING - "saphir: wrong HSCX versions check IO address\n"); - release_io_saphir(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c deleted file mode 100644 index c0b97b893495..000000000000 --- a/drivers/isdn/hisax/sedlbauer.c +++ /dev/null @@ -1,873 +0,0 @@ -/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $ - * - * low level stuff for Sedlbauer cards - * includes support for the Sedlbauer speed star (speed star II), - * support for the Sedlbauer speed fax+, - * support for the Sedlbauer ISDN-Controller PC/104 and - * support for the Sedlbauer speed pci - * derived from the original file asuscom.c from Karsten Keil - * - * Author Marcus Niemann - * Copyright by Marcus Niemann - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Karsten Keil - * Sedlbauer AG for informations - * Edgar Toernig - * - */ - -/* Supported cards: - * Card: Chip: Configuration: Comment: - * --------------------------------------------------------------------- - * Speed Card ISAC_HSCX DIP-SWITCH - * Speed Win ISAC_HSCX ISAPNP - * Speed Fax+ ISAC_ISAR ISAPNP Full analog support - * Speed Star ISAC_HSCX CARDMGR - * Speed Win2 IPAC ISAPNP - * ISDN PC/104 IPAC DIP-SWITCH - * Speed Star2 IPAC CARDMGR - * Speed PCI IPAC PCI PNP - * Speed Fax+ ISAC_ISAR PCI PNP Full analog support - * - * Important: - * For the sedlbauer speed fax+ to work properly you have to download - * the firmware onto the card. - * For example: hisaxctrl 9 ISAR.BIN - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isar.h" -#include "isdnl1.h" -#include -#include - -static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $"; - -static const char *Sedlbauer_Types[] = -{"None", "speed card/win", "speed star", "speed fax+", - "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"}; - -#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 -#define PCI_SUBVENDOR_HST_SAPHIR3 0x52 -#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 -#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 -#define PCI_SUB_ID_SEDLBAUER 0x01 - -#define SEDL_SPEED_CARD_WIN 1 -#define SEDL_SPEED_STAR 2 -#define SEDL_SPEED_FAX 3 -#define SEDL_SPEED_WIN2_PC104 4 -#define SEDL_SPEED_STAR2 5 -#define SEDL_SPEED_PCI 6 -#define SEDL_SPEEDFAX_PYRAMID 7 -#define SEDL_SPEEDFAX_PCI 8 -#define HST_SAPHIR3 9 - -#define SEDL_CHIP_TEST 0 -#define SEDL_CHIP_ISAC_HSCX 1 -#define SEDL_CHIP_ISAC_ISAR 2 -#define SEDL_CHIP_IPAC 3 - -#define SEDL_BUS_ISA 1 -#define SEDL_BUS_PCI 2 -#define SEDL_BUS_PCMCIA 3 - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define SEDL_HSCX_ISA_RESET_ON 0 -#define SEDL_HSCX_ISA_RESET_OFF 1 -#define SEDL_HSCX_ISA_ISAC 2 -#define SEDL_HSCX_ISA_HSCX 3 -#define SEDL_HSCX_ISA_ADR 4 - -#define SEDL_HSCX_PCMCIA_RESET 0 -#define SEDL_HSCX_PCMCIA_ISAC 1 -#define SEDL_HSCX_PCMCIA_HSCX 2 -#define SEDL_HSCX_PCMCIA_ADR 4 - -#define SEDL_ISAR_ISA_ISAC 4 -#define SEDL_ISAR_ISA_ISAR 6 -#define SEDL_ISAR_ISA_ADR 8 -#define SEDL_ISAR_ISA_ISAR_RESET_ON 10 -#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12 - -#define SEDL_IPAC_ANY_ADR 0 -#define SEDL_IPAC_ANY_IPAC 2 - -#define SEDL_IPAC_PCI_BASE 0 -#define SEDL_IPAC_PCI_ADR 0xc0 -#define SEDL_IPAC_PCI_IPAC 0xc8 -#define SEDL_ISAR_PCI_ADR 0xc8 -#define SEDL_ISAR_PCI_ISAC 0xd0 -#define SEDL_ISAR_PCI_ISAR 0xe0 -#define SEDL_ISAR_PCI_ISAR_RESET_ON 0x01 -#define SEDL_ISAR_PCI_ISAR_RESET_OFF 0x18 -#define SEDL_ISAR_PCI_LED1 0x08 -#define SEDL_ISAR_PCI_LED2 0x10 - -#define SEDL_RESET 0x3 /* same as DOS driver */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.sedl.adr, - cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.sedl.adr, - cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value); -} - -/* ISAR access routines - * mode = 0 access with IRQ on - * mode = 1 access with IRQ off - * mode = 2 access with IRQ off and using last offset - */ - -static u_char -ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) -{ - if (mode == 0) - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset)); - else if (mode == 1) - byteout(cs->hw.sedl.adr, offset); - return (bytein(cs->hw.sedl.hscx)); -} - -static void -WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) -{ - if (mode == 0) - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value); - else { - if (mode == 1) - byteout(cs->hw.sedl.adr, offset); - byteout(cs->hw.sedl.hscx, value); - } -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -sedlbauer_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - spin_unlock_irqrestore(&cs->lock, flags); - printk(KERN_WARNING "Sedlbauer: card not available!\n"); - return IRQ_NONE; - } - - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -sedlbauer_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val, icnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Sedlbauer IRQ LOOP"); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -sedlbauer_interrupt_isar(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - int cnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); -Start_ISAR: - if (val & ISAR_IRQSTA) - isar_int_main(cs); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); - if ((val & ISAR_IRQSTA) && --cnt) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "ISAR IntStat after IntRoutine"); - goto Start_ISAR; - } - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); - if (val && --cnt) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (!cnt) - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Sedlbauer IRQ LOOP"); - - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_sedlbauer(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - if (cs->subtyp == SEDL_SPEED_FAX) { - bytecnt = 16; - } else if (cs->hw.sedl.bus == SEDL_BUS_PCI) { - bytecnt = 256; - } - if (cs->hw.sedl.cfg_reg) - release_region(cs->hw.sedl.cfg_reg, bytecnt); -} - -static void -reset_sedlbauer(struct IsdnCardState *cs) -{ - printk(KERN_INFO "Sedlbauer: resetting card\n"); - - if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && - (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) { - if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); - mdelay(2); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); - mdelay(10); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12); - } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) && - (cs->hw.sedl.bus == SEDL_BUS_PCI)) { - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - mdelay(10); - } else { - byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ - mdelay(2); - byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - mdelay(10); - } - } -} - -static int -Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_sedlbauer(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - if (cs->hw.sedl.bus == SEDL_BUS_PCI) - /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg + 5, 0); - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - spin_lock_irqsave(&cs->lock, flags); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, - ISAR_IRQBIT, 0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, - ISAC_MASK, 0xFF); - reset_sedlbauer(cs); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, - ISAR_IRQBIT, 0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, - ISAC_MASK, 0xFF); - spin_unlock_irqrestore(&cs->lock, flags); - } - release_io_sedlbauer(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - if (cs->hw.sedl.bus == SEDL_BUS_PCI) - /* enable all IRQ */ - byteout(cs->hw.sedl.cfg_reg + 5, 0x02); - reset_sedlbauer(cs); - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - clear_pending_isac_ints(cs); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, - ISAR_IRQBIT, 0); - initisac(cs); - initisar(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - /* RESET Receiver and Transmitter */ - cs->writeisac(cs, ISAC_CMDR, 0x41); - } else { - inithscxisac(cs, 3); - } - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - case MDL_INFO_CONN: - if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) - return (0); - spin_lock_irqsave(&cs->lock, flags); - if ((long) arg) - cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; - else - cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1; - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case MDL_INFO_REL: - if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) - return (0); - spin_lock_irqsave(&cs->lock, flags); - if ((long) arg) - cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; - else - cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1; - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id sedl_ids[] = { - { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), - ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), - (unsigned long) "Speed win" }, - { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), - ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), - (unsigned long) "Speed Fax+" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &sedl_ids[0]; -static struct pnp_card *pnp_c = NULL; - -static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) -{ - struct IsdnCardState *cs = card->cs; - struct pnp_dev *pnp_d; - - if (!isapnp_present()) - return -1; - - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0x2)) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - *bytecnt = 16; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } - - return (1); - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return (0); - } - } - ipid++; - pnp_c = NULL; - } - - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); - return -1; -} -#else - -static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) -{ - return -1; -} -#endif /* __ISAPNP__ */ - -#ifdef CONFIG_PCI -static struct pci_dev *dev_sedl = NULL; - -static int setup_sedlbauer_pci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u16 sub_vendor_id, sub_id; - - if ((dev_sedl = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { - if (pci_enable_device(dev_sedl)) - return (0); - cs->irq = dev_sedl->irq; - if (!cs->irq) { - printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); - } else { - printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); - return (0); - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.sedl.bus = SEDL_BUS_PCI; - sub_vendor_id = dev_sedl->subsystem_vendor; - sub_id = dev_sedl->subsystem_device; - printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); - printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", - cs->hw.sedl.cfg_reg); - if (sub_id != PCI_SUB_ID_SEDLBAUER) { - printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return (0); - } - if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PCI; - } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = HST_SAPHIR3; - } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; - } else { - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return (0); - } - - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg + 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg + 5, 0); /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - mdelay(10); - - return (1); -} - -#else - -static int setup_sedlbauer_pci(struct IsdnCard *card) -{ - return (1); -} - -#endif /* CONFIG_PCI */ - -int setup_sedlbauer(struct IsdnCard *card) -{ - int bytecnt = 8, ver, val, rc; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Sedlbauer_revision); - printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); - - if (cs->typ == ISDN_CTYPE_SEDLBAUER) { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.bus = SEDL_BUS_ISA; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) { - cs->subtyp = SEDL_SPEED_STAR; - cs->hw.sedl.bus = SEDL_BUS_PCMCIA; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.bus = SEDL_BUS_ISA; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - } else - return (0); - - bytecnt = 8; - if (card->para[1]) { - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - bytecnt = 16; - } - } else { - rc = setup_sedlbauer_isapnp(card, &bytecnt); - if (!rc) - return (0); - if (rc > 0) - goto ready; - - /* Probe for Sedlbauer speed pci */ - rc = setup_sedlbauer_pci(card); - if (!rc) - return (0); - - bytecnt = 256; - } - -ready: - - /* In case of the sedlbauer pcmcia card, this region is in use, - * reserved for us by the card manager. So we do not check it - * here, it would fail. - */ - if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && - !request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt); - return (0); - } - - printk(KERN_INFO - "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n", - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt, - cs->irq); - - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Sedl_card_msg; - -/* - * testing ISA and PCMCIA Cards for IPAC, default is ISAC - * do not test for PCI card, because ports are different - * and PCI card uses only IPAC (for the moment) - */ - if (cs->hw.sedl.bus != SEDL_BUS_PCI) { - val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR, - cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); - printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val); - if ((val == 1) || (val == 2)) { - /* IPAC */ - cs->subtyp = SEDL_SPEED_WIN2_PC104; - if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { - cs->subtyp = SEDL_SPEED_STAR2; - } - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - } else { - /* ISAC_HSCX oder ISAC_ISAR */ - if (cs->hw.sedl.chip == SEDL_CHIP_TEST) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; - } - } - } - -/* - * hw.sedl.chip is now properly set - */ - printk(KERN_INFO "Sedlbauer: %s detected\n", - Sedlbauer_Types[cs->subtyp]); - - setup_isac(cs); - if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - if (cs->hw.sedl.bus == SEDL_BUS_PCI) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; - } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - } - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &sedlbauer_interrupt_ipac; - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID); - printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); - } else { - /* ISAC_HSCX oder ISAC_ISAR */ - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - if (cs->hw.sedl.bus == SEDL_BUS_PCI) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ISAR; - } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAR; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAR_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAR_RESET_OFF; - } - cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; - cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; - test_and_set_bit(HW_ISAR, &cs->HW_Flags); - cs->irq_func = &sedlbauer_interrupt_isar; - cs->auxcmd = &isar_auxcmd; - ISACVersion(cs, "Sedlbauer:"); - cs->BC_Read_Reg = &ReadISAR; - cs->BC_Write_Reg = &WriteISAR; - cs->BC_Send_Data = &isar_fill_fifo; - bytecnt = 3; - while (bytecnt) { - ver = ISARVersion(cs, "Sedlbauer:"); - if (ver < 0) - printk(KERN_WARNING - "Sedlbauer: wrong ISAR version (ret = %d)\n", ver); - else - break; - reset_sedlbauer(cs); - bytecnt--; - } - if (!bytecnt) { - release_io_sedlbauer(cs); - return (0); - } - } else { - if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; - cs->irq_flags |= IRQF_SHARED; - } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF; - } - cs->irq_func = &sedlbauer_interrupt; - ISACVersion(cs, "Sedlbauer:"); - - if (HscxVersion(cs, "Sedlbauer:")) { - printk(KERN_WARNING - "Sedlbauer: wrong HSCX versions check IO address\n"); - release_io_sedlbauer(cs); - return (0); - } - } - } - return (1); -} diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c deleted file mode 100644 index 92ef62d4caf4..000000000000 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ /dev/null @@ -1,209 +0,0 @@ -/*====================================================================== - - A Sedlbauer PCMCIA client driver - - This driver is for the Sedlbauer Speed Star and Speed Star II, - which are ISDN PCMCIA Cards. - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann - . All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - - ======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards"); -MODULE_AUTHOR("Marcus Niemann"); -MODULE_LICENSE("Dual MPL/GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int sedlbauer_config(struct pcmcia_device *link); -static void sedlbauer_release(struct pcmcia_device *link); - -static void sedlbauer_detach(struct pcmcia_device *p_dev); - -typedef struct local_info_t { - struct pcmcia_device *p_dev; - int stop; - int cardnr; -} local_info_t; - -static int sedlbauer_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - dev_dbg(&link->dev, "sedlbauer_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) return -ENOMEM; - local->cardnr = -1; - - local->p_dev = link; - link->priv = local; - - return sedlbauer_config(link); -} /* sedlbauer_attach */ - -static void sedlbauer_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link); - - ((local_info_t *)link->priv)->stop = 1; - sedlbauer_release(link); - - /* This points to the parent local_info_t struct */ - kfree(link->priv); -} /* sedlbauer_detach */ - -static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - p_dev->io_lines = 3; - return pcmcia_request_io(p_dev); -} - -static int sedlbauer_config(struct pcmcia_device *link) -{ - int ret; - IsdnCard_t icard; - - dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = protocol; - icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; - - ret = hisax_init_pcmcia(link, - &(((local_info_t *)link->priv)->stop), &icard); - if (ret < 0) { - printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d with %pR\n", - ret, link->resource[0]); - sedlbauer_release(link); - return -ENODEV; - } else - ((local_info_t *)link->priv)->cardnr = ret; - - return 0; - -failed: - sedlbauer_release(link); - return -ENODEV; - -} /* sedlbauer_config */ - -static void sedlbauer_release(struct pcmcia_device *link) -{ - local_info_t *local = link->priv; - dev_dbg(&link->dev, "sedlbauer_release(0x%p)\n", link); - - if (local) { - if (local->cardnr >= 0) { - /* no unregister function with hisax */ - HiSax_closecard(local->cardnr); - } - } - - pcmcia_disable_device(link); -} /* sedlbauer_release */ - -static int sedlbauer_suspend(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->stop = 1; - - return 0; -} - -static int sedlbauer_resume(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->stop = 0; - - return 0; -} - - -static const struct pcmcia_device_id sedlbauer_ids[] = { - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c), - PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae), -/* PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/ - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids); - -static struct pcmcia_driver sedlbauer_driver = { - .owner = THIS_MODULE, - .name = "sedlbauer_cs", - .probe = sedlbauer_probe, - .remove = sedlbauer_detach, - .id_table = sedlbauer_ids, - .suspend = sedlbauer_suspend, - .resume = sedlbauer_resume, -}; -module_pcmcia_driver(sedlbauer_driver); diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c deleted file mode 100644 index 18cee6360d0a..000000000000 --- a/drivers/isdn/hisax/sportster.c +++ /dev/null @@ -1,267 +0,0 @@ -/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for USR Sportster internal TA - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation - * - * - */ -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *sportster_revision = "$Revision: 1.16.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define SPORTSTER_ISAC 0xC000 -#define SPORTSTER_HSCXA 0x0000 -#define SPORTSTER_HSCXB 0x4000 -#define SPORTSTER_RES_IRQ 0x8000 -#define SPORTSTER_RESET 0x80 -#define SPORTSTER_INTE 0x40 - -static inline int -calc_off(unsigned int base, unsigned int off) -{ - return (base + ((off & 0xfc) << 8) + ((off & 3) << 1)); -} - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (bytein(calc_off(cs->hw.spt.isac, offset))); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - byteout(calc_off(cs->hw.spt.isac, offset), value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.spt.isac, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.spt.isac, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg)) -#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -sportster_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = READHSCX(cs, 1, HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = ReadISAC(cs, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = READHSCX(cs, 1, HSCX_ISTA); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = ReadISAC(cs, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - /* get a new irq impulse if there any pending */ - bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ + 1); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_sportster(struct IsdnCardState *cs) -{ - int i, adr; - - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0); - for (i = 0; i < 64; i++) { - adr = cs->hw.spt.cfg_reg + i * 1024; - release_region(adr, 8); - } -} - -static void -reset_sportster(struct IsdnCardState *cs) -{ - cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - mdelay(10); - cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - mdelay(10); -} - -static int -Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_sportster(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_sportster(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_sportster(cs); - inithscxisac(cs, 1); - cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int get_io_range(struct IsdnCardState *cs) -{ - int i, j, adr; - - for (i = 0; i < 64; i++) { - adr = cs->hw.spt.cfg_reg + i * 1024; - if (!request_region(adr, 8, "sportster")) { - printk(KERN_WARNING "HiSax: USR Sportster config port " - "%x-%x already in use\n", - adr, adr + 8); - break; - } - } - if (i == 64) - return (1); - else { - for (j = 0; j < i; j++) { - adr = cs->hw.spt.cfg_reg + j * 1024; - release_region(adr, 8); - } - return (0); - } -} - -int setup_sportster(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, sportster_revision); - printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_SPORTSTER) - return (0); - - cs->hw.spt.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (!get_io_range(cs)) - return (0); - cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC; - cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA; - cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB; - - switch (cs->irq) { - case 5: cs->hw.spt.res_irq = 1; - break; - case 7: cs->hw.spt.res_irq = 2; - break; - case 10:cs->hw.spt.res_irq = 3; - break; - case 11:cs->hw.spt.res_irq = 4; - break; - case 12:cs->hw.spt.res_irq = 5; - break; - case 14:cs->hw.spt.res_irq = 6; - break; - case 15:cs->hw.spt.res_irq = 7; - break; - default:release_io_sportster(cs); - printk(KERN_WARNING "Sportster: wrong IRQ\n"); - return (0); - } - printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n", - cs->irq, cs->hw.spt.cfg_reg); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Sportster_card_msg; - cs->irq_func = &sportster_interrupt; - ISACVersion(cs, "Sportster:"); - if (HscxVersion(cs, "Sportster:")) { - printk(KERN_WARNING - "Sportster: wrong HSCX versions check IO address\n"); - release_io_sportster(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h deleted file mode 100644 index b421b86ca7da..000000000000 --- a/drivers/isdn/hisax/st5481.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen - * 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _ST5481_H_ -#define _ST5481_H_ - - -// USB IDs, the Product Id is in the range 0x4810-0x481F - -#define ST_VENDOR_ID 0x0483 -#define ST5481_PRODUCT_ID 0x4810 -#define ST5481_PRODUCT_ID_MASK 0xFFF0 - -// ST5481 endpoints when using alternative setting 3 (2B+D). -// To get the endpoint address, OR with 0x80 for IN endpoints. - -#define EP_CTRL 0x00U /* Control endpoint */ -#define EP_INT 0x01U /* Interrupt endpoint */ -#define EP_B1_OUT 0x02U /* B1 channel out */ -#define EP_B1_IN 0x03U /* B1 channel in */ -#define EP_B2_OUT 0x04U /* B2 channel out */ -#define EP_B2_IN 0x05U /* B2 channel in */ -#define EP_D_OUT 0x06U /* D channel out */ -#define EP_D_IN 0x07U /* D channel in */ - -// Number of isochronous packets. With 20 packets we get -// 50 interrupts/sec for each endpoint. - -#define NUM_ISO_PACKETS_D 20 -#define NUM_ISO_PACKETS_B 20 - -// Size of each isochronous packet. -// In outgoing direction we need to match ISDN data rates: -// D: 2 bytes / msec -> 16 kbit / s -// B: 16 bytes / msec -> 64 kbit / s -#define SIZE_ISO_PACKETS_D_IN 16 -#define SIZE_ISO_PACKETS_D_OUT 2 -#define SIZE_ISO_PACKETS_B_IN 32 -#define SIZE_ISO_PACKETS_B_OUT 8 - -// If we overrun/underrun, we send one packet with +/- 2 bytes -#define B_FLOW_ADJUST 2 - -// Registers that are written using vendor specific device request -// on endpoint 0. - -#define LBA 0x02 /* S loopback */ -#define SET_DEFAULT 0x06 /* Soft reset */ -#define LBB 0x1D /* S maintenance loopback */ -#define STT 0x1e /* S force transmission signals */ -#define SDA_MIN 0x20 /* SDA-sin minimal value */ -#define SDA_MAX 0x21 /* SDA-sin maximal value */ -#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */ -#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */ -#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */ -#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */ -#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */ -#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */ -#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */ -#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */ -#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */ -#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */ -#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */ -#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */ -#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */ -#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */ -#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */ -#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */ -#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */ -#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */ -#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */ -#define MPMSK 0x4A /* Multi purpose interrupt MASK register */ -#define FFMSK_D 0x4c /* D fifo interrupt MASK register */ -#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */ -#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */ -#define GPIO_DIR 0x52 /* GPIO pins direction registers */ -#define GPIO_OUT 0x53 /* GPIO pins output register */ -#define GPIO_IN 0x54 /* GPIO pins input register */ -#define TXCI 0x56 /* CI command to be transmitted */ - - -// Format of the interrupt packet received on endpoint 1: -// -// +--------+--------+--------+--------+--------+--------+ -// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT! -// +--------+--------+--------+--------+--------+--------+ - -// Offsets in the interrupt packet - -#define MPINT 0 -#define FFINT_D 1 -#define FFINT_B1 2 -#define FFINT_B2 3 -#define CCIST 4 -#define GPIO_INT 5 -#define INT_PKT_SIZE 6 - -// MPINT -#define LSD_INT 0x80 /* S line activity detected */ -#define RXCI_INT 0x40 /* Indicate primitive arrived */ -#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */ -#define DCOLL_INT 0x10 /* D channel collision */ -#define AMIVN_INT 0x04 /* AMI violation number reached 2 */ -#define INFOI_INT 0x04 /* INFOi changed */ -#define DRXON_INT 0x02 /* Reception channel active */ -#define GPCHG_INT 0x01 /* GPIO pin value changed */ - -// FFINT_x -#define IN_OVERRUN 0x80 /* In fifo overrun */ -#define OUT_UNDERRUN 0x40 /* Out fifo underrun */ -#define IN_UP 0x20 /* In fifo thresholdh up-crossed */ -#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */ -#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */ -#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */ -#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */ -#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */ - -#define ANY_REC_INT (IN_OVERRUN + IN_UP + IN_DOWN + IN_COUNTER_ZEROED) -#define ANY_XMIT_INT (OUT_UNDERRUN + OUT_UP + OUT_DOWN + OUT_COUNTER_ZEROED) - - -// Level 1 commands that are sent using the TXCI device request -#define ST5481_CMD_DR 0x0 /* Deactivation Request */ -#define ST5481_CMD_RES 0x1 /* state machine RESet */ -#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */ -#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */ -#define ST5481_CMD_PUP 0x7 /* Power UP */ -#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */ -#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */ -#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */ -#define ST5481_CMD_PDN 0xF /* Power DoWn */ - -// Turn on/off the LEDs using the GPIO device request. -// To use the B LEDs, number_of_leds must be set to 4 -#define B1_LED 0x10U -#define B2_LED 0x20U -#define GREEN_LED 0x40U -#define RED_LED 0x80U - -// D channel out states -enum { - ST_DOUT_NONE, - - ST_DOUT_SHORT_INIT, - ST_DOUT_SHORT_WAIT_DEN, - - ST_DOUT_LONG_INIT, - ST_DOUT_LONG_WAIT_DEN, - ST_DOUT_NORMAL, - - ST_DOUT_WAIT_FOR_UNDERRUN, - ST_DOUT_WAIT_FOR_NOT_BUSY, - ST_DOUT_WAIT_FOR_STOP, - ST_DOUT_WAIT_FOR_RESET, -}; - -#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1) - -// D channel out events -enum { - EV_DOUT_START_XMIT, - EV_DOUT_COMPLETE, - EV_DOUT_DEN, - EV_DOUT_RESETED, - EV_DOUT_STOPPED, - EV_DOUT_COLL, - EV_DOUT_UNDERRUN, -}; - -#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1) - -// ---------------------------------------------------------------------- - -enum { - ST_L1_F3, - ST_L1_F4, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1_STATE_COUNT (ST_L1_F8 + 1) - -// The first 16 entries match the Level 1 indications that -// are found at offset 4 (CCIST) in the interrupt packet - -enum { - EV_IND_DP, // 0000 Deactivation Pending - EV_IND_1, // 0001 - EV_IND_2, // 0010 - EV_IND_3, // 0011 - EV_IND_RSY, // 0100 ReSYnchronizing - EV_IND_5, // 0101 - EV_IND_6, // 0110 - EV_IND_7, // 0111 - EV_IND_AP, // 1000 Activation Pending - EV_IND_9, // 1001 - EV_IND_10, // 1010 - EV_IND_11, // 1011 - EV_IND_AI8, // 1100 Activation Indication class 8 - EV_IND_AI10,// 1101 Activation Indication class 10 - EV_IND_AIL, // 1110 Activation Indication Loopback - EV_IND_DI, // 1111 Deactivation Indication - EV_PH_ACTIVATE_REQ, - EV_PH_DEACTIVATE_REQ, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -#define ERR(format, arg...) \ - printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) - -#define WARNING(format, arg...) \ - printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) - -#define INFO(format, arg...) \ - printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) - -#include -#include "fsm.h" -#include "hisax_if.h" -#include - -/* ====================================================================== - * FIFO handling - */ - -/* Generic FIFO structure */ -struct fifo { - u_char r, w, count, size; - spinlock_t lock; -}; - -/* - * Init an FIFO - */ -static inline void fifo_init(struct fifo *fifo, int size) -{ - fifo->r = fifo->w = fifo->count = 0; - fifo->size = size; - spin_lock_init(&fifo->lock); -} - -/* - * Add an entry to the FIFO - */ -static inline int fifo_add(struct fifo *fifo) -{ - unsigned long flags; - int index; - - if (!fifo) { - return -1; - } - - spin_lock_irqsave(&fifo->lock, flags); - if (fifo->count == fifo->size) { - // FIFO full - index = -1; - } else { - // Return index where to get the next data to add to the FIFO - index = fifo->w++ & (fifo->size - 1); - fifo->count++; - } - spin_unlock_irqrestore(&fifo->lock, flags); - return index; -} - -/* - * Remove an entry from the FIFO with the index returned. - */ -static inline int fifo_remove(struct fifo *fifo) -{ - unsigned long flags; - int index; - - if (!fifo) { - return -1; - } - - spin_lock_irqsave(&fifo->lock, flags); - if (!fifo->count) { - // FIFO empty - index = -1; - } else { - // Return index where to get the next data from the FIFO - index = fifo->r++ & (fifo->size - 1); - fifo->count--; - } - spin_unlock_irqrestore(&fifo->lock, flags); - - return index; -} - -/* ====================================================================== - * control pipe - */ -typedef void (*ctrl_complete_t)(void *); - -typedef struct ctrl_msg { - struct usb_ctrlrequest dr; - ctrl_complete_t complete; - void *context; -} ctrl_msg; - -/* FIFO of ctrl messages waiting to be sent */ -#define MAX_EP0_MSG 16 -struct ctrl_msg_fifo { - struct fifo f; - struct ctrl_msg data[MAX_EP0_MSG]; -}; - -#define MAX_DFRAME_LEN_L1 300 -#define HSCX_BUFMAX 4096 - -struct st5481_ctrl { - struct ctrl_msg_fifo msg_fifo; - unsigned long busy; - struct urb *urb; -}; - -struct st5481_intr { - // struct evt_fifo evt_fifo; - struct urb *urb; -}; - -struct st5481_d_out { - struct isdnhdlc_vars hdlc_state; - struct urb *urb[2]; /* double buffering */ - unsigned long busy; - struct sk_buff *tx_skb; - struct FsmInst fsm; -}; - -struct st5481_b_out { - struct isdnhdlc_vars hdlc_state; - struct urb *urb[2]; /* double buffering */ - u_char flow_event; - u_long busy; - struct sk_buff *tx_skb; -}; - -struct st5481_in { - struct isdnhdlc_vars hdlc_state; - struct urb *urb[2]; /* double buffering */ - int mode; - int bufsize; - unsigned int num_packets; - unsigned int packet_size; - unsigned char ep, counter; - unsigned char *rcvbuf; - struct st5481_adapter *adapter; - struct hisax_if *hisax_if; -}; - -int st5481_setup_in(struct st5481_in *in); -void st5481_release_in(struct st5481_in *in); -void st5481_in_mode(struct st5481_in *in, int mode); - -struct st5481_bcs { - struct hisax_b_if b_if; - struct st5481_adapter *adapter; - struct st5481_in b_in; - struct st5481_b_out b_out; - int channel; - int mode; -}; - -struct st5481_adapter { - int number_of_leds; - struct usb_device *usb_dev; - struct hisax_d_if hisax_d_if; - - struct st5481_ctrl ctrl; - struct st5481_intr intr; - struct st5481_in d_in; - struct st5481_d_out d_out; - - unsigned char leds; - unsigned int led_counter; - - unsigned long event; - - struct FsmInst l1m; - struct FsmTimer timer; - - struct st5481_bcs bcs[2]; -}; - -#define TIMER3_VALUE 7000 - -/* ====================================================================== - * - */ - -/* - * Submit an URB with error reporting. This is a macro so - * the __func__ returns the caller function name. - */ -#define SUBMIT_URB(urb, mem_flags) \ - ({ \ - int status; \ - if ((status = usb_submit_urb(urb, mem_flags)) < 0) { \ - WARNING("usb_submit_urb failed,status=%d", status); \ - } \ - status; \ - }) - -/* - * USB double buffering, return the URB index (0 or 1). - */ -static inline int get_buf_nr(struct urb *urbs[], struct urb *urb) -{ - return (urbs[0] == urb ? 0 : 1); -} - -/* ---------------------------------------------------------------------- */ - -/* B Channel */ - -int st5481_setup_b(struct st5481_bcs *bcs); -void st5481_release_b(struct st5481_bcs *bcs); -void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg); - -/* D Channel */ - -int st5481_setup_d(struct st5481_adapter *adapter); -void st5481_release_d(struct st5481_adapter *adapter); -void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg); -int st5481_d_init(void); -void st5481_d_exit(void); - -/* USB */ -void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command); -int st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev, - unsigned int pipe, int num_packets, - int packet_size, int buf_size, - usb_complete_t complete, void *context); -void st5481_release_isocpipes(struct urb *urb[2]); - -void st5481_usb_pipe_reset(struct st5481_adapter *adapter, - u_char pipe, ctrl_complete_t complete, void *context); -void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u16 value, - ctrl_complete_t complete, void *context); -int st5481_setup_usb(struct st5481_adapter *adapter); -void st5481_release_usb(struct st5481_adapter *adapter); -void st5481_start(struct st5481_adapter *adapter); -void st5481_stop(struct st5481_adapter *adapter); - -// ---------------------------------------------------------------------- -// debugging macros - -#define __debug_variable st5481_debug -#include "hisax_debug.h" - -extern int st5481_debug; - -#ifdef CONFIG_HISAX_DEBUG - -#define DBG_ISO_PACKET(level, urb) \ - if (level & __debug_variable) dump_iso_packet(__func__, urb) - -static void __attribute__((unused)) -dump_iso_packet(const char *name, struct urb *urb) -{ - int i, j; - int len, ofs; - u_char *data; - - printk(KERN_DEBUG "%s: packets=%d,errors=%d\n", - name, urb->number_of_packets, urb->error_count); - for (i = 0; i < urb->number_of_packets; ++i) { - if (urb->pipe & USB_DIR_IN) { - len = urb->iso_frame_desc[i].actual_length; - } else { - len = urb->iso_frame_desc[i].length; - } - ofs = urb->iso_frame_desc[i].offset; - printk(KERN_DEBUG "len=%.2d,ofs=%.3d ", len, ofs); - if (len) { - data = urb->transfer_buffer + ofs; - for (j = 0; j < len; j++) { - printk("%.2x", data[j]); - } - } - printk("\n"); - } -} - -static inline const char *ST5481_CMD_string(int evt) -{ - static char s[16]; - - switch (evt) { - case ST5481_CMD_DR: return "DR"; - case ST5481_CMD_RES: return "RES"; - case ST5481_CMD_TM1: return "TM1"; - case ST5481_CMD_TM2: return "TM2"; - case ST5481_CMD_PUP: return "PUP"; - case ST5481_CMD_AR8: return "AR8"; - case ST5481_CMD_AR10: return "AR10"; - case ST5481_CMD_ARL: return "ARL"; - case ST5481_CMD_PDN: return "PDN"; - } - - sprintf(s, "0x%x", evt); - return s; -} - -#else - -#define DBG_ISO_PACKET(level, urb) do {} while (0) - -#endif - - - -#endif diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c deleted file mode 100644 index f64a36007800..000000000000 --- a/drivers/isdn/hisax/st5481_b.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen - * 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include "st5481.h" - -static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; - - ifc->l1l2(ifc, pr, arg); -} - -/* - * Encode and transmit next frame. - */ -static void usb_b_out(struct st5481_bcs *bcs, int buf_nr) -{ - struct st5481_b_out *b_out = &bcs->b_out; - struct st5481_adapter *adapter = bcs->adapter; - struct urb *urb; - unsigned int packet_size, offset; - int len, buf_size, bytes_sent; - int i; - struct sk_buff *skb; - - if (test_and_set_bit(buf_nr, &b_out->busy)) { - DBG(4, "ep %d urb %d busy", (bcs->channel + 1) * 2, buf_nr); - return; - } - urb = b_out->urb[buf_nr]; - - // Adjust isoc buffer size according to flow state - if (b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) { - buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST; - packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST; - DBG(4, "B%d,adjust flow,add %d bytes", bcs->channel + 1, B_FLOW_ADJUST); - } else if (b_out->flow_event & OUT_UP) { - buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST; - packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST; - DBG(4, "B%d,adjust flow,remove %d bytes", bcs->channel + 1, B_FLOW_ADJUST); - } else { - buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT; - packet_size = 8; - } - b_out->flow_event = 0; - - len = 0; - while (len < buf_size) { - if ((skb = b_out->tx_skb)) { - DBG_SKB(0x100, skb); - DBG(4, "B%d,len=%d", bcs->channel + 1, skb->len); - - if (bcs->mode == L1_MODE_TRANS) { - bytes_sent = buf_size - len; - if (skb->len < bytes_sent) - bytes_sent = skb->len; - { /* swap tx bytes to get hearable audio data */ - register unsigned char *src = skb->data; - register unsigned char *dest = urb->transfer_buffer + len; - register unsigned int count; - for (count = 0; count < bytes_sent; count++) - *dest++ = bitrev8(*src++); - } - len += bytes_sent; - } else { - len += isdnhdlc_encode(&b_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer + len, buf_size-len); - } - - skb_pull(skb, bytes_sent); - - if (!skb->len) { - // Frame sent - b_out->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize); - dev_kfree_skb_any(skb); - -/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */ -/* st5481B_sched_event(bcs, B_XMTBUFREADY); */ -/* } */ - } - } else { - if (bcs->mode == L1_MODE_TRANS) { - memset(urb->transfer_buffer + len, 0xff, buf_size-len); - len = buf_size; - } else { - // Send flags - len += isdnhdlc_encode(&b_out->hdlc_state, - NULL, 0, &bytes_sent, - urb->transfer_buffer + len, buf_size-len); - } - } - } - - // Prepare the URB - for (i = 0, offset = 0; offset < len; i++) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = packet_size; - offset += packet_size; - packet_size = SIZE_ISO_PACKETS_B_OUT; - } - urb->transfer_buffer_length = len; - urb->number_of_packets = i; - urb->dev = adapter->usb_dev; - - DBG_ISO_PACKET(0x200, urb); - - SUBMIT_URB(urb, GFP_NOIO); -} - -/* - * Start transferring (flags or data) on the B channel, since - * FIFO counters has been set to a non-zero value. - */ -static void st5481B_start_xfer(void *context) -{ - struct st5481_bcs *bcs = context; - - DBG(4, "B%d", bcs->channel + 1); - - // Start transmitting (flags or data) on B channel - - usb_b_out(bcs, 0); - usb_b_out(bcs, 1); -} - -/* - * If the adapter has only 2 LEDs, the green - * LED will blink with a rate depending - * on the number of channels opened. - */ -static void led_blink(struct st5481_adapter *adapter) -{ - u_char leds = adapter->leds; - - // 50 frames/sec for each channel - if (++adapter->led_counter % 50) { - return; - } - - if (adapter->led_counter % 100) { - leds |= GREEN_LED; - } else { - leds &= ~GREEN_LED; - } - - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL); -} - -static void usb_b_out_complete(struct urb *urb) -{ - struct st5481_bcs *bcs = urb->context; - struct st5481_b_out *b_out = &bcs->b_out; - struct st5481_adapter *adapter = bcs->adapter; - int buf_nr; - - buf_nr = get_buf_nr(b_out->urb, urb); - test_and_clear_bit(buf_nr, &b_out->busy); - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(4, "urb killed status %d", urb->status); - return; // Give up - default: - WARNING("urb status %d", urb->status); - if (b_out->busy == 0) { - st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2 | USB_DIR_OUT, NULL, NULL); - } - break; - } - } - - usb_b_out(bcs, buf_nr); - - if (adapter->number_of_leds == 2) - led_blink(adapter); -} - -/* - * Start or stop the transfer on the B channel. - */ -static void st5481B_mode(struct st5481_bcs *bcs, int mode) -{ - struct st5481_b_out *b_out = &bcs->b_out; - struct st5481_adapter *adapter = bcs->adapter; - - DBG(4, "B%d,mode=%d", bcs->channel + 1, mode); - - if (bcs->mode == mode) - return; - - bcs->mode = mode; - - // Cancel all USB transfers on this B channel - usb_unlink_urb(b_out->urb[0]); - usb_unlink_urb(b_out->urb[1]); - b_out->busy = 0; - - st5481_in_mode(&bcs->b_in, mode); - if (bcs->mode != L1_MODE_NULL) { - // Open the B channel - if (bcs->mode != L1_MODE_TRANS) { - u32 features = HDLC_BITREVERSE; - if (bcs->mode == L1_MODE_HDLC_56K) - features |= HDLC_56KBIT; - isdnhdlc_out_init(&b_out->hdlc_state, features); - } - st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2, NULL, NULL); - - // Enable B channel interrupts - st5481_usb_device_ctrl_msg(adapter, FFMSK_B1 + (bcs->channel * 2), - OUT_UP + OUT_DOWN + OUT_UNDERRUN, NULL, NULL); - - // Enable B channel FIFOs - st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 32, st5481B_start_xfer, bcs); - if (adapter->number_of_leds == 4) { - if (bcs->channel == 0) { - adapter->leds |= B1_LED; - } else { - adapter->leds |= B2_LED; - } - } - } else { - // Disable B channel interrupts - st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel * 2), 0, NULL, NULL); - - // Disable B channel FIFOs - st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 0, NULL, NULL); - - if (adapter->number_of_leds == 4) { - if (bcs->channel == 0) { - adapter->leds &= ~B1_LED; - } else { - adapter->leds &= ~B2_LED; - } - } else { - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); - } - if (b_out->tx_skb) { - dev_kfree_skb_any(b_out->tx_skb); - b_out->tx_skb = NULL; - } - - } -} - -static int st5481_setup_b_out(struct st5481_bcs *bcs) -{ - struct usb_device *dev = bcs->adapter->usb_dev; - struct usb_interface *intf; - struct usb_host_interface *altsetting = NULL; - struct usb_host_endpoint *endpoint; - struct st5481_b_out *b_out = &bcs->b_out; - - DBG(4, ""); - - intf = usb_ifnum_to_if(dev, 0); - if (intf) - altsetting = usb_altnum_to_altsetting(intf, 3); - if (!altsetting) - return -ENXIO; - - // Allocate URBs and buffers for the B channel out - endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2]; - - DBG(4, "endpoint address=%02x,packet size=%d", - endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize)); - - // Allocate memory for 8000bytes/sec + extra bytes if underrun - return st5481_setup_isocpipes(b_out->urb, dev, - usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress), - NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT, - NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST, - usb_b_out_complete, bcs); -} - -static void st5481_release_b_out(struct st5481_bcs *bcs) -{ - struct st5481_b_out *b_out = &bcs->b_out; - - DBG(4, ""); - - st5481_release_isocpipes(b_out->urb); -} - -int st5481_setup_b(struct st5481_bcs *bcs) -{ - int retval; - - DBG(4, ""); - - retval = st5481_setup_b_out(bcs); - if (retval) - goto err; - bcs->b_in.bufsize = HSCX_BUFMAX; - bcs->b_in.num_packets = NUM_ISO_PACKETS_B; - bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN; - bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN; - bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER; - bcs->b_in.adapter = bcs->adapter; - bcs->b_in.hisax_if = &bcs->b_if.ifc; - retval = st5481_setup_in(&bcs->b_in); - if (retval) - goto err_b_out; - - - return 0; - -err_b_out: - st5481_release_b_out(bcs); -err: - return retval; -} - -/* - * Release buffers and URBs for the B channels - */ -void st5481_release_b(struct st5481_bcs *bcs) -{ - DBG(4, ""); - - st5481_release_in(&bcs->b_in); - st5481_release_b_out(bcs); -} - -/* - * st5481_b_l2l1 is the entry point for upper layer routines that want to - * transmit on the B channel. PH_DATA | REQUEST is a normal packet that - * we either start transmitting (if idle) or queue (if busy). - * PH_PULL | REQUEST can be called to request a callback message - * (PH_PULL | CONFIRM) - * once the link is idle. After a "pull" callback, the upper layer - * routines can use PH_PULL | INDICATION to send data. - */ -void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct st5481_bcs *bcs = ifc->priv; - struct sk_buff *skb = arg; - long mode; - - DBG(4, ""); - - switch (pr) { - case PH_DATA | REQUEST: - BUG_ON(bcs->b_out.tx_skb); - bcs->b_out.tx_skb = skb; - break; - case PH_ACTIVATE | REQUEST: - mode = (long) arg; - DBG(4, "B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode); - st5481B_mode(bcs, mode); - B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); - break; - case PH_DEACTIVATE | REQUEST: - DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); - st5481B_mode(bcs, L1_MODE_NULL); - B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); - break; - default: - WARNING("pr %#x\n", pr); - } -} diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c deleted file mode 100644 index e88c5c71fca7..000000000000 --- a/drivers/isdn/hisax/st5481_d.c +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen - * 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include "st5481.h" - -static void ph_connect(struct st5481_adapter *adapter); -static void ph_disconnect(struct st5481_adapter *adapter); - -static struct Fsm l1fsm; - -static char *strL1State[] = -{ - "ST_L1_F3", - "ST_L1_F4", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -static char *strL1Event[] = -{ - "EV_IND_DP", - "EV_IND_1", - "EV_IND_2", - "EV_IND_3", - "EV_IND_RSY", - "EV_IND_5", - "EV_IND_6", - "EV_IND_7", - "EV_IND_AP", - "EV_IND_9", - "EV_IND_10", - "EV_IND_11", - "EV_IND_AI8", - "EV_IND_AI10", - "EV_IND_AIL", - "EV_IND_DI", - "EV_PH_ACTIVATE_REQ", - "EV_PH_DEACTIVATE_REQ", - "EV_TIMER3", -}; - -static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if; - - ifc->l1l2(ifc, pr, arg); -} - -static void -l1_go_f3(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - if (fi->state == ST_L1_F7) - ph_disconnect(adapter); - - FsmChangeState(fi, ST_L1_F3); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void -l1_go_f6(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - if (fi->state == ST_L1_F7) - ph_disconnect(adapter); - - FsmChangeState(fi, ST_L1_F6); -} - -static void -l1_go_f7(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - FsmDelTimer(&adapter->timer, 0); - ph_connect(adapter); - FsmChangeState(fi, ST_L1_F7); - D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL); -} - -static void -l1_go_f8(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - if (fi->state == ST_L1_F7) - ph_disconnect(adapter); - - FsmChangeState(fi, ST_L1_F8); -} - -static void -l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - st5481_ph_command(adapter, ST5481_CMD_DR); - FsmChangeState(fi, ST_L1_F3); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void -l1_ignore(struct FsmInst *fi, int event, void *arg) -{ -} - -static void -l1_activate(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - st5481_ph_command(adapter, ST5481_CMD_DR); - st5481_ph_command(adapter, ST5481_CMD_PUP); - FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - st5481_ph_command(adapter, ST5481_CMD_AR8); - FsmChangeState(fi, ST_L1_F4); -} - -static struct FsmNode L1FnList[] __initdata = -{ - {ST_L1_F3, EV_IND_DP, l1_ignore}, - {ST_L1_F3, EV_IND_AP, l1_go_f6}, - {ST_L1_F3, EV_IND_AI8, l1_go_f7}, - {ST_L1_F3, EV_IND_AI10, l1_go_f7}, - {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate}, - - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_IND_DP, l1_go_f3}, - {ST_L1_F4, EV_IND_AP, l1_go_f6}, - {ST_L1_F4, EV_IND_AI8, l1_go_f7}, - {ST_L1_F4, EV_IND_AI10, l1_go_f7}, - - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_IND_DP, l1_go_f3}, - {ST_L1_F6, EV_IND_AP, l1_ignore}, - {ST_L1_F6, EV_IND_AI8, l1_go_f7}, - {ST_L1_F6, EV_IND_AI10, l1_go_f7}, - {ST_L1_F7, EV_IND_RSY, l1_go_f8}, - - {ST_L1_F7, EV_IND_DP, l1_go_f3}, - {ST_L1_F7, EV_IND_AP, l1_go_f6}, - {ST_L1_F7, EV_IND_AI8, l1_ignore}, - {ST_L1_F7, EV_IND_AI10, l1_ignore}, - {ST_L1_F7, EV_IND_RSY, l1_go_f8}, - - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_IND_DP, l1_go_f3}, - {ST_L1_F8, EV_IND_AP, l1_go_f6}, - {ST_L1_F8, EV_IND_AI8, l1_go_f8}, - {ST_L1_F8, EV_IND_AI10, l1_go_f8}, - {ST_L1_F8, EV_IND_RSY, l1_ignore}, -}; - -static __printf(2, 3) - void l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - DBG(8, "%s", buf); - va_end(args); -} - -/* ====================================================================== - * D-Channel out - */ - -/* - D OUT state machine: - ==================== - - Transmit short frame (< 16 bytes of encoded data): - - L1 FRAME D_OUT_STATE USB D CHANNEL - -------- ----------- --- --------- - - FIXME - - -> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF] - SHORT_WAIT_DEN <> OUT_D_COUNTER=16 - - END_OF_SHORT <- DEN_EVENT -> 7Exx - xxxx - xxxx - xxxx - xxxx - xxxx - C1C1 - 7EFF - WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms) - IDLE <> Reset pipe - - - - Transmit long frame (>= 16 bytes of encoded data): - - L1 FRAME D_OUT_STATE USB D CHANNEL - -------- ----------- --- --------- - - -> [xx...xx] IDLE - WAIT_FOR_STOP <> OUT_D_COUNTER=0 - WAIT_FOR_RESET <> Reset pipe - STOP - INIT_LONG_FRAME -> [7Exx..xx] - WAIT_DEN <> OUT_D_COUNTER=16 - OUT_NORMAL <- DEN_EVENT -> 7Exx - END_OF_FRAME_BUSY -> [xxxx] xxxx - END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx - -> [xxxx] xxxx - -> [C1C2] xxxx - -> [7EFF] xxxx - xxxx - xxxx - .... - xxxx - C1C2 - 7EFF - <- D_UNDERRUN <- (> 8ms) - WAIT_FOR_STOP <> OUT_D_COUNTER=0 - WAIT_FOR_RESET <> Reset pipe - STOP - -*/ - -static struct Fsm dout_fsm; - -static char *strDoutState[] = -{ - "ST_DOUT_NONE", - - "ST_DOUT_SHORT_INIT", - "ST_DOUT_SHORT_WAIT_DEN", - - "ST_DOUT_LONG_INIT", - "ST_DOUT_LONG_WAIT_DEN", - "ST_DOUT_NORMAL", - - "ST_DOUT_WAIT_FOR_UNDERRUN", - "ST_DOUT_WAIT_FOR_NOT_BUSY", - "ST_DOUT_WAIT_FOR_STOP", - "ST_DOUT_WAIT_FOR_RESET", -}; - -static char *strDoutEvent[] = -{ - "EV_DOUT_START_XMIT", - "EV_DOUT_COMPLETE", - "EV_DOUT_DEN", - "EV_DOUT_RESETED", - "EV_DOUT_STOPPED", - "EV_DOUT_COLL", - "EV_DOUT_UNDERRUN", -}; - -static __printf(2, 3) - void dout_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - DBG(0x2, "%s", buf); - va_end(args); -} - -static void dout_stop_event(void *context) -{ - struct st5481_adapter *adapter = context; - - FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL); -} - -/* - * Start the transfer of a D channel frame. - */ -static void usb_d_out(struct st5481_adapter *adapter, int buf_nr) -{ - struct st5481_d_out *d_out = &adapter->d_out; - struct urb *urb; - unsigned int num_packets, packet_offset; - int len, buf_size, bytes_sent; - struct sk_buff *skb; - struct usb_iso_packet_descriptor *desc; - - if (d_out->fsm.state != ST_DOUT_NORMAL) - return; - - if (test_and_set_bit(buf_nr, &d_out->busy)) { - DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); - return; - } - urb = d_out->urb[buf_nr]; - - skb = d_out->tx_skb; - - buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT; - - if (skb) { - len = isdnhdlc_encode(&d_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer, buf_size); - skb_pull(skb, bytes_sent); - } else { - // Send flags or idle - len = isdnhdlc_encode(&d_out->hdlc_state, - NULL, 0, &bytes_sent, - urb->transfer_buffer, buf_size); - } - - if (len < buf_size) { - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN); - } - if (skb && !skb->len) { - d_out->tx_skb = NULL; - D_L1L2(adapter, PH_DATA | CONFIRM, NULL); - dev_kfree_skb_any(skb); - } - - // Prepare the URB - urb->transfer_buffer_length = len; - num_packets = 0; - packet_offset = 0; - while (packet_offset < len) { - desc = &urb->iso_frame_desc[num_packets]; - desc->offset = packet_offset; - desc->length = SIZE_ISO_PACKETS_D_OUT; - if (len - packet_offset < desc->length) - desc->length = len - packet_offset; - num_packets++; - packet_offset += desc->length; - } - urb->number_of_packets = num_packets; - - // Prepare the URB - urb->dev = adapter->usb_dev; - // Need to transmit the next buffer 2ms after the DEN_EVENT - urb->transfer_flags = 0; - urb->start_frame = usb_get_current_frame_number(adapter->usb_dev) + 2; - - DBG_ISO_PACKET(0x20, urb); - - if (usb_submit_urb(urb, GFP_KERNEL) < 0) { - // There is another URB queued up - urb->transfer_flags = URB_ISO_ASAP; - SUBMIT_URB(urb, GFP_KERNEL); - } -} - -static void fifo_reseted(void *context) -{ - struct st5481_adapter *adapter = context; - - FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL); -} - -static void usb_d_out_complete(struct urb *urb) -{ - struct st5481_adapter *adapter = urb->context; - struct st5481_d_out *d_out = &adapter->d_out; - long buf_nr; - - DBG(2, ""); - - buf_nr = get_buf_nr(d_out->urb, urb); - test_and_clear_bit(buf_nr, &d_out->busy); - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(1, "urb killed status %d", urb->status); - break; - default: - WARNING("urb status %d", urb->status); - if (d_out->busy == 0) { - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); - } - break; - } - return; // Give up - } - - FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr); -} - -/* ====================================================================== */ - -static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg) -{ - // FIXME unify? - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - struct urb *urb; - int len, bytes_sent; - struct sk_buff *skb; - int buf_nr = 0; - - skb = d_out->tx_skb; - - DBG(2, "len=%d", skb->len); - - isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE); - - if (test_and_set_bit(buf_nr, &d_out->busy)) { - WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); - return; - } - urb = d_out->urb[buf_nr]; - - DBG_SKB(0x10, skb); - len = isdnhdlc_encode(&d_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer, 16); - skb_pull(skb, bytes_sent); - - if (len < 16) - FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_INIT); - else - FsmChangeState(&d_out->fsm, ST_DOUT_LONG_INIT); - - if (skb->len == 0) { - d_out->tx_skb = NULL; - D_L1L2(adapter, PH_DATA | CONFIRM, NULL); - dev_kfree_skb_any(skb); - } - -// Prepare the URB - urb->transfer_buffer_length = len; - - urb->iso_frame_desc[0].offset = 0; - urb->iso_frame_desc[0].length = len; - urb->number_of_packets = 1; - - // Prepare the URB - urb->dev = adapter->usb_dev; - urb->transfer_flags = URB_ISO_ASAP; - - DBG_ISO_PACKET(0x20, urb); - SUBMIT_URB(urb, GFP_KERNEL); -} - -static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_WAIT_DEN); - st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL); -} - -static void dout_end_short_frame(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN); -} - -static void dout_long_enable_fifo(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL); - FsmChangeState(&d_out->fsm, ST_DOUT_LONG_WAIT_DEN); -} - -static void dout_long_den(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_NORMAL); - usb_d_out(adapter, 0); - usb_d_out(adapter, 1); -} - -static void dout_reset(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_RESET); - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); -} - -static void dout_stop(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_STOP); - st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 0, dout_stop_event, adapter); -} - -static void dout_underrun(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - if (test_bit(0, &d_out->busy) || test_bit(1, &d_out->busy)) { - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_NOT_BUSY); - } else { - dout_stop(fsm, event, arg); - } -} - -static void dout_check_busy(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - if (!test_bit(0, &d_out->busy) && !test_bit(1, &d_out->busy)) - dout_stop(fsm, event, arg); -} - -static void dout_reseted(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_NONE); - // FIXME locking - if (d_out->tx_skb) - FsmEvent(&d_out->fsm, EV_DOUT_START_XMIT, NULL); -} - -static void dout_complete(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - long buf_nr = (long) arg; - - usb_d_out(adapter, buf_nr); -} - -static void dout_ignore(struct FsmInst *fsm, int event, void *arg) -{ -} - -static struct FsmNode DoutFnList[] __initdata = -{ - {ST_DOUT_NONE, EV_DOUT_START_XMIT, dout_start_xmit}, - - {ST_DOUT_SHORT_INIT, EV_DOUT_COMPLETE, dout_short_fifo}, - - {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_DEN, dout_end_short_frame}, - {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun}, - - {ST_DOUT_LONG_INIT, EV_DOUT_COMPLETE, dout_long_enable_fifo}, - - {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_DEN, dout_long_den}, - {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun}, - - {ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun}, - {ST_DOUT_NORMAL, EV_DOUT_COMPLETE, dout_complete}, - - {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_UNDERRUN, dout_underrun}, - {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_COMPLETE, dout_ignore}, - - {ST_DOUT_WAIT_FOR_NOT_BUSY, EV_DOUT_COMPLETE, dout_check_busy}, - - {ST_DOUT_WAIT_FOR_STOP, EV_DOUT_STOPPED, dout_reset}, - - {ST_DOUT_WAIT_FOR_RESET, EV_DOUT_RESETED, dout_reseted}, -}; - -void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) -{ - struct st5481_adapter *adapter = hisax_d_if->priv; - struct sk_buff *skb = arg; - - switch (pr) { - case PH_ACTIVATE | REQUEST: - FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL); - break; - case PH_DEACTIVATE | REQUEST: - FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL); - break; - case PH_DATA | REQUEST: - DBG(2, "PH_DATA REQUEST len %d", skb->len); - BUG_ON(adapter->d_out.tx_skb); - adapter->d_out.tx_skb = skb; - FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL); - break; - default: - WARNING("pr %#x\n", pr); - break; - } -} - -/* ====================================================================== - */ - -/* - * Start receiving on the D channel since entered state F7. - */ -static void ph_connect(struct st5481_adapter *adapter) -{ - struct st5481_d_out *d_out = &adapter->d_out; - struct st5481_in *d_in = &adapter->d_in; - - DBG(8, ""); - - FsmChangeState(&d_out->fsm, ST_DOUT_NONE); - - // st5481_usb_device_ctrl_msg(adapter, FFMSK_D, OUT_UNDERRUN, NULL, NULL); - st5481_usb_device_ctrl_msg(adapter, FFMSK_D, 0xfc, NULL, NULL); - st5481_in_mode(d_in, L1_MODE_HDLC); - -#ifdef LOOPBACK - // Turn loopback on (data sent on B and D looped back) - st5481_usb_device_ctrl_msg(cs, LBB, 0x04, NULL, NULL); -#endif - - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, NULL, NULL); - - // Turn on the green LED to tell that we are in state F7 - adapter->leds |= GREEN_LED; - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); -} - -/* - * Stop receiving on the D channel since not in state F7. - */ -static void ph_disconnect(struct st5481_adapter *adapter) -{ - DBG(8, ""); - - st5481_in_mode(&adapter->d_in, L1_MODE_NULL); - - // Turn off the green LED to tell that we left state F7 - adapter->leds &= ~GREEN_LED; - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); -} - -static int st5481_setup_d_out(struct st5481_adapter *adapter) -{ - struct usb_device *dev = adapter->usb_dev; - struct usb_interface *intf; - struct usb_host_interface *altsetting = NULL; - struct usb_host_endpoint *endpoint; - struct st5481_d_out *d_out = &adapter->d_out; - - DBG(2, ""); - - intf = usb_ifnum_to_if(dev, 0); - if (intf) - altsetting = usb_altnum_to_altsetting(intf, 3); - if (!altsetting) - return -ENXIO; - - // Allocate URBs and buffers for the D channel out - endpoint = &altsetting->endpoint[EP_D_OUT-1]; - - DBG(2, "endpoint address=%02x,packet size=%d", - endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize)); - - return st5481_setup_isocpipes(d_out->urb, dev, - usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress), - NUM_ISO_PACKETS_D, SIZE_ISO_PACKETS_D_OUT, - NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT, - usb_d_out_complete, adapter); -} - -static void st5481_release_d_out(struct st5481_adapter *adapter) -{ - struct st5481_d_out *d_out = &adapter->d_out; - - DBG(2, ""); - - st5481_release_isocpipes(d_out->urb); -} - -int st5481_setup_d(struct st5481_adapter *adapter) -{ - int retval; - - DBG(2, ""); - - retval = st5481_setup_d_out(adapter); - if (retval) - goto err; - adapter->d_in.bufsize = MAX_DFRAME_LEN_L1; - adapter->d_in.num_packets = NUM_ISO_PACKETS_D; - adapter->d_in.packet_size = SIZE_ISO_PACKETS_D_IN; - adapter->d_in.ep = EP_D_IN | USB_DIR_IN; - adapter->d_in.counter = IN_D_COUNTER; - adapter->d_in.adapter = adapter; - adapter->d_in.hisax_if = &adapter->hisax_d_if.ifc; - retval = st5481_setup_in(&adapter->d_in); - if (retval) - goto err_d_out; - - adapter->l1m.fsm = &l1fsm; - adapter->l1m.state = ST_L1_F3; - adapter->l1m.debug = st5481_debug & 0x100; - adapter->l1m.userdata = adapter; - adapter->l1m.printdebug = l1m_debug; - FsmInitTimer(&adapter->l1m, &adapter->timer); - - adapter->d_out.fsm.fsm = &dout_fsm; - adapter->d_out.fsm.state = ST_DOUT_NONE; - adapter->d_out.fsm.debug = st5481_debug & 0x100; - adapter->d_out.fsm.userdata = adapter; - adapter->d_out.fsm.printdebug = dout_debug; - - return 0; - -err_d_out: - st5481_release_d_out(adapter); -err: - return retval; -} - -void st5481_release_d(struct st5481_adapter *adapter) -{ - DBG(2, ""); - - st5481_release_in(&adapter->d_in); - st5481_release_d_out(adapter); -} - -/* ====================================================================== - * init / exit - */ - -int __init st5481_d_init(void) -{ - int retval; - - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strEvent = strL1Event; - l1fsm.strState = strL1State; - retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); - if (retval) - goto err; - - dout_fsm.state_count = DOUT_STATE_COUNT; - dout_fsm.event_count = DOUT_EVENT_COUNT; - dout_fsm.strEvent = strDoutEvent; - dout_fsm.strState = strDoutState; - retval = FsmNew(&dout_fsm, DoutFnList, ARRAY_SIZE(DoutFnList)); - if (retval) - goto err_l1; - - return 0; - -err_l1: - FsmFree(&l1fsm); -err: - return retval; -} - -// can't be __exit -void st5481_d_exit(void) -{ - FsmFree(&l1fsm); - FsmFree(&dout_fsm); -} diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c deleted file mode 100644 index 54ef9e4f8cbc..000000000000 --- a/drivers/isdn/hisax/st5481_init.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen - * 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* - * TODO: - * - * b layer1 delay? - * hotplug / unregister issues - * mod_inc/dec_use_count - * unify parts of d/b channel usb handling - * file header - * avoid copy to isoc buffer? - * improve usb delay? - * merge l1 state machines? - * clean up debug - */ - -#include -#include -#include -#include -#include "st5481.h" - -MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter"); -MODULE_AUTHOR("Frode Isaksen"); -MODULE_LICENSE("GPL"); - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int number_of_leds = 2; /* 2 LEDs on the adpater default */ -module_param(number_of_leds, int, 0); - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 0; -module_param(debug, int, 0); -#endif -int st5481_debug; - -/* ====================================================================== - * registration/deregistration with the USB layer - */ - -/* - * This function will be called when the adapter is plugged - * into the USB bus. - */ -static int probe_st5481(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct st5481_adapter *adapter; - struct hisax_b_if *b_if[2]; - int retval, i; - - printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct), - number_of_leds); - - adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL); - if (!adapter) - return -ENOMEM; - - adapter->number_of_leds = number_of_leds; - adapter->usb_dev = dev; - - adapter->hisax_d_if.owner = THIS_MODULE; - adapter->hisax_d_if.ifc.priv = adapter; - adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1; - - for (i = 0; i < 2; i++) { - adapter->bcs[i].adapter = adapter; - adapter->bcs[i].channel = i; - adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; - adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; - } - - retval = st5481_setup_usb(adapter); - if (retval < 0) - goto err; - - retval = st5481_setup_d(adapter); - if (retval < 0) - goto err_usb; - - retval = st5481_setup_b(&adapter->bcs[0]); - if (retval < 0) - goto err_d; - - retval = st5481_setup_b(&adapter->bcs[1]); - if (retval < 0) - goto err_b; - - for (i = 0; i < 2; i++) - b_if[i] = &adapter->bcs[i].b_if; - - if (hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", - protocol) != 0) - goto err_b1; - - st5481_start(adapter); - - usb_set_intfdata(intf, adapter); - return 0; - -err_b1: - st5481_release_b(&adapter->bcs[1]); -err_b: - st5481_release_b(&adapter->bcs[0]); -err_d: - st5481_release_d(adapter); -err_usb: - st5481_release_usb(adapter); -err: - kfree(adapter); - return -EIO; -} - -/* - * This function will be called when the adapter is removed - * from the USB bus. - */ -static void disconnect_st5481(struct usb_interface *intf) -{ - struct st5481_adapter *adapter = usb_get_intfdata(intf); - - DBG(1, ""); - - usb_set_intfdata(intf, NULL); - if (!adapter) - return; - - st5481_stop(adapter); - st5481_release_b(&adapter->bcs[1]); - st5481_release_b(&adapter->bcs[0]); - st5481_release_d(adapter); - // we would actually better wait for completion of outstanding urbs - mdelay(2); - st5481_release_usb(adapter); - - hisax_unregister(&adapter->hisax_d_if); - - kfree(adapter); -} - -/* - * The last 4 bits in the Product Id is set with 4 pins on the chip. - */ -static struct usb_device_id st5481_ids[] = { - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x0) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x1) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x2) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x3) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x4) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x5) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x6) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x7) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x8) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x9) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xA) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xB) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xC) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xD) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xE) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xF) }, - { } -}; -MODULE_DEVICE_TABLE(usb, st5481_ids); - -static struct usb_driver st5481_usb_driver = { - .name = "st5481_usb", - .probe = probe_st5481, - .disconnect = disconnect_st5481, - .id_table = st5481_ids, - .disable_hub_initiated_lpm = 1, -}; - -static int __init st5481_usb_init(void) -{ - int retval; - -#ifdef CONFIG_HISAX_DEBUG - st5481_debug = debug; -#endif - - printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n"); - - retval = st5481_d_init(); - if (retval < 0) - goto out; - - retval = usb_register(&st5481_usb_driver); - if (retval < 0) - goto out_d_exit; - - return 0; - -out_d_exit: - st5481_d_exit(); -out: - return retval; -} - -static void __exit st5481_usb_exit(void) -{ - usb_deregister(&st5481_usb_driver); - st5481_d_exit(); -} - -module_init(st5481_usb_init); -module_exit(st5481_usb_exit); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c deleted file mode 100644 index f207fda691c7..000000000000 --- a/drivers/isdn/hisax/st5481_usb.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen - * 2001 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include "st5481.h" - -static int st5481_isoc_flatten(struct urb *urb); - -/* ====================================================================== - * control pipe - */ - -/* - * Send the next endpoint 0 request stored in the FIFO. - * Called either by the completion or by usb_ctrl_msg. - */ -static void usb_next_ctrl_msg(struct urb *urb, - struct st5481_adapter *adapter) -{ - struct st5481_ctrl *ctrl = &adapter->ctrl; - int r_index; - - if (test_and_set_bit(0, &ctrl->busy)) { - return; - } - - if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) { - test_and_clear_bit(0, &ctrl->busy); - return; - } - urb->setup_packet = - (unsigned char *)&ctrl->msg_fifo.data[r_index]; - - DBG(1, "request=0x%02x,value=0x%04x,index=%x", - ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest, - ((struct ctrl_msg *)urb->setup_packet)->dr.wValue, - ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex); - - // Prepare the URB - urb->dev = adapter->usb_dev; - - SUBMIT_URB(urb, GFP_ATOMIC); -} - -/* - * Asynchronous endpoint 0 request (async version of usb_control_msg). - * The request will be queued up in a FIFO if the endpoint is busy. - */ -static void usb_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u8 requesttype, u16 value, u16 index, - ctrl_complete_t complete, void *context) -{ - struct st5481_ctrl *ctrl = &adapter->ctrl; - int w_index; - struct ctrl_msg *ctrl_msg; - - if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) { - WARNING("control msg FIFO full"); - return; - } - ctrl_msg = &ctrl->msg_fifo.data[w_index]; - - ctrl_msg->dr.bRequestType = requesttype; - ctrl_msg->dr.bRequest = request; - ctrl_msg->dr.wValue = cpu_to_le16p(&value); - ctrl_msg->dr.wIndex = cpu_to_le16p(&index); - ctrl_msg->dr.wLength = 0; - ctrl_msg->complete = complete; - ctrl_msg->context = context; - - usb_next_ctrl_msg(ctrl->urb, adapter); -} - -/* - * Asynchronous endpoint 0 device request. - */ -void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u16 value, - ctrl_complete_t complete, void *context) -{ - usb_ctrl_msg(adapter, request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, complete, context); -} - -/* - * Asynchronous pipe reset (async version of usb_clear_halt). - */ -void st5481_usb_pipe_reset(struct st5481_adapter *adapter, - u_char pipe, - ctrl_complete_t complete, void *context) -{ - DBG(1, "pipe=%02x", pipe); - - usb_ctrl_msg(adapter, - USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT, - 0, pipe, complete, context); -} - - -/* - Physical level functions -*/ - -void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command) -{ - DBG(8, "command=%s", ST5481_CMD_string(command)); - - st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL); -} - -/* - * The request on endpoint 0 has completed. - * Call the user provided completion routine and try - * to send the next request. - */ -static void usb_ctrl_complete(struct urb *urb) -{ - struct st5481_adapter *adapter = urb->context; - struct st5481_ctrl *ctrl = &adapter->ctrl; - struct ctrl_msg *ctrl_msg; - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(1, "urb killed status %d", urb->status); - return; // Give up - default: - WARNING("urb status %d", urb->status); - break; - } - } - - ctrl_msg = (struct ctrl_msg *)urb->setup_packet; - - if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { - /* Special case handling for pipe reset */ - le16_to_cpus(&ctrl_msg->dr.wIndex); - usb_reset_endpoint(adapter->usb_dev, ctrl_msg->dr.wIndex); - } - - if (ctrl_msg->complete) - ctrl_msg->complete(ctrl_msg->context); - - clear_bit(0, &ctrl->busy); - - // Try to send next control message - usb_next_ctrl_msg(urb, adapter); - return; -} - -/* ====================================================================== - * interrupt pipe - */ - -/* - * The interrupt endpoint will be called when any - * of the 6 registers changes state (depending on masks). - * Decode the register values and schedule a private event. - * Called at interrupt. - */ -static void usb_int_complete(struct urb *urb) -{ - u8 *data = urb->transfer_buffer; - u8 irqbyte; - struct st5481_adapter *adapter = urb->context; - int j; - int status; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - DBG(2, "urb shutting down with status: %d", urb->status); - return; - default: - WARNING("nonzero urb status received: %d", urb->status); - goto exit; - } - - - DBG_PACKET(2, data, INT_PKT_SIZE); - - if (urb->actual_length == 0) { - goto exit; - } - - irqbyte = data[MPINT]; - if (irqbyte & DEN_INT) - FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL); - - if (irqbyte & DCOLL_INT) - FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL); - - irqbyte = data[FFINT_D]; - if (irqbyte & OUT_UNDERRUN) - FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL); - - if (irqbyte & OUT_DOWN) - ;// printk("OUT_DOWN\n"); - - irqbyte = data[MPINT]; - if (irqbyte & RXCI_INT) - FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL); - - for (j = 0; j < 2; j++) - adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j]; - - urb->actual_length = 0; - -exit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - WARNING("usb_submit_urb failed with result %d", status); -} - -/* ====================================================================== - * initialization - */ - -int st5481_setup_usb(struct st5481_adapter *adapter) -{ - struct usb_device *dev = adapter->usb_dev; - struct st5481_ctrl *ctrl = &adapter->ctrl; - struct st5481_intr *intr = &adapter->intr; - struct usb_interface *intf; - struct usb_host_interface *altsetting = NULL; - struct usb_host_endpoint *endpoint; - int status; - struct urb *urb; - u8 *buf; - - DBG(2, ""); - - if ((status = usb_reset_configuration(dev)) < 0) { - WARNING("reset_configuration failed,status=%d", status); - return status; - } - - intf = usb_ifnum_to_if(dev, 0); - if (intf) - altsetting = usb_altnum_to_altsetting(intf, 3); - if (!altsetting) - return -ENXIO; - - // Check if the config is sane - if (altsetting->desc.bNumEndpoints != 7) { - WARNING("expecting 7 got %d endpoints!", altsetting->desc.bNumEndpoints); - return -EINVAL; - } - - // The descriptor is wrong for some early samples of the ST5481 chip - altsetting->endpoint[3].desc.wMaxPacketSize = cpu_to_le16(32); - altsetting->endpoint[4].desc.wMaxPacketSize = cpu_to_le16(32); - - // Use alternative setting 3 on interface 0 to have 2B+D - if ((status = usb_set_interface(dev, 0, 3)) < 0) { - WARNING("usb_set_interface failed,status=%d", status); - return status; - } - - // Allocate URB for control endpoint - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - return -ENOMEM; - } - ctrl->urb = urb; - - // Fill the control URB - usb_fill_control_urb(urb, dev, - usb_sndctrlpipe(dev, 0), - NULL, NULL, 0, usb_ctrl_complete, adapter); - - - fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data)); - - // Allocate URBs and buffers for interrupt endpoint - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - goto err1; - } - intr->urb = urb; - - buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL); - if (!buf) { - goto err2; - } - - endpoint = &altsetting->endpoint[EP_INT-1]; - - // Fill the interrupt URB - usb_fill_int_urb(urb, dev, - usb_rcvintpipe(dev, endpoint->desc.bEndpointAddress), - buf, INT_PKT_SIZE, - usb_int_complete, adapter, - endpoint->desc.bInterval); - - return 0; -err2: - usb_free_urb(intr->urb); - intr->urb = NULL; -err1: - usb_free_urb(ctrl->urb); - ctrl->urb = NULL; - - return -ENOMEM; -} - -/* - * Release buffers and URBs for the interrupt and control - * endpoint. - */ -void st5481_release_usb(struct st5481_adapter *adapter) -{ - struct st5481_intr *intr = &adapter->intr; - struct st5481_ctrl *ctrl = &adapter->ctrl; - - DBG(1, ""); - - // Stop and free Control and Interrupt URBs - usb_kill_urb(ctrl->urb); - kfree(ctrl->urb->transfer_buffer); - usb_free_urb(ctrl->urb); - ctrl->urb = NULL; - - usb_kill_urb(intr->urb); - kfree(intr->urb->transfer_buffer); - usb_free_urb(intr->urb); - intr->urb = NULL; -} - -/* - * Initialize the adapter. - */ -void st5481_start(struct st5481_adapter *adapter) -{ - static const u8 init_cmd_table[] = { - SET_DEFAULT, 0, - STT, 0, - SDA_MIN, 0x0d, - SDA_MAX, 0x29, - SDELAY_VALUE, 0x14, - GPIO_DIR, 0x01, - GPIO_OUT, RED_LED, -// FFCTRL_OUT_D,4, -// FFCTRH_OUT_D,12, - FFCTRL_OUT_B1, 6, - FFCTRH_OUT_B1, 20, - FFCTRL_OUT_B2, 6, - FFCTRH_OUT_B2, 20, - MPMSK, RXCI_INT + DEN_INT + DCOLL_INT, - 0 - }; - struct st5481_intr *intr = &adapter->intr; - int i = 0; - u8 request, value; - - DBG(8, ""); - - adapter->leds = RED_LED; - - // Start receiving on the interrupt endpoint - SUBMIT_URB(intr->urb, GFP_KERNEL); - - while ((request = init_cmd_table[i++])) { - value = init_cmd_table[i++]; - st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL); - } - st5481_ph_command(adapter, ST5481_CMD_PUP); -} - -/* - * Reset the adapter to default values. - */ -void st5481_stop(struct st5481_adapter *adapter) -{ - DBG(8, ""); - - st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL); -} - -/* ====================================================================== - * isochronous USB helpers - */ - -static void -fill_isoc_urb(struct urb *urb, struct usb_device *dev, - unsigned int pipe, void *buf, int num_packets, - int packet_size, usb_complete_t complete, - void *context) -{ - int k; - - usb_fill_int_urb(urb, dev, pipe, buf, num_packets * packet_size, - complete, context, 1); - - urb->number_of_packets = num_packets; - urb->transfer_flags = URB_ISO_ASAP; - for (k = 0; k < num_packets; k++) { - urb->iso_frame_desc[k].offset = packet_size * k; - urb->iso_frame_desc[k].length = packet_size; - urb->iso_frame_desc[k].actual_length = 0; - } -} - -int -st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev, - unsigned int pipe, int num_packets, - int packet_size, int buf_size, - usb_complete_t complete, void *context) -{ - int j, retval; - unsigned char *buf; - - for (j = 0; j < 2; j++) { - retval = -ENOMEM; - urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL); - if (!urb[j]) - goto err; - - // Allocate memory for 2000bytes/sec (16Kb/s) - buf = kmalloc(buf_size, GFP_KERNEL); - if (!buf) - goto err; - - // Fill the isochronous URB - fill_isoc_urb(urb[j], dev, pipe, buf, - num_packets, packet_size, complete, - context); - } - return 0; - -err: - for (j = 0; j < 2; j++) { - if (urb[j]) { - kfree(urb[j]->transfer_buffer); - urb[j]->transfer_buffer = NULL; - usb_free_urb(urb[j]); - urb[j] = NULL; - } - } - return retval; -} - -void st5481_release_isocpipes(struct urb *urb[2]) -{ - int j; - - for (j = 0; j < 2; j++) { - usb_kill_urb(urb[j]); - kfree(urb[j]->transfer_buffer); - usb_free_urb(urb[j]); - urb[j] = NULL; - } -} - -/* - * Decode frames received on the B/D channel. - * Note that this function will be called continuously - * with 64Kbit/s / 16Kbit/s of data and hence it will be - * called 50 times per second with 20 ISOC descriptors. - * Called at interrupt. - */ -static void usb_in_complete(struct urb *urb) -{ - struct st5481_in *in = urb->context; - unsigned char *ptr; - struct sk_buff *skb; - int len, count, status; - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(1, "urb killed status %d", urb->status); - return; // Give up - default: - WARNING("urb status %d", urb->status); - break; - } - } - - DBG_ISO_PACKET(0x80, urb); - - len = st5481_isoc_flatten(urb); - ptr = urb->transfer_buffer; - while (len > 0) { - if (in->mode == L1_MODE_TRANS) { - memcpy(in->rcvbuf, ptr, len); - status = len; - len = 0; - } else { - status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count, - in->rcvbuf, in->bufsize); - ptr += count; - len -= count; - } - - if (status > 0) { - // Good frame received - DBG(4, "count=%d", status); - DBG_PACKET(0x400, in->rcvbuf, status); - if (!(skb = dev_alloc_skb(status))) { - WARNING("receive out of memory\n"); - break; - } - skb_put_data(skb, in->rcvbuf, status); - in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb); - } else if (status == -HDLC_CRC_ERROR) { - INFO("CRC error"); - } else if (status == -HDLC_FRAMING_ERROR) { - INFO("framing error"); - } else if (status == -HDLC_LENGTH_ERROR) { - INFO("length error"); - } - } - - // Prepare URB for next transfer - urb->dev = in->adapter->usb_dev; - urb->actual_length = 0; - - SUBMIT_URB(urb, GFP_ATOMIC); -} - -int st5481_setup_in(struct st5481_in *in) -{ - struct usb_device *dev = in->adapter->usb_dev; - int retval; - - DBG(4, ""); - - in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL); - retval = -ENOMEM; - if (!in->rcvbuf) - goto err; - - retval = st5481_setup_isocpipes(in->urb, dev, - usb_rcvisocpipe(dev, in->ep), - in->num_packets, in->packet_size, - in->num_packets * in->packet_size, - usb_in_complete, in); - if (retval) - goto err_free; - return 0; - -err_free: - kfree(in->rcvbuf); -err: - return retval; -} - -void st5481_release_in(struct st5481_in *in) -{ - DBG(2, ""); - - st5481_release_isocpipes(in->urb); -} - -/* - * Make the transfer_buffer contiguous by - * copying from the iso descriptors if necessary. - */ -static int st5481_isoc_flatten(struct urb *urb) -{ - struct usb_iso_packet_descriptor *pipd, *pend; - unsigned char *src, *dst; - unsigned int len; - - if (urb->status < 0) { - return urb->status; - } - for (pipd = &urb->iso_frame_desc[0], - pend = &urb->iso_frame_desc[urb->number_of_packets], - dst = urb->transfer_buffer; - pipd < pend; - pipd++) { - - if (pipd->status < 0) { - return (pipd->status); - } - - len = pipd->actual_length; - pipd->actual_length = 0; - src = urb->transfer_buffer + pipd->offset; - - if (src != dst) { - // Need to copy since isoc buffers not full - while (len--) { - *dst++ = *src++; - } - } else { - // No need to copy, just update destination buffer - dst += len; - } - } - // Return size of flattened buffer - return (dst - (unsigned char *)urb->transfer_buffer); -} - -static void st5481_start_rcv(void *context) -{ - struct st5481_in *in = context; - struct st5481_adapter *adapter = in->adapter; - - DBG(4, ""); - - in->urb[0]->dev = adapter->usb_dev; - SUBMIT_URB(in->urb[0], GFP_KERNEL); - - in->urb[1]->dev = adapter->usb_dev; - SUBMIT_URB(in->urb[1], GFP_KERNEL); -} - -void st5481_in_mode(struct st5481_in *in, int mode) -{ - if (in->mode == mode) - return; - - in->mode = mode; - - usb_unlink_urb(in->urb[0]); - usb_unlink_urb(in->urb[1]); - - if (in->mode != L1_MODE_NULL) { - if (in->mode != L1_MODE_TRANS) { - u32 features = HDLC_BITREVERSE; - - if (in->mode == L1_MODE_HDLC_56K) - features |= HDLC_56KBIT; - isdnhdlc_rcv_init(&in->hdlc_state, features); - } - st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); - st5481_usb_device_ctrl_msg(in->adapter, in->counter, - in->packet_size, - NULL, NULL); - st5481_start_rcv(in); - } else { - st5481_usb_device_ctrl_msg(in->adapter, in->counter, - 0, NULL, NULL); - } -} diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c deleted file mode 100644 index 9195f9fd628f..000000000000 --- a/drivers/isdn/hisax/tei.c +++ /dev/null @@ -1,465 +0,0 @@ -/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $ - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For changes and modifications please read - * Documentation/isdn/HiSax.cert - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include "hisax.h" -#include "isdnl2.h" -#include -#include -#include - -const char *tei_revision = "$Revision: 2.20.2.3 $"; - -#define ID_REQUEST 1 -#define ID_ASSIGNED 2 -#define ID_DENIED 3 -#define ID_CHK_REQ 4 -#define ID_CHK_RES 5 -#define ID_REMOVE 6 -#define ID_VERIFY 7 - -#define TEI_ENTITY_ID 0xf - -static struct Fsm teifsm; - -void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb); - -enum { - ST_TEI_NOP, - ST_TEI_IDREQ, - ST_TEI_IDVERIFY, -}; - -#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1) - -static char *strTeiState[] = -{ - "ST_TEI_NOP", - "ST_TEI_IDREQ", - "ST_TEI_IDVERIFY", -}; - -enum { - EV_IDREQ, - EV_ASSIGN, - EV_DENIED, - EV_CHKREQ, - EV_REMOVE, - EV_VERIFY, - EV_T202, -}; - -#define TEI_EVENT_COUNT (EV_T202 + 1) - -static char *strTeiEvent[] = -{ - "EV_IDREQ", - "EV_ASSIGN", - "EV_DENIED", - "EV_CHKREQ", - "EV_REMOVE", - "EV_VERIFY", - "EV_T202", -}; - -static unsigned int -random_ri(void) -{ - unsigned int x; - - get_random_bytes(&x, sizeof(x)); - return (x & 0xffff); -} - -static struct PStack * -findtei(struct PStack *st, int tei) -{ - struct PStack *ptr = *(st->l1.stlistp); - - if (tei == 127) - return (NULL); - - while (ptr) - if (ptr->l2.tei == tei) - return (ptr); - else - ptr = ptr->next; - return (NULL); -} - -static void -put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei) -{ - struct sk_buff *skb; - u_char *bp; - - if (!(skb = alloc_skb(8, GFP_ATOMIC))) { - printk(KERN_WARNING "HiSax: No skb for TEI manager\n"); - return; - } - bp = skb_put(skb, 3); - bp[0] = (TEI_SAPI << 2); - bp[1] = (GROUP_TEI << 1) | 0x1; - bp[2] = UI; - bp = skb_put(skb, 5); - bp[0] = TEI_ENTITY_ID; - bp[1] = ri >> 8; - bp[2] = ri & 0xff; - bp[3] = m_id; - bp[4] = (tei << 1) | 1; - st->l2.l2l1(st, PH_DATA | REQUEST, skb); -} - -static void -tei_id_request(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (st->l2.tei != -1) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign request for already assigned tei %d", - st->l2.tei); - return; - } - st->ma.ri = random_ri(); - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign request ri %d", st->ma.ri); - put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); - FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1); - st->ma.N202 = 3; -} - -static void -tei_id_assign(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *ost, *st = fi->userdata; - struct sk_buff *skb = arg; - struct IsdnCardState *cs; - int ri, tei; - - ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - if (ri != ost->ma.ri) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL); - } - } else if (ri == st->ma.ri) { - FsmDelTimer(&st->ma.t202, 1); - FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); - } -} - -static void -tei_id_test_dup(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *ost, *st = fi->userdata; - struct sk_buff *skb = arg; - int tei, ri; - - ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "foreign identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - if (ri != ost->ma.ri) { /* and it wasn't our request */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); - } - } -} - -static void -tei_id_denied(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int ri, tei; - - ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity denied ri %d tei %d", ri, tei); -} - -static void -tei_id_chk_req(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int tei; - - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity check req tei %d", tei); - if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { - FsmDelTimer(&st->ma.t202, 4); - FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei); - } -} - -static void -tei_id_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - struct IsdnCardState *cs; - int tei; - - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity remove tei %d", tei); - if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { - FsmDelTimer(&st->ma.t202, 5); - FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); - } -} - -static void -tei_id_verify(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "id verify request for tei %d", st->l2.tei); - put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); - FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2); - st->ma.N202 = 2; -} - -static void -tei_id_req_tout(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct IsdnCardState *cs; - - if (--st->ma.N202) { - st->ma.ri = random_ri(); - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign req(%d) ri %d", 4 - st->ma.N202, - st->ma.ri); - put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); - } else { - st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); - st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); - FsmChangeState(fi, ST_TEI_NOP); - } -} - -static void -tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct IsdnCardState *cs; - - if (--st->ma.N202) { - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "id verify req(%d) for tei %d", - 3 - st->ma.N202, st->l2.tei); - put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4); - } else { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "verify req for tei %d failed", st->l2.tei); - st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); - FsmChangeState(fi, ST_TEI_NOP); - } -} - -static void -tei_l1l2(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - int mt; - - if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { - dev_kfree_skb(skb); - return; - } - - if (pr == (PH_DATA | INDICATION)) { - if (skb->len < 3) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "short mgr frame %ld/3", skb->len); - } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) || - (skb->data[1] != ((GROUP_TEI << 1) | 1))) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "wrong mgr sapi/tei %x/%x", - skb->data[0], skb->data[1]); - } else if ((skb->data[2] & 0xef) != UI) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "mgr frame is not ui %x", skb->data[2]); - } else { - skb_pull(skb, 3); - if (skb->len < 5) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "short mgr frame %ld/5", skb->len); - } else if (skb->data[0] != TEI_ENTITY_ID) { - /* wrong management entity identifier, ignore */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "tei handler wrong entity id %x", - skb->data[0]); - } else { - mt = skb->data[3]; - if (mt == ID_ASSIGNED) - FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb); - else if (mt == ID_DENIED) - FsmEvent(&st->ma.tei_m, EV_DENIED, skb); - else if (mt == ID_CHK_REQ) - FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb); - else if (mt == ID_REMOVE) - FsmEvent(&st->ma.tei_m, EV_REMOVE, skb); - else { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "tei handler wrong mt %x\n", mt); - } - } - } - } else { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "tei handler wrong pr %x\n", pr); - } - dev_kfree_skb(skb); -} - -static void -tei_l2tei(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs; - - if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { - if (pr == (MDL_ASSIGN | INDICATION)) { - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "fixed assign tei %d", st->l2.tei); - st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); - } - return; - } - switch (pr) { - case (MDL_ASSIGN | INDICATION): - FsmEvent(&st->ma.tei_m, EV_IDREQ, arg); - break; - case (MDL_ERROR | REQUEST): - FsmEvent(&st->ma.tei_m, EV_VERIFY, arg); - break; - default: - break; - } -} - -static void -tei_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - - va_start(args, fmt); - VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args); - va_end(args); -} - -void -setstack_tei(struct PStack *st) -{ - st->l2.l2tei = tei_l2tei; - st->ma.T202 = 2000; /* T202 2000 milliseconds */ - st->l1.l1tei = tei_l1l2; - st->ma.debug = 1; - st->ma.tei_m.fsm = &teifsm; - st->ma.tei_m.state = ST_TEI_NOP; - st->ma.tei_m.debug = 1; - st->ma.tei_m.userdata = st; - st->ma.tei_m.userint = 0; - st->ma.tei_m.printdebug = tei_debug; - FsmInitTimer(&st->ma.tei_m, &st->ma.t202); -} - -void -init_tei(struct IsdnCardState *cs, int protocol) -{ -} - -void -release_tei(struct IsdnCardState *cs) -{ - struct PStack *st = cs->stlist; - - while (st) { - FsmDelTimer(&st->ma.t202, 1); - st = st->next; - } -} - -static struct FsmNode TeiFnList[] __initdata = -{ - {ST_TEI_NOP, EV_IDREQ, tei_id_request}, - {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, - {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, - {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, - {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, - {ST_TEI_IDREQ, EV_T202, tei_id_req_tout}, - {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, - {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, - {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout}, - {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, - {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, -}; - -int __init -TeiNew(void) -{ - teifsm.state_count = TEI_STATE_COUNT; - teifsm.event_count = TEI_EVENT_COUNT; - teifsm.strEvent = strTeiEvent; - teifsm.strState = strTeiState; - return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList)); -} - -void -TeiFree(void) -{ - FsmFree(&teifsm); -} diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c deleted file mode 100644 index 247aa33076b1..000000000000 --- a/drivers/isdn/hisax/teleint.c +++ /dev/null @@ -1,334 +0,0 @@ -/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $ - * - * low level stuff for TeleInt isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hfc_2bs0.h" -#include "isdnl1.h" - -static const char *TeleInt_revision = "$Revision: 1.16.2.5 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - int max_delay = 2000; - - byteout(ale, off); - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return (0); - } - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - register u_char ret; - register int max_delay = 20000; - register int i; - - byteout(ale, off); - for (i = 0; i < size; i++) { - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return; - } - data[i] = bytein(adr); - } -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - register u_char ret; - int max_delay = 2000; - - byteout(ale, off); - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return; - } - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - register u_char ret; - register int max_delay = 20000; - register int i; - - byteout(ale, off); - for (i = 0; i < size; i++) { - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return; - } - byteout(adr, data[i]); - } -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - cs->hw.hfc.cip = offset; - return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - cs->hw.hfc.cip = offset; - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.hfc.cip = 0; - readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.hfc.cip = 0; - writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); -} - -static u_char -ReadHFC(struct IsdnCardState *cs, int data, u_char reg) -{ - register u_char ret; - - if (data) { - cs->hw.hfc.cip = reg; - byteout(cs->hw.hfc.addr | 1, reg); - ret = bytein(cs->hw.hfc.addr); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) - debugl1(cs, "hfc RD %02x %02x", reg, ret); - } else - ret = bytein(cs->hw.hfc.addr | 1); - return (ret); -} - -static void -WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value) -{ - byteout(cs->hw.hfc.addr | 1, reg); - cs->hw.hfc.cip = reg; - if (data) - byteout(cs->hw.hfc.addr, value); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) - debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); -} - -static irqreturn_t -TeleInt_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF); - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -TeleInt_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfc.timer); - int stat = 0; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->bcs[0].mode) { - stat |= 1; - main_irq_hfc(&cs->bcs[0]); - } - if (cs->bcs[1].mode) { - stat |= 2; - main_irq_hfc(&cs->bcs[1]); - } - spin_unlock_irqrestore(&cs->lock, flags); - stat = HZ / 100; - if (!stat) - stat = 1; - cs->hw.hfc.timer.expires = jiffies + stat; - add_timer(&cs->hw.hfc.timer); -} - -static void -release_io_TeleInt(struct IsdnCardState *cs) -{ - del_timer(&cs->hw.hfc.timer); - releasehfc(cs); - if (cs->hw.hfc.addr) - release_region(cs->hw.hfc.addr, 2); -} - -static void -reset_TeleInt(struct IsdnCardState *cs) -{ - printk(KERN_INFO "TeleInt: resetting card\n"); - cs->hw.hfc.cirm |= HFC_RESET; - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */ - mdelay(10); - cs->hw.hfc.cirm &= ~HFC_RESET; - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ - mdelay(10); -} - -static int -TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - int delay; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_TeleInt(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_TeleInt(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_TeleInt(cs); - inithfc(cs); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - cs->writeisac(cs, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&cs->lock, flags); - delay = HZ / 100; - if (!delay) - delay = 1; - cs->hw.hfc.timer.expires = jiffies + delay; - add_timer(&cs->hw.hfc.timer); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_TeleInt(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, TeleInt_revision); - printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_TELEINT) - return (0); - - cs->hw.hfc.addr = card->para[1] & 0x3fe; - cs->irq = card->para[0]; - cs->hw.hfc.cirm = HFC_CIRM; - cs->hw.hfc.isac_spcr = 0x00; - cs->hw.hfc.cip = 0; - cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; - cs->hw.hfc.fifosize = 7 * 1024 + 512; - timer_setup(&cs->hw.hfc.timer, TeleInt_Timer, 0); - if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) { - printk(KERN_WARNING - "HiSax: TeleInt config port %x-%x already in use\n", - cs->hw.hfc.addr, - cs->hw.hfc.addr + 2); - return (0); - } - /* HW IO = IO */ - byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff); - byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54); - switch (cs->irq) { - case 3: - cs->hw.hfc.cirm |= HFC_INTA; - break; - case 4: - cs->hw.hfc.cirm |= HFC_INTB; - break; - case 5: - cs->hw.hfc.cirm |= HFC_INTC; - break; - case 7: - cs->hw.hfc.cirm |= HFC_INTD; - break; - case 10: - cs->hw.hfc.cirm |= HFC_INTE; - break; - case 11: - cs->hw.hfc.cirm |= HFC_INTF; - break; - default: - printk(KERN_WARNING "TeleInt: wrong IRQ\n"); - release_io_TeleInt(cs); - return (0); - } - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt); - - printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n", - cs->hw.hfc.addr, cs->irq); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHFC; - cs->BC_Write_Reg = &WriteHFC; - cs->cardmsg = &TeleInt_card_msg; - cs->irq_func = &TeleInt_interrupt; - ISACVersion(cs, "TeleInt:"); - return (1); -} diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c deleted file mode 100644 index ce9eabdd2f6e..000000000000 --- a/drivers/isdn/hisax/teles0.c +++ /dev/null @@ -1,364 +0,0 @@ -/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Teles Memory IO isdn cards - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Beat Doebeli - * - */ - -#include -#include "hisax.h" -#include "isdnl1.h" -#include "isac.h" -#include "hscx.h" - -static const char *teles0_revision = "$Revision: 2.15.2.4 $"; - -#define TELES_IOMEM_SIZE 0x400 -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readisac(void __iomem *adr, u_char off) -{ - return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off); -} - -static inline void -writeisac(void __iomem *adr, u_char off, u_char data) -{ - writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); -} - - -static inline u_char -readhscx(void __iomem *adr, int hscx, u_char off) -{ - return readb(adr + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); -} - -static inline void -writehscx(void __iomem *adr, int hscx, u_char off, u_char data) -{ - writeb(data, adr + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); mb(); -} - -static inline void -read_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register int i; - register u_char __iomem *ad = adr + 0x100; - for (i = 0; i < size; i++) - data[i] = readb(ad); -} - -static inline void -write_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register int i; - register u_char __iomem *ad = adr + 0x100; - for (i = 0; i < size; i++) { - writeb(data[i], ad); mb(); - } -} - -static inline void -read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - register int i; - register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180); - for (i = 0; i < size; i++) - data[i] = readb(ad); -} - -static inline void -write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - int i; - register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180); - for (i = 0; i < size; i++) { - writeb(data[i], ad); mb(); - } -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readisac(cs->hw.teles0.membase, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writeisac(cs->hw.teles0.membase, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readhscx(cs->hw.teles0.membase, hscx, offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writehscx(cs->hw.teles0.membase, hscx, offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -teles0_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - int count = 0; - - spin_lock_irqsave(&cs->lock, flags); - val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readisac(cs->hw.teles0.membase, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); - if (val && count < 5) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readisac(cs->hw.teles0.membase, ISAC_ISTA); - if (val && count < 5) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_teles0(struct IsdnCardState *cs) -{ - if (cs->hw.teles0.cfg_reg) - release_region(cs->hw.teles0.cfg_reg, 8); - iounmap(cs->hw.teles0.membase); - release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); -} - -static int -reset_teles0(struct IsdnCardState *cs) -{ - u_char cfval; - - if (cs->hw.teles0.cfg_reg) { - switch (cs->irq) { - case 2: - case 9: - cfval = 0x00; - break; - case 3: - cfval = 0x02; - break; - case 4: - cfval = 0x04; - break; - case 5: - cfval = 0x06; - break; - case 10: - cfval = 0x08; - break; - case 11: - cfval = 0x0A; - break; - case 12: - cfval = 0x0C; - break; - case 15: - cfval = 0x0E; - break; - default: - return (1); - } - cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0); - byteout(cs->hw.teles0.cfg_reg + 4, cfval); - HZDELAY(HZ / 10 + 1); - byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1); - HZDELAY(HZ / 10 + 1); - } - writeb(0, cs->hw.teles0.membase + 0x80); mb(); - HZDELAY(HZ / 5 + 1); - writeb(1, cs->hw.teles0.membase + 0x80); mb(); - HZDELAY(HZ / 5 + 1); - return (0); -} - -static int -Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_teles0(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_teles0(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_teles0(struct IsdnCard *card) -{ - u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, teles0_revision); - printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp)); - if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0)) - return (0); - - if (cs->typ == ISDN_CTYPE_16_0) - cs->hw.teles0.cfg_reg = card->para[2]; - else /* 8.0 */ - cs->hw.teles0.cfg_reg = 0; - - if (card->para[1] < 0x10000) { - card->para[1] <<= 4; - printk(KERN_INFO - "Teles0: membase configured DOSish, assuming 0x%lx\n", - (unsigned long) card->para[1]); - } - cs->irq = card->para[0]; - if (cs->hw.teles0.cfg_reg) { - if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.teles0.cfg_reg, - cs->hw.teles0.cfg_reg + 8); - return (0); - } - } - if (cs->hw.teles0.cfg_reg) { - if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 0, val); - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 1, val); - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB - * 0x1f=with AB - * 0x1c 16.3 ??? - */ - if (val != 0x1e && val != 0x1f) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 2, val); - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - } - /* 16.0 and 8.0 designed for IOM1 */ - test_and_set_bit(HW_IOM1, &cs->HW_Flags); - cs->hw.teles0.phymem = card->para[1]; - if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) { - printk(KERN_WARNING - "HiSax: %s memory region %lx-%lx already in use\n", - CardType[card->typ], - cs->hw.teles0.phymem, - cs->hw.teles0.phymem + TELES_IOMEM_SIZE); - if (cs->hw.teles0.cfg_reg) - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); - printk(KERN_INFO - "HiSax: %s config irq:%d mem:%p cfg:0x%X\n", - CardType[cs->typ], cs->irq, - cs->hw.teles0.membase, cs->hw.teles0.cfg_reg); - if (reset_teles0(cs)) { - printk(KERN_WARNING "Teles0: wrong IRQ\n"); - release_io_teles0(cs); - return (0); - } - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Teles_card_msg; - cs->irq_func = &teles0_interrupt; - ISACVersion(cs, "Teles0:"); - if (HscxVersion(cs, "Teles0:")) { - printk(KERN_WARNING - "Teles0: wrong HSCX versions check IO/MEM addresses\n"); - release_io_teles0(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c deleted file mode 100644 index 1eef693f04f0..000000000000 --- a/drivers/isdn/hisax/teles3.c +++ /dev/null @@ -1,498 +0,0 @@ -/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Teles 16.3 & PNP isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Beat Doebeli - * - */ -#include -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *teles3_revision = "$Revision: 2.19.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int adr, u_char off) -{ - return (bytein(adr + off)); -} - -static inline void -writereg(unsigned int adr, u_char off, u_char data) -{ - byteout(adr + off, data); -} - - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.teles3.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.teles3.isacfifo, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.teles3.isacfifo, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.teles3.hscx[hscx], offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.hscx[hscx], offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -teles3_interrupt(int intno, void *dev_id) -{ -#define MAXCOUNT 5 - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - int count = 0; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.teles3.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.teles3.isac, ISAC_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (count >= MAXCOUNT) - printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count); - writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0); - writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static inline void -release_ioregs(struct IsdnCardState *cs, int mask) -{ - if (mask & 1) - release_region(cs->hw.teles3.isac + 32, 32); - if (mask & 2) - release_region(cs->hw.teles3.hscx[0] + 32, 32); - if (mask & 4) - release_region(cs->hw.teles3.hscx[1] + 32, 32); -} - -static void -release_io_teles3(struct IsdnCardState *cs) -{ - if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - release_region(cs->hw.teles3.hscx[1], 96); - } else { - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - release_ioregs(cs, 0x7); - } -} - -static int -reset_teles3(struct IsdnCardState *cs) -{ - u_char irqcfg; - - if (cs->typ != ISDN_CTYPE_TELESPCMCIA) { - if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { - switch (cs->irq) { - case 2: - case 9: - irqcfg = 0x00; - break; - case 3: - irqcfg = 0x02; - break; - case 4: - irqcfg = 0x04; - break; - case 5: - irqcfg = 0x06; - break; - case 10: - irqcfg = 0x08; - break; - case 11: - irqcfg = 0x0A; - break; - case 12: - irqcfg = 0x0C; - break; - case 15: - irqcfg = 0x0E; - break; - default: - return (1); - } - byteout(cs->hw.teles3.cfg_reg + 4, irqcfg); - HZDELAY(HZ / 10 + 1); - byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1); - HZDELAY(HZ / 10 + 1); - } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - byteout(cs->hw.teles3.cfg_reg, 0xff); - HZDELAY(2); - byteout(cs->hw.teles3.cfg_reg, 0x00); - HZDELAY(2); - } else { - /* Reset off for 16.3 PnP , thanks to Georg Acher */ - byteout(cs->hw.teles3.isac + 0x3c, 0); - HZDELAY(2); - byteout(cs->hw.teles3.isac + 0x3c, 1); - HZDELAY(2); - } - } - return (0); -} - -static int -Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_teles3(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_teles3(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ - -static struct isapnp_device_id teles_ids[] = { - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), - (unsigned long) "Teles 16.3 PnP" }, - { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), - ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), - (unsigned long) "Creatix 16.3 PnP" }, - { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), - ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), - (unsigned long) "Compaq ISDN S0" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &teles_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_teles3(struct IsdnCard *card) -{ - u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, teles3_revision); - printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp)); - if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP) - && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) - return (0); - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[3] = pnp_port_start(pnp_d, 2); - card->para[2] = pnp_port_start(pnp_d, 1); - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1] || !card->para[2]) { - printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n", - card->para[0], card->para[1], card->para[2]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "Teles PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Teles PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - if (cs->typ == ISDN_CTYPE_16_3) { - cs->hw.teles3.cfg_reg = card->para[1]; - switch (cs->hw.teles3.cfg_reg) { - case 0x180: - case 0x280: - case 0x380: - cs->hw.teles3.cfg_reg |= 0xc00; - break; - } - cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420; - cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; - cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; - } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - cs->hw.teles3.cfg_reg = 0; - cs->hw.teles3.hscx[0] = card->para[1] - 0x20; - cs->hw.teles3.hscx[1] = card->para[1]; - cs->hw.teles3.isac = card->para[1] + 0x20; - } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - cs->hw.teles3.cfg_reg = card->para[3]; - cs->hw.teles3.isac = card->para[2] - 32; - cs->hw.teles3.hscx[0] = card->para[1] - 32; - cs->hw.teles3.hscx[1] = card->para[1]; - } else { /* PNP */ - cs->hw.teles3.cfg_reg = 0; - cs->hw.teles3.isac = card->para[1] - 32; - cs->hw.teles3.hscx[0] = card->para[2] - 32; - cs->hw.teles3.hscx[1] = card->para[2]; - } - cs->irq = card->para[0]; - cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; - cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; - cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; - if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) { - printk(KERN_WARNING - "HiSax: %s ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.hscx[1], - cs->hw.teles3.hscx[1] + 96); - return (0); - } - cs->irq_flags |= IRQF_SHARED; /* cardbus can share */ - } else { - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) { - printk(KERN_WARNING - "HiSax: %s config port %x already in use\n", - CardType[card->typ], - cs->hw.teles3.cfg_reg); - return (0); - } - } else { - if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.teles3.cfg_reg, - cs->hw.teles3.cfg_reg + 8); - return (0); - } - } - } - if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) { - printk(KERN_WARNING - "HiSax: %s isac ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.isac + 32, - cs->hw.teles3.isac + 64); - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - return (0); - } - if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) { - printk(KERN_WARNING - "HiSax: %s hscx A ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.hscx[0] + 32, - cs->hw.teles3.hscx[0] + 64); - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - release_ioregs(cs, 1); - return (0); - } - if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) { - printk(KERN_WARNING - "HiSax: %s hscx B ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.hscx[1] + 32, - cs->hw.teles3.hscx[1] + 64); - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - release_ioregs(cs, 3); - return (0); - } - } - if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { - if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 0, val); - release_io_teles3(cs); - return (0); - } - if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 1, val); - release_io_teles3(cs); - return (0); - } - val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB - * 0x1f=with AB - * 0x1c 16.3 ??? - * 0x39 16.3 1.1 - * 0x38 16.3 1.3 - * 0x46 16.3 with AB + Video (Teles-Vision) - */ - if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 2, val); - release_io_teles3(cs); - return (0); - } - } - printk(KERN_INFO - "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n", - CardType[cs->typ], cs->irq, - cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg); - printk(KERN_INFO - "HiSax: hscx A:0x%X hscx B:0x%X\n", - cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32); - - setup_isac(cs); - if (reset_teles3(cs)) { - printk(KERN_WARNING "Teles3: wrong IRQ\n"); - release_io_teles3(cs); - return (0); - } - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Teles_card_msg; - cs->irq_func = &teles3_interrupt; - ISACVersion(cs, "Teles3:"); - if (HscxVersion(cs, "Teles3:")) { - printk(KERN_WARNING - "Teles3: wrong HSCX versions check IO address\n"); - release_io_teles3(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c deleted file mode 100644 index bcc37e955622..000000000000 --- a/drivers/isdn/hisax/teles_cs.c +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */ -/*====================================================================== - - A teles S0 PCMCIA client driver - - Based on skeleton by David Hinds, dhinds@allegro.stanford.edu - Written by Christof Petig, christof.petig@wtal.de - - Also inspired by ELSA PCMCIA driver - by Klaus Lichtenwalder - - Extensions to new hisax_pcmcia by Karsten Keil - - minor changes to be compatible with kernel 2.4.x - by Jan.Schubert@GMX.li - - ======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards"); -MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de"); -MODULE_LICENSE("GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int teles_cs_config(struct pcmcia_device *link); -static void teles_cs_release(struct pcmcia_device *link); -static void teles_detach(struct pcmcia_device *p_dev); - -typedef struct local_info_t { - struct pcmcia_device *p_dev; - int busy; - int cardnr; -} local_info_t; - -static int teles_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - dev_dbg(&link->dev, "teles_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) return -ENOMEM; - local->cardnr = -1; - - local->p_dev = link; - link->priv = local; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - return teles_cs_config(link); -} /* teles_attach */ - -static void teles_detach(struct pcmcia_device *link) -{ - local_info_t *info = link->priv; - - dev_dbg(&link->dev, "teles_detach(0x%p)\n", link); - - info->busy = 1; - teles_cs_release(link); - - kfree(info); -} /* teles_detach */ - -static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - int j; - - p_dev->io_lines = 5; - p_dev->resource[0]->end = 96; - p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { - printk(KERN_INFO "(teles_cs: looks like the 96 model)\n"); - if (!pcmcia_request_io(p_dev)) - return 0; - } else { - printk(KERN_INFO "(teles_cs: looks like the 97 model)\n"); - for (j = 0x2f0; j > 0x100; j -= 0x10) { - p_dev->resource[0]->start = j; - if (!pcmcia_request_io(p_dev)) - return 0; - } - } - return -ENODEV; -} - -static int teles_cs_config(struct pcmcia_device *link) -{ - int i; - IsdnCard_t icard; - - dev_dbg(&link->dev, "teles_config(0x%p)\n", link); - - i = pcmcia_loop_config(link, teles_cs_configcheck, NULL); - if (i != 0) - goto cs_failed; - - if (!link->irq) - goto cs_failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto cs_failed; - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = protocol; - icard.typ = ISDN_CTYPE_TELESPCMCIA; - - i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard); - if (i < 0) { - printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n", - i, (unsigned int) link->resource[0]->start); - teles_cs_release(link); - return -ENODEV; - } - - ((local_info_t *)link->priv)->cardnr = i; - return 0; - -cs_failed: - teles_cs_release(link); - return -ENODEV; -} /* teles_cs_config */ - -static void teles_cs_release(struct pcmcia_device *link) -{ - local_info_t *local = link->priv; - - dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link); - - if (local) { - if (local->cardnr >= 0) { - /* no unregister function with hisax */ - HiSax_closecard(local->cardnr); - } - } - - pcmcia_disable_device(link); -} /* teles_cs_release */ - -static int teles_suspend(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 1; - - return 0; -} - -static int teles_resume(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 0; - - return 0; -} - - -static const struct pcmcia_device_id teles_ids[] = { - PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, teles_ids); - -static struct pcmcia_driver teles_cs_driver = { - .owner = THIS_MODULE, - .name = "teles_cs", - .probe = teles_probe, - .remove = teles_detach, - .id_table = teles_ids, - .suspend = teles_suspend, - .resume = teles_resume, -}; -module_pcmcia_driver(teles_cs_driver); diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c deleted file mode 100644 index 33eeb4602c7e..000000000000 --- a/drivers/isdn/hisax/telespci.c +++ /dev/null @@ -1,349 +0,0 @@ -/* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $ - * - * low level stuff for Teles PCI isdn cards - * - * Author Ton van Rosmalen - * Karsten Keil - * Copyright by Ton van Rosmalen - * by Karsten Keil - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include - -static const char *telespci_revision = "$Revision: 2.23.2.3 $"; - -#define ZORAN_PO_RQ_PEN 0x02000000 -#define ZORAN_PO_WR 0x00800000 -#define ZORAN_PO_GID0 0x00000000 -#define ZORAN_PO_GID1 0x00100000 -#define ZORAN_PO_GREG0 0x00000000 -#define ZORAN_PO_GREG1 0x00010000 -#define ZORAN_PO_DMASK 0xFF - -#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) -#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) -#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) -#define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0) -#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1) -#define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1) - -#define ZORAN_WAIT_NOBUSY do { \ - portdata = readl(adr + 0x200); \ - } while (portdata & ZORAN_PO_RQ_PEN) - -static inline u_char -readisac(void __iomem *adr, u_char off) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - - /* set address for ISAC */ - writel(WRITE_ADDR_ISAC | off, adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* read data from ISAC */ - writel(READ_DATA_ISAC, adr + 0x200); - ZORAN_WAIT_NOBUSY; - return ((u_char)(portdata & ZORAN_PO_DMASK)); -} - -static inline void -writeisac(void __iomem *adr, u_char off, u_char data) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - - /* set address for ISAC */ - writel(WRITE_ADDR_ISAC | off, adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* write data to ISAC */ - writel(WRITE_DATA_ISAC | data, adr + 0x200); - ZORAN_WAIT_NOBUSY; -} - -static inline u_char -readhscx(void __iomem *adr, int hscx, u_char off) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - /* set address for HSCX */ - writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* read data from HSCX */ - writel(READ_DATA_HSCX, adr + 0x200); - ZORAN_WAIT_NOBUSY; - return ((u_char)(portdata & ZORAN_PO_DMASK)); -} - -static inline void -writehscx(void __iomem *adr, int hscx, u_char off, u_char data) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - /* set address for HSCX */ - writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* write data to HSCX */ - writel(WRITE_DATA_HSCX | data, adr + 0x200); - ZORAN_WAIT_NOBUSY; -} - -static inline void -read_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* read data from ISAC */ - for (i = 0; i < size; i++) { - /* set address for ISAC fifo */ - writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(READ_DATA_ISAC, adr + 0x200); - ZORAN_WAIT_NOBUSY; - data[i] = (u_char)(portdata & ZORAN_PO_DMASK); - } -} - -static void -write_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* write data to ISAC */ - for (i = 0; i < size; i++) { - /* set address for ISAC fifo */ - writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(WRITE_DATA_ISAC | data[i], adr + 0x200); - ZORAN_WAIT_NOBUSY; - } -} - -static inline void -read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - register unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* read data from HSCX */ - for (i = 0; i < size; i++) { - /* set address for HSCX fifo */ - writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(READ_DATA_HSCX, adr + 0x200); - ZORAN_WAIT_NOBUSY; - data[i] = (u_char) (portdata & ZORAN_PO_DMASK); - } -} - -static inline void -write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* write data to HSCX */ - for (i = 0; i < size; i++) { - /* set address for HSCX fifo */ - writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(WRITE_DATA_HSCX | data[i], adr + 0x200); - ZORAN_WAIT_NOBUSY; - udelay(10); - } -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readisac(cs->hw.teles0.membase, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writeisac(cs->hw.teles0.membase, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readhscx(cs->hw.teles0.membase, hscx, offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writehscx(cs->hw.teles0.membase, hscx, offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -telespci_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char hval, ival; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); - if (hval) - hscx_int_main(cs, hval); - ival = readisac(cs->hw.teles0.membase, ISAC_ISTA); - if ((hval | ival) == 0) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (ival) - isac_interrupt(cs, ival); - /* Clear interrupt register for Zoran PCI controller */ - writel(0x70000000, cs->hw.teles0.membase + 0x3C); - - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_telespci(struct IsdnCardState *cs) -{ - iounmap(cs->hw.teles0.membase); -} - -static int -TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - return (0); - case CARD_RELEASE: - release_io_telespci(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static struct pci_dev *dev_tel = NULL; - -int setup_telespci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, telespci_revision); - printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_TELESPCI) - return (0); - - if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { - if (pci_enable_device(dev_tel)) - return (0); - cs->irq = dev_tel->irq; - if (!cs->irq) { - printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0), - PAGE_SIZE); - printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n", - (unsigned long long)pci_resource_start(dev_tel, 0), - dev_tel->irq); - } else { - printk(KERN_WARNING "TelesPCI: No PCI card found\n"); - return (0); - } - - /* Initialize Zoran PCI controller */ - writel(0x00000000, cs->hw.teles0.membase + 0x28); - writel(0x01000000, cs->hw.teles0.membase + 0x28); - writel(0x01000000, cs->hw.teles0.membase + 0x28); - writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C); - writel(0x70000000, cs->hw.teles0.membase + 0x3C); - writel(0x61000000, cs->hw.teles0.membase + 0x40); - /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ - - printk(KERN_INFO - "HiSax: Teles PCI config irq:%d mem:%p\n", - cs->irq, - cs->hw.teles0.membase); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &TelesPCI_card_msg; - cs->irq_func = &telespci_interrupt; - cs->irq_flags |= IRQF_SHARED; - ISACVersion(cs, "TelesPCI:"); - if (HscxVersion(cs, "TelesPCI:")) { - printk(KERN_WARNING - "TelesPCI: wrong HSCX versions check IO/MEM addresses\n"); - release_io_telespci(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c deleted file mode 100644 index 36eefaa3a7d9..000000000000 --- a/drivers/isdn/hisax/w6692.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $ - * - * Winbond W6692 specific routines - * - * Author Petr Novak - * Copyright by Petr Novak - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include "hisax.h" -#include "w6692.h" -#include "isdnl1.h" -#include -#include -#include - -/* table entry in the PCI devices list */ -typedef struct { - int vendor_id; - int device_id; - char *vendor_name; - char *card_name; -} PCI_ENTRY; - -static const PCI_ENTRY id_list[] = -{ - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"}, - {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, - {0, 0, "U.S.Robotics", "ISDN PCI Card TA"} -}; - -#define W6692_SV_USR 0x16ec -#define W6692_SD_USR 0x3409 -#define W6692_WINBOND 0 -#define W6692_DYNALINK 1 -#define W6692_USR 2 - -static const char *w6692_revision = "$Revision: 1.18.2.4 $"; - -#define DBUSY_TIMER_VALUE 80 - -static char *W6692Ver[] = -{"W6692 V00", "W6692 V01", "W6692 V10", - "W6692 V11"}; - -static void -W6692Version(struct IsdnCardState *cs, char *s) -{ - int val; - - val = cs->readW6692(cs, W_D_RBCH); - printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]); -} - -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command %x", command); - cs->writeisac(cs, W_CIX, command); -} - - -static void -W6692_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.w6692.ph_state) { - case (W_L1CMD_RST): - ph_command(cs, W_L1CMD_DRC); - l1_msg(cs, HW_RESET | INDICATION, NULL); - /* fall through */ - case (W_L1IND_CD): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (W_L1IND_DRD): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (W_L1IND_CE): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (W_L1IND_LD): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (W_L1IND_ARD): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (W_L1IND_AI8): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (W_L1IND_AI10): - l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); - break; - default: - break; - } -} - -static void -W6692_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) - W6692_new_ph(cs); - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -/* - if (test_and_clear_bit(D_RX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_RX_END, NULL); - if (test_and_clear_bit(D_TX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_TX_END, NULL); -*/ -} - -static void -W6692_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "W6692_empty_fifo"); - - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692_empty_fifo overrun %d", - cs->rcvidx + count); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK); - cs->rcvidx = 0; - return; - } - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->readW6692fifo(cs, ptr, count); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "W6692_empty_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -W6692_fill_fifo(struct IsdnCardState *cs) -{ - int count, more; - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "W6692_fill_fifo"); - - if (!cs->tx_skb) - return; - - count = cs->tx_skb->len; - if (count <= 0) - return; - - more = 0; - if (count > W_D_FIFO_THRESH) { - more = !0; - count = W_D_FIFO_THRESH; - } - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeW6692fifo(cs, ptr, count); - cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME)); - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "W6692_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); - add_timer(&cs->dbusytimer); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "W6692_fill_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -W6692B_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "W6692B_empty_fifo"); - - if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); - cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - bcs->hw.w6692.rcvidx = 0; - return; - } - ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx; - bcs->hw.w6692.rcvidx += count; - READW6692BFIFO(cs, bcs->channel, ptr, count); - cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "W6692B_empty_fifo %c cnt %d", - bcs->channel + '1', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -W6692B_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count; - u_char *ptr; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > W_B_FIFO_THRESH) { - more = 1; - count = W_B_FIFO_THRESH; - } else - count = bcs->tx_skb->len; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " " : " last "), count); - - ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.w6692.count += count; - WRITEW6692BFIFO(cs, bcs->channel, ptr, count); - cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "W6692B_fill_fifo %c cnt %d", - bcs->channel + '1', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) -{ - u_char val; - u_char r; - struct BCState *bcs; - struct sk_buff *skb; - int count; - - bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs + 1); - val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); - debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) { - debugl1(cs, "W6692B not INIT yet"); - return; - } - if (val & W_B_EXI_RME) { /* RME */ - r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); - if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B STAR %x", r); - if ((r & W_B_STAR_RDOV) && bcs->mode) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B RDOV mode=%d", - bcs->mode); - if (r & W_B_STAR_CRCE) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B CRC error"); - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); - } else { - count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1); - if (count == 0) - count = W_B_FIFO_THRESH; - W6692B_empty_fifo(bcs, count); - if ((count = bcs->hw.w6692.rcvidx) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "W6692 Bchan Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "W6692: Bchan receive out of memory\n"); - else { - skb_put_data(skb, - bcs->hw.w6692.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.w6692.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & W_B_EXI_RMR) { /* RMR */ - W6692B_empty_fifo(bcs, W_B_FIFO_THRESH); - r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); - if (r & W_B_STAR_RDOV) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B RDOV(RMR) mode=%d", bcs->mode); - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); - if (bcs->mode != L1_MODE_TRANS) - bcs->hw.w6692.rcvidx = 0; - } - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.w6692.rcvbuf, - W_B_FIFO_THRESH); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.w6692.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & W_B_EXI_XDUN) { /* XDUN */ - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B EXIR %x Lost TX", val); - if (bcs->mode == 1) - W6692B_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.w6692.count); - bcs->tx_cnt += bcs->hw.w6692.count; - bcs->hw.w6692.count = 0; - } - } - return; - } - if (val & W_B_EXI_XFR) { /* XFR */ - r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); - if (r & W_B_STAR_XDOW) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B STAR %x XDOW", r); - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); - if (bcs->tx_skb && (bcs->mode != 1)) { - skb_push(bcs->tx_skb, bcs->hw.w6692.count); - bcs->tx_cnt += bcs->hw.w6692.count; - bcs->hw.w6692.count = 0; - } - } - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - W6692B_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.w6692.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.w6692.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.w6692.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - W6692B_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static irqreturn_t -W6692_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, exval, v1; - struct sk_buff *skb; - u_int count; - u_long flags; - int icnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - val = cs->readW6692(cs, W_ISTA); - if (!val) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } -StartW6692: - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "W6692 ISTA %x", val); - - if (val & W_INT_D_RME) { /* RME */ - exval = cs->readW6692(cs, W_D_RSTA); - if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { - if (exval & W_D_RSTA_RDOV) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 RDOV"); - if (exval & W_D_RSTA_CRCE) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 D-channel CRC error"); - if (exval & W_D_RSTA_RMB) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 D-channel ABORT"); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); - } else { - count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1); - if (count == 0) - count = W_D_FIFO_THRESH; - W6692_empty_fifo(cs, count); - if ((count = cs->rcvidx) > 0) { - cs->rcvidx = 0; - if (!(skb = alloc_skb(count, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - if (val & W_INT_D_RMR) { /* RMR */ - W6692_empty_fifo(cs, W_D_FIFO_THRESH); - } - if (val & W_INT_D_XFR) { /* XFR */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - W6692_fill_fifo(cs); - goto afterXFR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - W6692_fill_fifo(cs); - } else - schedule_event(cs, D_XMTBUFREADY); - } -afterXFR: - if (val & (W_INT_XINT0 | W_INT_XINT1)) { /* XINT0/1 - never */ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "W6692 spurious XINT!"); - } - if (val & W_INT_D_EXI) { /* EXI */ - exval = cs->readW6692(cs, W_D_EXIR); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 D_EXIR %02x", exval); - if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { /* Transmit underrun/collision */ - debugl1(cs, "W6692 D-chan underrun/collision"); - printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n"); - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { /* Restart frame */ - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - W6692_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n"); - debugl1(cs, "W6692 XDUN/XCOL no skb"); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); - } - } - if (exval & W_D_EXI_RDOV) { /* RDOV */ - debugl1(cs, "W6692 D-channel RDOV"); - printk(KERN_WARNING "HiSax: W6692 D-RDOV\n"); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST); - } - if (exval & W_D_EXI_TIN2) { /* TIN2 - never */ - debugl1(cs, "W6692 spurious TIN2 interrupt"); - } - if (exval & W_D_EXI_MOC) { /* MOC - not supported */ - debugl1(cs, "W6692 spurious MOC interrupt"); - v1 = cs->readW6692(cs, W_MOSR); - debugl1(cs, "W6692 MOSR %02x", v1); - } - if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ - v1 = cs->readW6692(cs, W_CIR); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "W6692 ISC CIR=0x%02X", v1); - if (v1 & W_CIR_ICC) { - cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state); - schedule_event(cs, D_L1STATECHANGE); - } - if (v1 & W_CIR_SCC) { - v1 = cs->readW6692(cs, W_SQR); - debugl1(cs, "W6692 SCC SQR=0x%02X", v1); - } - } - if (exval & W_D_EXI_WEXP) { - debugl1(cs, "W6692 spurious WEXP interrupt!"); - } - if (exval & W_D_EXI_TEXP) { - debugl1(cs, "W6692 spurious TEXP interrupt!"); - } - } - if (val & W_INT_B1_EXI) { - debugl1(cs, "W6692 B channel 1 interrupt"); - W6692B_interrupt(cs, 0); - } - if (val & W_INT_B2_EXI) { - debugl1(cs, "W6692 B channel 2 interrupt"); - W6692B_interrupt(cs, 1); - } - val = cs->readW6692(cs, W_ISTA); - if (val && icnt) { - icnt--; - goto StartW6692; - } - if (!icnt) { - printk(KERN_WARNING "W6692 IRQ LOOP\n"); - cs->writeW6692(cs, W_IMASK, 0xff); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -W6692_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - int val; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - W6692_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - W6692_fill_fifo(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if (cs->dc.w6692.ph_state == W_L1IND_DRD) { - ph_command(cs, W_L1CMD_ECK); - spin_unlock_irqrestore(&cs->lock, flags); - } else { - ph_command(cs, W_L1CMD_RST); - cs->dc.w6692.ph_state = W_L1CMD_RST; - spin_unlock_irqrestore(&cs->lock, flags); - W6692_new_ph(cs); - } - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, W_L1CMD_ECK); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, W_L1CMD_AR8); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - val = 0; - if (1 & (long) arg) - val |= 0x0c; - if (2 & (long) arg) - val |= 0x3; - /* !!! not implemented yet */ - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692_l1hw unknown %04x", pr); - break; - } -} - -static void -setstack_W6692(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = W6692_l1hw; -} - -static void -DC_Close_W6692(struct IsdnCardState *cs) -{ -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *stptr; - int rbch, star; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = cs->readW6692(cs, W_D_RBCH); - star = cs->readW6692(cs, W_D_STAR); - if (cs->debug) - debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x", - rbch, star); - if (star & W_D_STAR_XBZ) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */ - spin_unlock_irqrestore(&cs->lock, flags); - cs->irq_func(cs->irq, cs); - return; - } - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -static void -W6692Bmode(struct BCState *bcs, int mode, int bchan) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "w6692 %c mode %d ichan %d", - '1' + bchan, mode, bchan); - bcs->mode = mode; - bcs->channel = bchan; - bcs->hw.w6692.bchan = bchan; - - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0); - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF); - cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff); - cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff); - break; - } - if (mode) - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST | - W_B_CMDR_RACT | W_B_CMDR_XRST); - cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00); -} - -static void -W6692_l2l1(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - struct BCState *bcs = st->l1.bcs; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.w6692.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - if (bcs->tx_skb) { - printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n"); - break; - } - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.w6692.count = 0; - bcs->cs->BC_Send_Data(bcs); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - W6692Bmode(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - W6692Bmode(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_w6692state(struct BCState *bcs) -{ - W6692Bmode(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.w6692.rcvbuf); - bcs->hw.w6692.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_w6692state(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for w6692.rcvbuf\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.w6692.rcvbuf); - bcs->hw.w6692.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.w6692.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_w6692(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_w6692state(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = W6692_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void resetW6692(struct IsdnCardState *cs) -{ - cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); - mdelay(10); - cs->writeW6692(cs, W_D_CTL, 0x00); - mdelay(10); - cs->writeW6692(cs, W_IMASK, 0xff); - cs->writeW6692(cs, W_D_SAM, 0xff); - cs->writeW6692(cs, W_D_TAM, 0xff); - cs->writeW6692(cs, W_D_EXIM, 0x00); - cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); - cs->writeW6692(cs, W_IMASK, 0x18); - if (cs->subtyp == W6692_USR) { - /* seems that USR implemented some power control features - * Pin 79 is connected to the oscilator circuit so we - * have to handle it here - */ - cs->writeW6692(cs, W_PCTL, 0x80); - cs->writeW6692(cs, W_XDATA, 0x00); - } -} - -static void initW6692(struct IsdnCardState *cs, int part) -{ - if (part & 1) { - cs->setstack_d = setstack_W6692; - cs->DC_Close = DC_Close_W6692; - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); - resetW6692(cs); - ph_command(cs, W_L1CMD_RST); - cs->dc.w6692.ph_state = W_L1CMD_RST; - W6692_new_ph(cs); - ph_command(cs, W_L1CMD_ECK); - - cs->bcs[0].BC_SetStack = setstack_w6692; - cs->bcs[1].BC_SetStack = setstack_w6692; - cs->bcs[0].BC_Close = close_w6692state; - cs->bcs[1].BC_Close = close_w6692state; - W6692Bmode(cs->bcs, 0, 0); - W6692Bmode(cs->bcs + 1, 0, 0); - } - if (part & 2) { - /* Reenable all IRQ */ - cs->writeW6692(cs, W_IMASK, 0x18); - cs->writeW6692(cs, W_D_EXIM, 0x00); - cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00); - cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00); - /* Reset D-chan receiver and transmitter */ - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); - } -} - -/* Interface functions */ - -static u_char -ReadW6692(struct IsdnCardState *cs, u_char offset) -{ - return (inb(cs->hw.w6692.iobase + offset)); -} - -static void -WriteW6692(struct IsdnCardState *cs, u_char offset, u_char value) -{ - outb(value, cs->hw.w6692.iobase + offset); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size); -} - -static u_char -ReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset) -{ - return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset)); -} - -static void -WriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value) -{ - outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset); -} - -static int -w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - resetW6692(cs); - return (0); - case CARD_RELEASE: - cs->writeW6692(cs, W_IMASK, 0xff); - release_region(cs->hw.w6692.iobase, 256); - if (cs->subtyp == W6692_USR) { - cs->writeW6692(cs, W_XDATA, 0x04); - } - return (0); - case CARD_INIT: - initW6692(cs, 3); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int id_idx; - -static struct pci_dev *dev_w6692 = NULL; - -int setup_w6692(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_char found = 0; - u_char pci_irq = 0; - u_int pci_ioaddr = 0; - - strcpy(tmp, w6692_revision); - printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_W6692) - return (0); - - while (id_list[id_idx].vendor_id) { - dev_w6692 = hisax_find_pci_device(id_list[id_idx].vendor_id, - id_list[id_idx].device_id, - dev_w6692); - if (dev_w6692) { - if (pci_enable_device(dev_w6692)) - continue; - cs->subtyp = id_idx; - break; - } - id_idx++; - } - if (dev_w6692) { - found = 1; - pci_irq = dev_w6692->irq; - /* I think address 0 is allways the configuration area */ - /* and address 1 is the real IO space KKe 03.09.99 */ - pci_ioaddr = pci_resource_start(dev_w6692, 1); - /* USR ISDN PCI card TA need some special handling */ - if (cs->subtyp == W6692_WINBOND) { - if ((W6692_SV_USR == dev_w6692->subsystem_vendor) && - (W6692_SD_USR == dev_w6692->subsystem_device)) { - cs->subtyp = W6692_USR; - } - } - } - if (!found) { - printk(KERN_WARNING "W6692: No PCI card found\n"); - return (0); - } - cs->irq = pci_irq; - if (!cs->irq) { - printk(KERN_WARNING "W6692: No IRQ for PCI card found\n"); - return (0); - } - if (!pci_ioaddr) { - printk(KERN_WARNING "W6692: NO I/O Base Address found\n"); - return (0); - } - cs->hw.w6692.iobase = pci_ioaddr; - printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n", - id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, - pci_ioaddr, pci_irq); - if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) { - printk(KERN_WARNING - "HiSax: %s I/O ports %x-%x already in use\n", - id_list[cs->subtyp].card_name, - cs->hw.w6692.iobase, - cs->hw.w6692.iobase + 255); - return (0); - } - - printk(KERN_INFO - "HiSax: %s config irq:%d I/O:%x\n", - id_list[cs->subtyp].card_name, cs->irq, - cs->hw.w6692.iobase); - - INIT_WORK(&cs->tqueue, W6692_bh); - cs->readW6692 = &ReadW6692; - cs->writeW6692 = &WriteW6692; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadW6692B; - cs->BC_Write_Reg = &WriteW6692B; - cs->BC_Send_Data = &W6692B_fill_fifo; - cs->cardmsg = &w6692_card_msg; - cs->irq_func = &W6692_interrupt; - cs->irq_flags |= IRQF_SHARED; - W6692Version(cs, "W6692:"); - printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA)); - printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK)); - printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR)); - printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM)); - printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA)); - return (1); -} diff --git a/drivers/isdn/hisax/w6692.h b/drivers/isdn/hisax/w6692.h deleted file mode 100644 index 024b04d33e43..000000000000 --- a/drivers/isdn/hisax/w6692.h +++ /dev/null @@ -1,184 +0,0 @@ -/* $Id: w6692.h,v 1.4.2.2 2004/01/12 22:52:29 keil Exp $ - * - * Winbond W6692 specific defines - * - * Author Petr Novak - * Copyright by Petr Novak - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* map W6692 functions to ISAC functions */ -#define readW6692 readisac -#define writeW6692 writeisac -#define readW6692fifo readisacfifo -#define writeW6692fifo writeisacfifo - -/* B-channel FIFO read/write routines */ - -#define READW6692BFIFO(cs, bchan, ptr, count) \ - insb(cs->hw.w6692.iobase + W_B_RFIFO + (bchan ? 0x40 : 0), ptr, count) - -#define WRITEW6692BFIFO(cs, bchan, ptr, count) \ - outsb(cs->hw.w6692.iobase + W_B_XFIFO + (bchan ? 0x40 : 0), ptr, count) - -/* Specifications of W6692 registers */ - -#define W_D_RFIFO 0x00 /* R */ -#define W_D_XFIFO 0x04 /* W */ -#define W_D_CMDR 0x08 /* W */ -#define W_D_MODE 0x0c /* R/W */ -#define W_D_TIMR 0x10 /* R/W */ -#define W_ISTA 0x14 /* R_clr */ -#define W_IMASK 0x18 /* R/W */ -#define W_D_EXIR 0x1c /* R_clr */ -#define W_D_EXIM 0x20 /* R/W */ -#define W_D_STAR 0x24 /* R */ -#define W_D_RSTA 0x28 /* R */ -#define W_D_SAM 0x2c /* R/W */ -#define W_D_SAP1 0x30 /* R/W */ -#define W_D_SAP2 0x34 /* R/W */ -#define W_D_TAM 0x38 /* R/W */ -#define W_D_TEI1 0x3c /* R/W */ -#define W_D_TEI2 0x40 /* R/W */ -#define W_D_RBCH 0x44 /* R */ -#define W_D_RBCL 0x48 /* R */ -#define W_TIMR2 0x4c /* W */ -#define W_L1_RC 0x50 /* R/W */ -#define W_D_CTL 0x54 /* R/W */ -#define W_CIR 0x58 /* R */ -#define W_CIX 0x5c /* W */ -#define W_SQR 0x60 /* R */ -#define W_SQX 0x64 /* W */ -#define W_PCTL 0x68 /* R/W */ -#define W_MOR 0x6c /* R */ -#define W_MOX 0x70 /* R/W */ -#define W_MOSR 0x74 /* R_clr */ -#define W_MOCR 0x78 /* R/W */ -#define W_GCR 0x7c /* R/W */ - -#define W_B_RFIFO 0x80 /* R */ -#define W_B_XFIFO 0x84 /* W */ -#define W_B_CMDR 0x88 /* W */ -#define W_B_MODE 0x8c /* R/W */ -#define W_B_EXIR 0x90 /* R_clr */ -#define W_B_EXIM 0x94 /* R/W */ -#define W_B_STAR 0x98 /* R */ -#define W_B_ADM1 0x9c /* R/W */ -#define W_B_ADM2 0xa0 /* R/W */ -#define W_B_ADR1 0xa4 /* R/W */ -#define W_B_ADR2 0xa8 /* R/W */ -#define W_B_RBCL 0xac /* R */ -#define W_B_RBCH 0xb0 /* R */ - -#define W_XADDR 0xf4 /* R/W */ -#define W_XDATA 0xf8 /* R/W */ -#define W_EPCTL 0xfc /* W */ - -/* W6692 register bits */ - -#define W_D_CMDR_XRST 0x01 -#define W_D_CMDR_XME 0x02 -#define W_D_CMDR_XMS 0x08 -#define W_D_CMDR_STT 0x10 -#define W_D_CMDR_RRST 0x40 -#define W_D_CMDR_RACK 0x80 - -#define W_D_MODE_RLP 0x01 -#define W_D_MODE_DLP 0x02 -#define W_D_MODE_MFD 0x04 -#define W_D_MODE_TEE 0x08 -#define W_D_MODE_TMS 0x10 -#define W_D_MODE_RACT 0x40 -#define W_D_MODE_MMS 0x80 - -#define W_INT_B2_EXI 0x01 -#define W_INT_B1_EXI 0x02 -#define W_INT_D_EXI 0x04 -#define W_INT_XINT0 0x08 -#define W_INT_XINT1 0x10 -#define W_INT_D_XFR 0x20 -#define W_INT_D_RME 0x40 -#define W_INT_D_RMR 0x80 - -#define W_D_EXI_WEXP 0x01 -#define W_D_EXI_TEXP 0x02 -#define W_D_EXI_ISC 0x04 -#define W_D_EXI_MOC 0x08 -#define W_D_EXI_TIN2 0x10 -#define W_D_EXI_XCOL 0x20 -#define W_D_EXI_XDUN 0x40 -#define W_D_EXI_RDOV 0x80 - -#define W_D_STAR_DRDY 0x10 -#define W_D_STAR_XBZ 0x20 -#define W_D_STAR_XDOW 0x80 - -#define W_D_RSTA_RMB 0x10 -#define W_D_RSTA_CRCE 0x20 -#define W_D_RSTA_RDOV 0x40 - -#define W_D_CTL_SRST 0x20 - -#define W_CIR_SCC 0x80 -#define W_CIR_ICC 0x40 -#define W_CIR_COD_MASK 0x0f - -#define W_B_CMDR_XRST 0x01 -#define W_B_CMDR_XME 0x02 -#define W_B_CMDR_XMS 0x04 -#define W_B_CMDR_RACT 0x20 -#define W_B_CMDR_RRST 0x40 -#define W_B_CMDR_RACK 0x80 - -#define W_B_MODE_FTS0 0x01 -#define W_B_MODE_FTS1 0x02 -#define W_B_MODE_SW56 0x04 -#define W_B_MODE_BSW0 0x08 -#define W_B_MODE_BSW1 0x10 -#define W_B_MODE_EPCM 0x20 -#define W_B_MODE_ITF 0x40 -#define W_B_MODE_MMS 0x80 - -#define W_B_EXI_XDUN 0x01 -#define W_B_EXI_XFR 0x02 -#define W_B_EXI_RDOV 0x10 -#define W_B_EXI_RME 0x20 -#define W_B_EXI_RMR 0x40 - -#define W_B_STAR_XBZ 0x01 -#define W_B_STAR_XDOW 0x04 -#define W_B_STAR_RMB 0x10 -#define W_B_STAR_CRCE 0x20 -#define W_B_STAR_RDOV 0x40 - -#define W_B_RBCH_LOV 0x20 - -/* W6692 Layer1 commands */ - -#define W_L1CMD_ECK 0x00 -#define W_L1CMD_RST 0x01 -#define W_L1CMD_SCP 0x04 -#define W_L1CMD_SSP 0x02 -#define W_L1CMD_AR8 0x08 -#define W_L1CMD_AR10 0x09 -#define W_L1CMD_EAL 0x0a -#define W_L1CMD_DRC 0x0f - -/* W6692 Layer1 indications */ - -#define W_L1IND_CE 0x07 -#define W_L1IND_DRD 0x00 -#define W_L1IND_LD 0x04 -#define W_L1IND_ARD 0x08 -#define W_L1IND_TI 0x0a -#define W_L1IND_ATI 0x0b -#define W_L1IND_AI8 0x0c -#define W_L1IND_AI10 0x0d -#define W_L1IND_CD 0x0f - -/* FIFO thresholds */ -#define W_D_FIFO_THRESH 64 -#define W_B_FIFO_THRESH 64 diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index caa1b52f06f7..cacde8de38a3 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -122,8 +122,6 @@ endmenu comment "ISDN4Linux hardware drivers" -source "drivers/isdn/hisax/Kconfig" - # end ISDN_I4L endif -- cgit v1.2.3 From 9c3c0c2048149d946d7f3ebdcbe70e2946750bfb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Apr 2019 22:43:36 +0200 Subject: isdn: remove isdn4linux With all isdn4linux hardware drivers gone, this is only a wrapper around CAPI to support old user space. However, from looking at the mailing list, it seems that the last time anyone asked about it was in 2014, when the upgrade from a linux-2.4 installation failed, and mISDN was suggested as a replacement. The largest public ISDN network (Deutsche Telekom) was supposed to be shut down 2018, which must have drastically reduced the number of legacy installations. When we last discussed removing i4l in 2016, Karsten Keil suggested revisiting this in 2018. I guess this is overdue. Link: http://listserv.isdn4linux.de/pipermail/isdn4linux/2014-October/006165.html Link: https://patchwork.kernel.org/patch/8484861/#17900371 Link: https://listserv.isdn4linux.de/pipermail/isdn4linux/2019-April/thread.html Signed-off-by: Arnd Bergmann --- Documentation/isdn/INTERFACE | 759 ------- Documentation/isdn/INTERFACE.fax | 163 -- Documentation/isdn/README | 599 ------ Documentation/isdn/README.FAQ | 26 - Documentation/isdn/README.audio | 138 -- Documentation/isdn/README.concap | 259 --- Documentation/isdn/README.diversion | 127 -- Documentation/isdn/README.fax | 45 - Documentation/isdn/README.hfc-pci | 41 - Documentation/isdn/README.syncppp | 58 - Documentation/isdn/README.x25 | 184 -- Documentation/isdn/syncPPP.FAQ | 224 --- Documentation/process/changes.rst | 16 +- MAINTAINERS | 2 - drivers/isdn/Kconfig | 26 - drivers/isdn/Makefile | 2 - drivers/isdn/capi/Kconfig | 9 - drivers/isdn/capi/capidrv.c | 2525 ----------------------- drivers/isdn/capi/capidrv.h | 140 -- drivers/isdn/divert/Makefile | 10 - drivers/isdn/divert/divert_init.c | 82 - drivers/isdn/divert/divert_procfs.c | 336 ---- drivers/isdn/divert/isdn_divert.c | 846 -------- drivers/isdn/divert/isdn_divert.h | 132 -- drivers/isdn/i4l/Kconfig | 127 -- drivers/isdn/i4l/Makefile | 14 - drivers/isdn/i4l/isdn_audio.c | 711 ------- drivers/isdn/i4l/isdn_audio.h | 44 - drivers/isdn/i4l/isdn_bsdcomp.c | 930 --------- drivers/isdn/i4l/isdn_common.c | 2368 ---------------------- drivers/isdn/i4l/isdn_common.h | 47 - drivers/isdn/i4l/isdn_concap.c | 99 - drivers/isdn/i4l/isdn_concap.h | 11 - drivers/isdn/i4l/isdn_net.c | 3198 ----------------------------- drivers/isdn/i4l/isdn_net.h | 151 -- drivers/isdn/i4l/isdn_ppp.c | 3046 ---------------------------- drivers/isdn/i4l/isdn_ppp.h | 41 - drivers/isdn/i4l/isdn_tty.c | 3756 ----------------------------------- drivers/isdn/i4l/isdn_tty.h | 120 -- drivers/isdn/i4l/isdn_ttyfax.c | 1123 ----------- drivers/isdn/i4l/isdn_ttyfax.h | 17 - drivers/isdn/i4l/isdn_v110.c | 625 ------ drivers/isdn/i4l/isdn_v110.h | 29 - drivers/isdn/i4l/isdn_x25iface.c | 332 ---- drivers/isdn/i4l/isdn_x25iface.h | 30 - drivers/isdn/isdnloop/Makefile | 6 - drivers/isdn/isdnloop/isdnloop.c | 1528 -------------- drivers/isdn/isdnloop/isdnloop.h | 112 -- include/linux/concap.h | 112 -- include/linux/isdn.h | 473 ----- include/linux/isdn_divertif.h | 35 - include/linux/isdn_ppp.h | 194 -- include/linux/isdnif.h | 505 ----- include/linux/wanrouter.h | 11 - include/uapi/linux/isdn.h | 144 -- include/uapi/linux/isdn_divertif.h | 31 - include/uapi/linux/isdn_ppp.h | 68 - include/uapi/linux/isdnif.h | 57 - include/uapi/linux/wanrouter.h | 18 - 59 files changed, 2 insertions(+), 26860 deletions(-) delete mode 100644 Documentation/isdn/INTERFACE delete mode 100644 Documentation/isdn/INTERFACE.fax delete mode 100644 Documentation/isdn/README delete mode 100644 Documentation/isdn/README.FAQ delete mode 100644 Documentation/isdn/README.audio delete mode 100644 Documentation/isdn/README.concap delete mode 100644 Documentation/isdn/README.diversion delete mode 100644 Documentation/isdn/README.fax delete mode 100644 Documentation/isdn/README.hfc-pci delete mode 100644 Documentation/isdn/README.syncppp delete mode 100644 Documentation/isdn/README.x25 delete mode 100644 Documentation/isdn/syncPPP.FAQ delete mode 100644 drivers/isdn/capi/capidrv.c delete mode 100644 drivers/isdn/capi/capidrv.h delete mode 100644 drivers/isdn/divert/Makefile delete mode 100644 drivers/isdn/divert/divert_init.c delete mode 100644 drivers/isdn/divert/divert_procfs.c delete mode 100644 drivers/isdn/divert/isdn_divert.c delete mode 100644 drivers/isdn/divert/isdn_divert.h delete mode 100644 drivers/isdn/i4l/Kconfig delete mode 100644 drivers/isdn/i4l/isdn_audio.c delete mode 100644 drivers/isdn/i4l/isdn_audio.h delete mode 100644 drivers/isdn/i4l/isdn_bsdcomp.c delete mode 100644 drivers/isdn/i4l/isdn_common.c delete mode 100644 drivers/isdn/i4l/isdn_common.h delete mode 100644 drivers/isdn/i4l/isdn_concap.c delete mode 100644 drivers/isdn/i4l/isdn_concap.h delete mode 100644 drivers/isdn/i4l/isdn_net.c delete mode 100644 drivers/isdn/i4l/isdn_net.h delete mode 100644 drivers/isdn/i4l/isdn_ppp.c delete mode 100644 drivers/isdn/i4l/isdn_ppp.h delete mode 100644 drivers/isdn/i4l/isdn_tty.c delete mode 100644 drivers/isdn/i4l/isdn_tty.h delete mode 100644 drivers/isdn/i4l/isdn_ttyfax.c delete mode 100644 drivers/isdn/i4l/isdn_ttyfax.h delete mode 100644 drivers/isdn/i4l/isdn_v110.c delete mode 100644 drivers/isdn/i4l/isdn_v110.h delete mode 100644 drivers/isdn/i4l/isdn_x25iface.c delete mode 100644 drivers/isdn/i4l/isdn_x25iface.h delete mode 100644 drivers/isdn/isdnloop/Makefile delete mode 100644 drivers/isdn/isdnloop/isdnloop.c delete mode 100644 drivers/isdn/isdnloop/isdnloop.h delete mode 100644 include/linux/concap.h delete mode 100644 include/linux/isdn.h delete mode 100644 include/linux/isdn_divertif.h delete mode 100644 include/linux/isdn_ppp.h delete mode 100644 include/linux/isdnif.h delete mode 100644 include/linux/wanrouter.h delete mode 100644 include/uapi/linux/isdn.h delete mode 100644 include/uapi/linux/isdn_divertif.h delete mode 100644 include/uapi/linux/isdn_ppp.h delete mode 100644 include/uapi/linux/isdnif.h delete mode 100644 include/uapi/linux/wanrouter.h (limited to 'drivers/isdn') diff --git a/Documentation/isdn/INTERFACE b/Documentation/isdn/INTERFACE deleted file mode 100644 index 5df17e5b25c8..000000000000 --- a/Documentation/isdn/INTERFACE +++ /dev/null @@ -1,759 +0,0 @@ -$Id: INTERFACE,v 1.15.8.2 2001/03/13 16:17:07 kai Exp $ - -Description of the Interface between Linklevel and Hardwarelevel - of isdn4linux: - - - The Communication between Linklevel (LL) and Hardwarelevel (HL) - is based on the struct isdn_if (defined in isdnif.h). - - An HL-driver can register itself at LL by calling the function - register_isdn() with a pointer to that struct. Prior to that, it has - to preset some of the fields of isdn_if. The LL sets the rest of - the fields. All further communication is done via callbacks using - the function-pointers defined in isdn_if. - - Changes/Version numbering: - - During development of the ISDN subsystem, several changes have been - made to the interface. Before it went into kernel, the package - had a unique version number. The last version, distributed separately - was 0.7.4. When the subsystem went into kernel, every functional unit - got a separate version number. These numbers are shown at initialization, - separated by slashes: - - c.c/t.t/n.n/p.p/a.a/v.v - - where - - c.c is the revision of the common code. - t.t is the revision of the tty related code. - n.n is the revision of the network related code. - p.p is the revision of the ppp related code. - a.a is the revision of the audio related code. - v.v is the revision of the V.110 related code. - - Changes in this document are marked with '***CHANGEx' where x representing - the version number. If that number starts with 0, it refers to the old, - separately distributed package. If it starts with one of the letters - above, it refers to the revision of the corresponding module. - ***CHANGEIx refers to the revision number of the isdnif.h - -1. Description of the fields of isdn_if: - - int channels; - - This field has to be set by the HL-driver to the number of channels - supported prior to calling register_isdn(). Upon return of the call, - the LL puts an id there, which has to be used by the HL-driver when - invoking the other callbacks. - - int maxbufsize; - - ***CHANGE0.6: New since this version. - - Also to be preset by the HL-driver. With this value the HL-driver - tells the LL the maximum size of a data-packet it will accept. - - unsigned long features; - - To be preset by the HL-driver. Using this field, the HL-driver - announces the features supported. At the moment this is limited to - report the supported layer2 and layer3-protocols. For setting this - field the constants ISDN_FEATURE..., declared in isdnif.h have to be - used. - - ***CHANGE0.7.1: The line type (1TR6, EDSS1) has to be set. - - unsigned short hl_hdrlen; - - ***CHANGE0.7.4: New field. - - To be preset by the HL-driver, if it supports sk_buff's. The driver - should put here the amount of additional space needed in sk_buff's for - its internal purposes. Drivers not supporting sk_buff's should - initialize this field to 0. - - void (*rcvcallb_skb)(int, int, struct sk_buff *) - - ***CHANGE0.7.4: New field. - - This field will be set by LL. The HL-driver delivers received data- - packets by calling this function. Upon calling, the HL-driver must - already have its private data pulled off the head of the sk_buff. - - Parameter: - int driver-Id - int Channel-number locally to the driver. (starting with 0) - struct sk_buff * Pointer to sk_buff, containing received data. - - int (*statcallb)(isdn_ctrl*); - - This field will be set by LL. This function has to be called by the - HL-driver for signaling status-changes or other events to the LL. - - Parameter: - isdn_ctrl* - - The struct isdn_ctrl also defined in isdn_if. The exact meanings of its - fields are described together with the descriptions of the possible - events. Here is only a short description of the fields: - - driver = driver Id. - command = event-type. (one of the constants ISDN_STAT_...) - arg = depends on event-type. - num = depends on event-type. - - Returnvalue: - 0 on success, else -1 - - int (*command)(isdn_ctrl*); - - This field has to be preset by the HL-driver. It points to a function, - to be called by LL to perform functions like dialing, B-channel - setup, etc. The exact meaning of the parameters is described with the - descriptions of the possible commands. - - Parameter: - isdn_ctrl* - driver = driver-Id - command = command to perform. (one of the constants ISDN_CMD_...) - arg = depends on command. - num = depends on command. - - Returnvalue: - >=0 on success, else error-code (-ENODEV etc.) - - int (*writebuf_skb)(int, int, int, struct sk_buff *) - - ***CHANGE0.7.4: New field. - ***CHANGEI.1.21: New field. - - This field has to be preset by the HL-driver. The given function will - be called by the LL for delivering data to be send via B-Channel. - - - Parameter: - int driver-Id ***CHANGE0.7.4: New parameter. - int channel-number locally to the HL-driver. (starts with 0) - int ack ***ChangeI1.21: New parameter - If this is !0, the driver has to signal the delivery - by sending an ISDN_STAT_BSENT. If this is 0, the driver - MUST NOT send an ISDN_STAT_BSENT. - struct sk_buff * Pointer to sk_buff containing data to be send via - B-channel. - - Returnvalue: - Length of data accepted on success, else error-code (-EINVAL on - oversized packets etc.) - - int (*writecmd)(u_char*, int, int, int, int); - - This field has to be preset by the HL-driver. The given function will be - called to perform write-requests on /dev/isdnctrl (i.e. sending commands - to the card) The data-format is hardware-specific. This function is - intended for debugging only. It is not necessary for normal operation - and never will be called by the tty-emulation- or network-code. If - this function is not supported, the driver has to set NULL here. - - Parameter: - u_char* pointer to data. - int length of data. - int flag: 0 = call from within kernel-space. (HL-driver must use - memcpy, may NOT use schedule()) - 1 = call from user-space. (HL-driver must use - memcpy_fromfs, use of schedule() allowed) - int driver-Id. - int channel-number locally to the HL-driver. (starts with 0) - -***CHANGEI1.14: The driver-Id and channel-number are new since this revision. - - Returnvalue: - Length of data accepted on success, else error-code (-EINVAL etc.) - - int (*readstat)(u_char*, int, int, int, int); - - This field has to be preset by the HL-driver. The given function will be - called to perform read-requests on /dev/isdnctrl (i.e. reading replies - from the card) The data-format is hardware-specific. This function is - intended for debugging only. It is not necessary for normal operation - and never will be called by the tty-emulation- or network-code. If - this function is not supported, the driver has to set NULL here. - - Parameter: - u_char* pointer to data. - int length of data. - int flag: 0 = call from within kernel-space. (HL-driver must use - memcpy, may NOT use schedule()) - 1 = call from user-space. (HL-driver must use - memcpy_fromfs, use of schedule() allowed) - int driver-Id. - int channel-number locally to the HL-driver. (starts with 0) - -***CHANGEI1.14: The driver-Id and channel-number are new since this revision. - - Returnvalue: - Length of data on success, else error-code (-EINVAL etc.) - - char id[20]; - ***CHANGE0.7: New since this version. - - This string has to be preset by the HL-driver. Its purpose is for - identification of the driver by the user. Eg.: it is shown in the - status-info of /dev/isdninfo. Furthermore it is used as Id for binding - net-interfaces to a specific channel. If a string of length zero is - given, upon return, isdn4linux will replace it by a generic name. (line0, - line1 etc.) It is recommended to make this string configurable during - module-load-time. (copy a global variable to this string.) For doing that, - modules 1.2.8 or newer are necessary. - -2. Description of the commands, a HL-driver has to support: - - All commands will be performed by calling the function command() described - above from within the LL. The field command of the struct-parameter will - contain the desired command, the field driver is always set to the - appropriate driver-Id. - - Until now, the following commands are defined: - -***CHANGEI1.34: The parameter "num" has been replaced by a union "parm" containing - the old "num" and a new setup_type struct used for ISDN_CMD_DIAL - and ISDN_STAT_ICALL callback. - - ISDN_CMD_IOCTL: - - This command is intended for performing ioctl-calls for configuring - hardware or similar purposes (setting port-addresses, loading firmware - etc.) For this purpose, in the LL all ioctl-calls with an argument - >= IIOCDRVCTL (0x100) will be handed transparently to this - function after subtracting 0x100 and placing the result in arg. - Example: - If a userlevel-program calls ioctl(0x101,...) the function gets - called with the field command set to 1. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_IOCTL - arg = Original ioctl-cmd - IIOCDRVCTL - parm.num = first bytes filled with (unsigned long)arg - - Returnvalue: - Depending on driver. - - - ISDN_CMD_DIAL: - - This command is used to tell the HL-driver it should dial a given - number. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_DIAL - arg = channel-number locally to the driver. (starting with 0) - - parm.setup.phone = An ASCII-String containing the number to dial. - parm.setup.eazmsn = An ASCII-Sting containing the own EAZ or MSN. - parm.setup.si1 = The Service-Indicator. - parm.setup.si2 = Additional Service-Indicator. - - If the Line has been designed as SPV (a special german - feature, meaning semi-leased-line) the phone has to - start with an "S". - ***CHANGE0.6: In previous versions the EAZ has been given in the - highbyte of arg. - ***CHANGE0.7.1: New since this version: ServiceIndicator and AddInfo. - - ISDN_CMD_ACCEPTD: - - With this command, the HL-driver is told to accept a D-Channel-setup. - (Response to an incoming call) - - Parameter: - driver = driver-Id. - command = ISDN_CMD_ACCEPTD - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - - ISDN_CMD_ACCEPTB: - - With this command, the HL-driver is told to perform a B-Channel-setup. - (after establishing D-Channel-Connection) - - Parameter: - driver = driver-Id. - command = ISDN_CMD_ACCEPTB - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - - ISDN_CMD_HANGUP: - - With this command, the HL-driver is told to hangup (B-Channel if - established first, then D-Channel). This command is also used for - actively rejecting an incoming call. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_HANGUP - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - - ISDN_CMD_CLREAZ: - - With this command, the HL-driver is told not to signal incoming - calls to the LL. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_CLREAZ - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - - ISDN_CMD_SETEAZ: - - With this command, the HL-driver is told to signal incoming calls for - the given EAZs/MSNs to the LL. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_SETEAZ - arg = channel-number locally to the driver. (starting with 0) - parm.num = ASCII-String, containing the desired EAZ's/MSN's - (comma-separated). If an empty String is given, the - HL-driver should respond to ALL incoming calls, - regardless of the destination-address. - ***CHANGE0.6: New since this version the "empty-string"-feature. - - ISDN_CMD_GETEAZ: (currently unused) - - With this command, the HL-driver is told to report the current setting - given with ISDN_CMD_SETEAZ. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_GETEAZ - arg = channel-number locally to the driver. (starting with 0) - parm.num = ASCII-String, containing the current EAZ's/MSN's - - ISDN_CMD_SETSIL: (currently unused) - - With this command, the HL-driver is told to signal only incoming - calls with the given Service-Indicators. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_SETSIL - arg = channel-number locally to the driver. (starting with 0) - parm.num = ASCII-String, containing the desired Service-Indicators. - - ISDN_CMD_GETSIL: (currently unused) - - With this command, the HL-driver is told to return the current - Service-Indicators it will respond to. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_SETSIL - arg = channel-number locally to the driver. (starting with 0) - parm.num = ASCII-String, containing the current Service-Indicators. - - ISDN_CMD_SETL2: - - With this command, the HL-driver is told to select the given Layer-2- - protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or - ISDN_CMD_ACCEPTD. - - - Parameter: - driver = driver-Id. - command = ISDN_CMD_SETL2 - arg = channel-number locally to the driver. (starting with 0) - logical or'ed with (protocol-Id << 8) - protocol-Id is one of the constants ISDN_PROTO_L2... - parm = unused. - - ISDN_CMD_GETL2: (currently unused) - - With this command, the HL-driver is told to return the current - setting of the Layer-2-protocol. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_GETL2 - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - Returnvalue: - current protocol-Id (one of the constants ISDN_L2_PROTO) - - ISDN_CMD_SETL3: - - With this command, the HL-driver is told to select the given Layer-3- - protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or - ISDN_CMD_ACCEPTD. - - - Parameter: - driver = driver-Id. - command = ISDN_CMD_SETL3 - arg = channel-number locally to the driver. (starting with 0) - logical or'ed with (protocol-Id << 8) - protocol-Id is one of the constants ISDN_PROTO_L3... - parm.fax = Pointer to T30_s fax struct. (fax usage only) - - ISDN_CMD_GETL2: (currently unused) - - With this command, the HL-driver is told to return the current - setting of the Layer-3-protocol. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_GETL3 - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - Returnvalue: - current protocol-Id (one of the constants ISDN_L3_PROTO) - - ISDN_CMD_PROCEED: - - With this command, the HL-driver is told to proceed with a incoming call. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_PROCEED - arg = channel-number locally to the driver. (starting with 0) - setup.eazmsn= empty string or string send as uus1 in DSS1 with - PROCEED message - - ISDN_CMD_ALERT: - - With this command, the HL-driver is told to alert a proceeding call. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_ALERT - arg = channel-number locally to the driver. (starting with 0) - setup.eazmsn= empty string or string send as uus1 in DSS1 with - ALERT message - - ISDN_CMD_REDIR: - - With this command, the HL-driver is told to redirect a call in proceeding - or alerting state. - - Parameter: - driver = driver-Id. - command = ISDN_CMD_REDIR - arg = channel-number locally to the driver. (starting with 0) - setup.eazmsn= empty string or string send as uus1 in DSS1 protocol - setup.screen= screening indicator - setup.phone = redirected to party number - - ISDN_CMD_PROT_IO: - - With this call, the LL-driver invokes protocol specific features through - the LL. - The call is not implicitely bound to a connection. - - Parameter: - driver = driver-Id - command = ISDN_CMD_PROT_IO - arg = The lower 8 Bits define the addressed protocol as defined - in ISDN_PTYPE..., the upper bits are used to differentiate - the protocol specific CMD. - - para = protocol and function specific. See isdnif.h for detail. - - - ISDN_CMD_FAXCMD: - - With this command the HL-driver receives a fax sub-command. - For details refer to INTERFACE.fax - - Parameter: - driver = driver-Id. - command = ISDN_CMD_FAXCMD - arg = channel-number locally to the driver. (starting with 0) - parm = unused. - - -3. Description of the events to be signaled by the HL-driver to the LL. - - All status-changes are signaled via calling the previously described - function statcallb(). The field command of the struct isdn_cmd has - to be set by the HL-driver with the appropriate Status-Id (event-number). - The field arg has to be set to the channel-number (locally to the driver, - starting with 0) to which this event applies. (Exception: STAVAIL-event) - - Until now, the following Status-Ids are defined: - - ISDN_STAT_AVAIL: - - With this call, the HL-driver signals the availability of new data - for readstat(). Used only for debugging-purposes, see description - of readstat(). - - Parameter: - driver = driver-Id - command = ISDN_STAT_STAVAIL - arg = length of available data. - parm = unused. - - ISDN_STAT_ICALL: - ISDN_STAT_ICALLW: - - With this call, the HL-driver signals an incoming call to the LL. - If ICALLW is signalled the incoming call is a waiting call without - a available B-chan. - - Parameter: - driver = driver-Id - command = ISDN_STAT_ICALL - arg = channel-number, locally to the driver. (starting with 0) - para.setup.phone = Callernumber. - para.setup.eazmsn = CalledNumber. - para.setup.si1 = Service Indicator. - para.setup.si2 = Additional Service Indicator. - para.setup.plan = octet 3 from Calling party number Information Element. - para.setup.screen = octet 3a from Calling party number Information Element. - - Return: - 0 = No device matching this call. - 1 = At least one device matching this call (RING on ttyI). - HL-driver may send ALERTING on the D-channel in this case. - 2 = Call will be rejected. - 3 = Incoming called party number is currently incomplete. - Additional digits are required. - Used for signalling with PtP connections. - 4 = Call will be held in a proceeding state - (HL driver sends PROCEEDING) - Used when a user space prog needs time to interpret a call - para.setup.eazmsn may be filled with an uus1 message of - 30 octets maximum. Empty string if no uus. - 5 = Call will be actively deflected to another party - Only available in DSS1/EURO protocol - para.setup.phone must be set to destination party number - para.setup.eazmsn may be filled with an uus1 message of - 30 octets maximum. Empty string if no uus. - -1 = An error happened. (Invalid parameters for example.) - The keypad support now is included in the dial command. - - - ISDN_STAT_RUN: - - With this call, the HL-driver signals availability of the ISDN-card. - (after initializing, loading firmware) - - Parameter: - driver = driver-Id - command = ISDN_STAT_RUN - arg = unused. - parm = unused. - - ISDN_STAT_STOP: - - With this call, the HL-driver signals unavailability of the ISDN-card. - (before unloading, while resetting/reconfiguring the card) - - Parameter: - driver = driver-Id - command = ISDN_STAT_STOP - arg = unused. - parm = unused. - - ISDN_STAT_DCONN: - - With this call, the HL-driver signals the successful establishment of - a D-Channel-connection. (Response to ISDN_CMD_ACCEPTD or ISDN_CMD_DIAL) - - Parameter: - driver = driver-Id - command = ISDN_STAT_DCONN - arg = channel-number, locally to the driver. (starting with 0) - parm = unused. - - ISDN_STAT_BCONN: - - With this call, the HL-driver signals the successful establishment of - a B-Channel-connection. (Response to ISDN_CMD_ACCEPTB or because the - remote-station has initiated establishment) - - The HL driver should call this when the logical l2/l3 protocol - connection on top of the physical B-channel is established. - - Parameter: - driver = driver-Id - command = ISDN_STAT_BCONN - arg = channel-number, locally to the driver. (starting with 0) - parm.num = ASCII-String, containing type of connection (for analog - modem only). This will be appended to the CONNECT message - e.g. 14400/V.32bis - - ISDN_STAT_DHUP: - - With this call, the HL-driver signals the shutdown of a - D-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP, - or caused by a remote-hangup or if the remote-station has actively - rejected a call. - - Parameter: - driver = driver-Id - command = ISDN_STAT_DHUP - arg = channel-number, locally to the driver. (starting with 0) - parm = unused. - - ISDN_STAT_BHUP: - - With this call, the HL-driver signals the shutdown of a - B-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP, - or caused by a remote-hangup. - - The HL driver should call this as soon as the logical l2/l3 protocol - connection on top of the physical B-channel is released. - - Parameter: - driver = driver-Id - command = ISDN_STAT_BHUP - arg = channel-number, locally to the driver. (starting with 0) - parm = unused. - - ISDN_STAT_CINF: - - With this call, the HL-driver delivers charge-unit information to the - LL. - - Parameter: - driver = driver-Id - command = ISDN_STAT_CINF - arg = channel-number, locally to the driver. (starting with 0) - parm.num = ASCII string containing charge-units (digits only). - - ISDN_STAT_LOAD: (currently unused) - - ISDN_STAT_UNLOAD: - - With this call, the HL-driver signals that it will be unloaded now. This - tells the LL to release all corresponding data-structures. - - Parameter: - driver = driver-Id - command = ISDN_STAT_UNLOAD - arg = unused. - parm = unused. - - ISDN_STAT_BSENT: - - With this call the HL-driver signals the delivery of a data-packet. - This callback is used by the network-interfaces only, tty-Emulation - does not need this call. - - Parameter: - driver = driver-Id - command = ISDN_STAT_BSENT - arg = channel-number, locally to the driver. (starting with 0) - parm.length = ***CHANGEI.1.21: New field. - the driver has to set this to the original length - of the skb at the time of receiving it from the linklevel. - - ISDN_STAT_NODCH: - - With this call, the driver has to respond to a prior ISDN_CMD_DIAL, if - no D-Channel is available. - - Parameter: - driver = driver-Id - command = ISDN_STAT_NODCH - arg = channel-number, locally to the driver. (starting with 0) - parm = unused. - - ISDN_STAT_ADDCH: - - This call is for HL-drivers, which are unable to check card-type - or numbers of supported channels before they have loaded any firmware - using ioctl. Those HL-driver simply set the channel-parameter to a - minimum channel-number when registering, and later if they know - the real amount, perform this call, allocating additional channels. - - Parameter: - driver = driver-Id - command = ISDN_STAT_ADDCH - arg = number of channels to be added. - parm = unused. - - ISDN_STAT_CAUSE: - - With this call, the HL-driver delivers CAUSE-messages to the LL. - Currently the LL does not use this messages. Their contents is simply - logged via kernel-messages. Therefore, currently the format of the - messages is completely free. However they should be printable. - - Parameter: - driver = driver-Id - command = ISDN_STAT_NODCH - arg = channel-number, locally to the driver. (starting with 0) - parm.num = ASCII string containing CAUSE-message. - - ISDN_STAT_DISPLAY: - - With this call, the HL-driver delivers DISPLAY-messages to the LL. - Currently the LL does not use this messages. - - Parameter: - driver = driver-Id - command = ISDN_STAT_DISPLAY - arg = channel-number, locally to the driver. (starting with 0) - para.display= string containing DISPLAY-message. - - ISDN_STAT_PROT: - - With this call, the HL-driver delivers protocol specific infos to the LL. - The call is not implicitely bound to a connection. - - Parameter: - driver = driver-Id - command = ISDN_STAT_PROT - arg = The lower 8 Bits define the addressed protocol as defined - in ISDN_PTYPE..., the upper bits are used to differentiate - the protocol specific STAT. - - para = protocol and function specific. See isdnif.h for detail. - - ISDN_STAT_DISCH: - - With this call, the HL-driver signals the LL to disable or enable the - use of supplied channel and driver. - The call may be used to reduce the available number of B-channels after - loading the driver. The LL has to ignore a disabled channel when searching - for free channels. The HL driver itself never delivers STAT callbacks for - disabled channels. - The LL returns a nonzero code if the operation was not successful or the - selected channel is actually regarded as busy. - - Parameter: - driver = driver-Id - command = ISDN_STAT_DISCH - arg = channel-number, locally to the driver. (starting with 0) - parm.num[0] = 0 if channel shall be disabled, else enabled. - - ISDN_STAT_L1ERR: - - ***CHANGEI1.21 new status message. - A signal can be sent to the linklevel if an Layer1-error results in - packet-loss on receive or send. The field errcode of the cmd.parm - union describes the error more precisely. - - Parameter: - driver = driver-Id - command = ISDN_STAT_L1ERR - arg = channel-number, locally to the driver. (starting with 0) - parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending. - ISDN_STAT_L1ERR_RECV: Packet lost while receiving. - ISDN_STAT_FAXIND: - - With this call the HL-driver signals a fax sub-command to the LL. - For details refer to INTERFACE.fax - - Parameter: - driver = driver-Id. - command = ISDN_STAT_FAXIND - arg = channel-number, locally to the driver. (starting with 0) - parm = unused. - diff --git a/Documentation/isdn/INTERFACE.fax b/Documentation/isdn/INTERFACE.fax deleted file mode 100644 index 9c8c6d914ec7..000000000000 --- a/Documentation/isdn/INTERFACE.fax +++ /dev/null @@ -1,163 +0,0 @@ -$Id: INTERFACE.fax,v 1.2 2000/08/06 09:22:50 armin Exp $ - - -Description of the fax-subinterface between linklevel and hardwarelevel of - isdn4linux. - - The communication between linklevel (LL) and hardwarelevel (HL) for fax - is based on the struct T30_s (defined in isdnif.h). - This struct is allocated in the LL. - In order to use fax, the LL provides the pointer to this struct with the - command ISDN_CMD_SETL3 (parm.fax). This pointer expires in case of hangup - and when a new channel to a new connection is assigned. - - -Data handling: - In send-mode the HL-driver has to handle the codes and the bit-order - conversion by itself. - In receive-mode the LL-driver takes care of the bit-order conversion - (specified by +FBOR) - -Structure T30_s description: - - This structure stores the values (set by AT-commands), the remote- - capability-values and the command-codes between LL and HL. - - If the HL-driver receives ISDN_CMD_FAXCMD, all needed information - is in this struct set by the LL. - To signal information to the LL, the HL-driver has to set the - parameters and use ISDN_STAT_FAXIND. - (Please refer to INTERFACE) - -Structure T30_s: - - All members are 8-bit unsigned (__u8) - - - resolution - - rate - - width - - length - - compression - - ecm - - binary - - scantime - - id[] - Local faxmachine's parameters, set by +FDIS, +FDCS, +FLID, ... - - - r_resolution - - r_rate - - r_width - - r_length - - r_compression - - r_ecm - - r_binary - - r_scantime - - r_id[] - Remote faxmachine's parameters. To be set by HL-driver. - - - phase - Defines the actual state of fax connection. Set by HL or LL - depending on progress and type of connection. - If the phase changes because of an AT command, the LL driver - changes this value. Otherwise the HL-driver takes care of it, but - only necessary on call establishment (from IDLE to PHASE_A). - (one of the constants ISDN_FAX_PHASE_[IDLE,A,B,C,D,E]) - - - direction - Defines outgoing/send or incoming/receive connection. - (ISDN_TTY_FAX_CONN_[IN,OUT]) - - - code - Commands from LL to HL; possible constants : - ISDN_TTY_FAX_DR signals +FDR command to HL - - ISDN_TTY_FAX_DT signals +FDT command to HL - - ISDN_TTY_FAX_ET signals +FET command to HL - - - Other than that the "code" is set with the hangup-code value at - the end of connection for the +FHNG message. - - - r_code - Commands from HL to LL; possible constants : - ISDN_TTY_FAX_CFR output of +FCFR message. - - ISDN_TTY_FAX_RID output of remote ID set in r_id[] - (+FCSI/+FTSI on send/receive) - - ISDN_TTY_FAX_DCS output of +FDCS and CONNECT message, - switching to phase C. - - ISDN_TTY_FAX_ET signals end of data, - switching to phase D. - - ISDN_TTY_FAX_FCON signals the established, outgoing connection, - switching to phase B. - - ISDN_TTY_FAX_FCON_I signals the established, incoming connection, - switching to phase B. - - ISDN_TTY_FAX_DIS output of +FDIS message and values. - - ISDN_TTY_FAX_SENT signals that all data has been sent - and is acknowledged, - OK message will be sent. - - ISDN_TTY_FAX_PTS signals a msg-confirmation (page sent successful), - depending on fet value: - 0: output OK message (more pages follow) - 1: switching to phase B (next document) - - ISDN_TTY_FAX_TRAIN_OK output of +FDCS and OK message (for receive mode). - - ISDN_TTY_FAX_EOP signals end of data in receive mode, - switching to phase D. - - ISDN_TTY_FAX_HNG output of the +FHNG and value set by code and - OK message, switching to phase E. - - - - badlin - Value of +FBADLIN - - - badmul - Value of +FBADMUL - - - bor - Value of +FBOR - - - fet - Value of +FET command in send-mode. - Set by HL in receive-mode for +FET message. - - - pollid[] - ID-string, set by +FCIG - - - cq - Value of +FCQ - - - cr - Value of +FCR - - - ctcrty - Value of +FCTCRTY - - - minsp - Value of +FMINSP - - - phcto - Value of +FPHCTO - - - rel - Value of +FREL - - - nbc - Value of +FNBC (0,1) - (+FNBC is not a known class 2 fax command, I added this to change the - automatic "best capabilities" connection in the eicon HL-driver) - - -Armin -mac@melware.de - diff --git a/Documentation/isdn/README b/Documentation/isdn/README deleted file mode 100644 index 74bd2bdb455b..000000000000 --- a/Documentation/isdn/README +++ /dev/null @@ -1,599 +0,0 @@ -README for the ISDN-subsystem - -1. Preface - - 1.1 Introduction - - This README describes how to set up and how to use the different parts - of the ISDN-subsystem. - - For using the ISDN-subsystem, some additional userlevel programs are - necessary. Those programs and some contributed utilities are available - at - - ftp.isdn4linux.de - - /pub/isdn4linux/isdn4k-utils-.tar.gz - - - We also have set up a mailing-list: - - The isdn4linux-project originates in Germany, and therefore by historical - reasons, the mailing-list's primary language is german. However mails - written in english have been welcome all the time. - - to subscribe: write a email to majordomo@listserv.isdn4linux.de, - Subject irrelevant, in the message body: - subscribe isdn4linux - - To write to the mailing-list, write to isdn4linux@listserv.isdn4linux.de - - This mailinglist is bidirectionally gated to the newsgroup - - de.alt.comm.isdn4linux - - There is also a well maintained FAQ in English available at - https://www.mhessler.de/i4lfaq/ - It can be viewed online, or downloaded in sgml/text/html format. - The FAQ can also be viewed online at - https://www.isdn4linux.de/faq/i4lfaq.html - or downloaded from - ftp://ftp.isdn4linux.de/pub/isdn4linux/FAQ/ - - 1.1 Technical details - - In the following Text, the terms MSN and EAZ are used. - - MSN is the abbreviation for (M)ultiple(S)ubscriber(N)umber, and applies - to Euro(EDSS1)-type lines. Usually it is simply the phone number. - - EAZ is the abbreviation of (E)ndgeraete(A)uswahl(Z)iffer and - applies to German 1TR6-type lines. This is a one-digit string, - simply appended to the base phone number - - The internal handling is nearly identical, so replace the appropriate - term to that one, which applies to your local ISDN-environment. - - When the link-level-module isdn.o is loaded, it supports up to 16 - low-level-modules with up to 64 channels. (The number 64 is arbitrarily - chosen and can be configured at compile-time --ISDN_MAX in isdn.h). - A low-level-driver can register itself through an interface (which is - defined in isdnif.h) and gets assigned a slot. - The following char-devices are made available for each channel: - - A raw-control-device with the following functions: - write: raw D-channel-messages (format: depends on driver). - read: raw D-channel-messages (format: depends on driver). - ioctl: depends on driver, i.e. for the ICN-driver, the base-address of - the ports and the shared memory on the card can be set and read - also the boot-code and the protocol software can be loaded into - the card. - - O N L Y !!! for debugging (no locking against other devices): - One raw-data-device with the following functions: - write: data to B-channel. - read: data from B-channel. - - In addition the following devices are made available: - - 128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator: - The functionality is almost the same as that of a serial device - (the line-discs are handled by the kernel), which lets you run - SLIP, CSLIP and asynchronous PPP through the devices. We have tested - Seyon, minicom, CSLIP (uri-dip) PPP, mgetty, XCept and Hylafax. - - The modem-emulation supports the following: - 1.3.1 Commands: - - ATA Answer incoming call. - ATD Dial, the number may contain: - [0-9] and [,#.*WPT-S] - the latter are ignored until 'S'. - The 'S' must precede the number, if - the line is a SPV (German 1TR6). - ATE0 Echo off. - ATE1 Echo on (default). - ATH Hang-up. - ATH1 Off hook (ignored). - ATH0 Hang-up. - ATI Return "ISDN for Linux...". - ATI0 " - ATI1 " - ATI2 Report of last connection. - ATO On line (data mode). - ATQ0 Enable result codes (default). - ATQ1 Disable result codes (default). - ATSx=y Set register x to y. - ATSx? Show contents of register x. - ATV0 Numeric responses. - ATV1 English responses (default). - ATZ Load registers and EAZ/MSN from Profile. - AT&Bx Set Send-Packet-size to x (max. 4000) - The real packet-size may be limited by the - low-level-driver used. e.g. the HiSax-Module- - limit is 2000. You will get NO Error-Message, - if you set it to higher values, because at the - time of giving this command the corresponding - driver may not be selected (see "Automatic - Assignment") however the size of outgoing packets - will be limited correctly. - AT&D0 Ignore DTR - AT&D2 DTR-low-edge: Hang up and return to - command mode (default). - AT&D3 Same as AT&D2 but also resets all registers. - AT&Ex Set the EAZ/MSN for this channel to x. - AT&F Reset all registers and profile to "factory-defaults" - AT&Lx Set list of phone numbers to listen on. x is a - list of wildcard patterns separated by semicolon. - If this is set, it has precedence over the MSN set - by AT&E. - AT&Rx Select V.110 bitrate adaption. - This command enables V.110 protocol with 9600 baud - (x=9600), 19200 baud (x=19200) or 38400 baud - (x=38400). A value of x=0 disables V.110 switching - back to default X.75. This command sets the following - Registers: - Reg 14 (Layer-2 protocol): - x = 0: 0 - x = 9600: 7 - x = 19200: 8 - x = 38400: 9 - Reg 18.2 = 1 - Reg 19 (Additional Service Indicator): - x = 0: 0 - x = 9600: 197 - x = 19200: 199 - x = 38400: 198 - Note on value in Reg 19: - There is _NO_ common convention for 38400 baud. - The value 198 is chosen arbitrarily. Users - _MUST_ negotiate this value before establishing - a connection. - AT&Sx Set window-size (x = 1..8) (not yet implemented) - AT&V Show all settings. - AT&W0 Write registers and EAZ/MSN to profile. See also - iprofd (5.c in this README). - AT&X0 BTX-mode and T.70-mode off (default) - AT&X1 BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0) - AT&X2 T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0) - AT+Rx Resume a suspended call with CallID x (x = 1,2,3...) - AT+Sx Suspend a call with CallID x (x = 1,2,3...) - - For voice-mode commands refer to README.audio - - 1.3.2 Escape sequence: - During a connection, the emulation reacts just like - a normal modem to the escape sequence +++. - (The escape character - default '+' - can be set in the - register 2). - The DELAY must at least be 1.5 seconds long and delay - between the escape characters must not exceed 0.5 seconds. - - 1.3.3 Registers: - - Nr. Default Description - 0 0 Answer on ring number. - (no auto-answer if S0=0). - 1 0 Count of rings. - 2 43 Escape character. - (a value >= 128 disables the escape sequence). - 3 13 Carriage return character (ASCII). - 4 10 Line feed character (ASCII). - 5 8 Backspace character (ASCII). - 6 3 Delay in seconds before dialing. - 7 60 Wait for carrier. - 8 2 Pause time for comma (ignored) - 9 6 Carrier detect time (ignored) - 10 7 Carrier loss to disconnect time (ignored). - 11 70 Touch tone timing (ignored). - 12 69 Bit coded register: - Bit 0: 0 = Suppress response messages. - 1 = Show response messages. - Bit 1: 0 = English response messages. - 1 = Numeric response messages. - Bit 2: 0 = Echo off. - 1 = Echo on. - Bit 3 0 = DCD always on. - 1 = DCD follows carrier. - Bit 4 0 = CTS follows RTS - 1 = Ignore RTS, CTS always on. - Bit 5 0 = return to command mode on DTR low. - 1 = Same as 0 but also resets all - registers. - See also register 13, bit 2 - Bit 6 0 = DSR always on. - 1 = DSR only on if channel is available. - Bit 7 0 = Cisco-PPP-flag-hack off (default). - 1 = Cisco-PPP-flag-hack on. - 13 0 Bit coded register: - Bit 0: 0 = Use delayed tty-send-algorithm - 1 = Direct tty-send. - Bit 1: 0 = T.70 protocol (Only for BTX!) off - 1 = T.70 protocol (Only for BTX!) on - Bit 2: 0 = Don't hangup on DTR low. - 1 = Hangup on DTR low. - Bit 3: 0 = Standard response messages - 1 = Extended response messages - Bit 4: 0 = CALLER NUMBER before every RING. - 1 = CALLER NUMBER after first RING. - Bit 5: 0 = T.70 extended protocol off - 1 = T.70 extended protocol on - Bit 6: 0 = Special RUNG Message off - 1 = Special RUNG Message on - "RUNG" is delivered on a ttyI, if - an incoming call happened (RING) and - the remote party hung up before any - local ATA was given. - Bit 7: 0 = Don't show display messages from net - 1 = Show display messages from net - (S12 Bit 1 must be 0 too) - 14 0 Layer-2 protocol: - 0 = X75/LAPB with I-frames - 1 = X75/LAPB with UI-frames - 2 = X75/LAPB with BUI-frames - 3 = HDLC - 4 = Transparent (audio) - 7 = V.110, 9600 baud - 8 = V.110, 19200 baud - 9 = V.110, 38400 baud - 10 = Analog Modem (only if hardware supports this) - 11 = Fax G3 (only if hardware supports this) - 15 0 Layer-3 protocol: - 0 = transparent - 1 = transparent with audio features (e.g. DSP) - 2 = Fax G3 Class 2 commands (S14 has to be set to 11) - 3 = Fax G3 Class 1 commands (S14 has to be set to 11) - 16 250 Send-Packet-size/16 - 17 8 Window-size (not yet implemented) - 18 4 Bit coded register, Service-Octet-1 to accept, - or to be used on dialout: - Bit 0: Service 1 (audio) when set. - Bit 1: Service 5 (BTX) when set. - Bit 2: Service 7 (data) when set. - Note: It is possible to set more than one - bit. In this case, on incoming calls - the selected services are accepted, - and if the service is "audio", the - Layer-2-protocol is automatically - changed to 4 regardless of the setting - of register 14. On outgoing calls, - the most significant 1-bit is chosen to - select the outgoing service octet. - 19 0 Service-Octet-2 - 20 0 Bit coded register (readonly) - Service-Octet-1 of last call. - Bit mapping is the same as register 18 - 21 0 Bit coded register (readonly) - Set on incoming call (during RING) to - octet 3 of calling party number IE (Numbering plan) - See section 4.5.10 of ITU Q.931 - 22 0 Bit coded register (readonly) - Set on incoming call (during RING) to - octet 3a of calling party number IE (Screening info) - See section 4.5.10 of ITU Q.931 - 23 0 Bit coded register: - Bit 0: 0 = Add CPN to RING message off - 1 = Add CPN to RING message on - Bit 1: 0 = Add CPN to FCON message off - 1 = Add CPN to FCON message on - Bit 2: 0 = Add CDN to RING/FCON message off - 1 = Add CDN to RING/FCON message on - - Last but not least a (at the moment fairly primitive) device to request - the line-status (/dev/isdninfo) is made available. - - Automatic assignment of devices to lines: - - All inactive physical lines are listening to all EAZs for incoming - calls and are NOT assigned to a specific tty or network interface. - When an incoming call is detected, the driver looks first for a network - interface and then for an opened tty which: - - 1. is configured for the same EAZ. - 2. has the same protocol settings for the B-channel. - 3. (only for network interfaces if the security flag is set) - contains the caller number in its access list. - 4. Either the channel is not bound exclusively to another Net-interface, or - it is bound AND the other checks apply to exactly this interface. - (For usage of the bind-features, refer to the isdnctrl-man-page) - - Only when a matching interface or tty is found is the call accepted - and the "connection" between the low-level-layer and the link-level-layer - is established and kept until the end of the connection. - In all other cases no connection is established. Isdn4linux can be - configured to either do NOTHING in this case (which is useful, if - other, external devices with the same EAZ/MSN are connected to the bus) - or to reject the call actively. (isdnctrl busreject ...) - - For an outgoing call, the inactive physical lines are searched. - The call is placed on the first physical line, which supports the - requested protocols for the B-channel. If a net-interface, however - is pre-bound to a channel, this channel is used directly. - - This makes it possible to configure several network interfaces and ttys - for one EAZ, if the network interfaces are set to secure operation. - If an incoming call matches one network interface, it gets connected to it. - If another incoming call for the same EAZ arrives, which does not match - a network interface, the first tty gets a "RING" and so on. - -2 System prerequisites: - - ATTENTION! - - Always use the latest module utilities. The current version is - named in Documentation/Changes. Some old versions of insmod - are not capable of setting the driver-Ids correctly. - -3. Lowlevel-driver configuration. - - Configuration depends on how the drivers are built. See the - README. for information on driver-specific setup. - -4. Device-inodes - - The major and minor numbers and their names are described in - Documentation/admin-guide/devices.rst. The major numbers are: - - 43 for the ISDN-tty's. - 44 for the ISDN-callout-tty's. - 45 for control/info/debug devices. - -5. Application - - a) For some card-types, firmware has to be loaded into the cards, before - proceeding with device-independent setup. See README. - for how to do that. - - b) If you only intend to use ttys, you are nearly ready now. - - c) If you want to have really permanent "Modem"-settings on disk, you - can start the daemon iprofd. Give it a path to a file at the command- - line. It will store the profile-settings in this file every time - an AT&W0 is performed on any ISDN-tty. If the file already exists, - all profiles are initialized from this file. If you want to unload - any of the modules, kill iprofd first. - - d) For networking, continue: Create an interface: - isdnctrl addif isdn0 - - e) Set the EAZ (or MSN for Euro-ISDN): - isdnctrl eaz isdn0 2 - - (For 1TR6 a single digit is allowed, for Euro-ISDN the number is your - real MSN e.g.: Phone-Number) - - f) Set the number for outgoing calls on the interface: - isdnctrl addphone isdn0 out 1234567 - ... (this can be executed more than once, all assigned numbers are - tried in order) - and the number(s) for incoming calls: - isdnctrl addphone isdn0 in 1234567 - - g) Set the timeout for hang-up: - isdnctrl huptimeout isdn0 - - h) additionally you may activate charge-hang-up (= Hang up before - next charge-info, this only works, if your isdn-provider transmits - the charge-info during and after the connection): - isdnctrl chargehup isdn0 on - - i) Set the dial mode of the interface: - isdnctrl dialmode isdn0 auto - "off" means that you (or the system) cannot make any connection - (neither incoming or outgoing connections are possible). Use - this if you want to be sure that no connections will be made. - "auto" means that the interface is in auto-dial mode, and will - attempt to make a connection whenever a network data packet needs - the interface's link. Note that this can cause unexpected dialouts, - and lead to a high phone bill! Some daemons or other pc's that use - this interface can cause this. - Incoming connections are also possible. - "manual" is a dial mode created to prevent the unexpected dialouts. - In this mode, the interface will never make any connections on its - own. You must explicitly initiate a connection with "isdnctrl dial - isdn0". However, after an idle time of no traffic as configured for - the huptimeout value with isdnctrl, the connection _will_ be ended. - If you don't want any automatic hangup, set the huptimeout value to 0. - "manual" is the default. - - j) Setup the interface with ifconfig as usual, and set a route to it. - - k) (optional) If you run X11 and have Tcl/Tk-wish version 4.0, you can use - the script tools/tcltk/isdnmon. You can add actions for line-status - changes. See the comments at the beginning of the script for how to - do that. There are other tty-based tools in the tools-subdirectory - contributed by Michael Knigge (imon), Volker Götz (imontty) and - Andreas Kool (isdnmon). - - l) For initial testing, you can set the verbose-level to 2 (default: 0). - Then all incoming calls are logged, even if they are not addressed - to one of the configured net-interfaces: - isdnctrl verbose 2 - - Now you are ready! A ping to the set address should now result in an - automatic dial-out (look at syslog kernel-messages). - The phone numbers and EAZs can be assigned at any time with isdnctrl. - You can add as many interfaces as you like with addif following the - directions above. Of course, there may be some limitations. But we have - tested as many as 20 interfaces without any problem. However, if you - don't give an interface name to addif, the kernel will assign a name - which starts with "eth". The number of "eth"-interfaces is limited by - the kernel. - -5. Additional options for isdnctrl: - - "isdnctrl secure on" - Only incoming calls, for which the caller-id is listed in the access - list of the interface are accepted. You can add caller-id's With the - command "isdnctrl addphone in " - Euro-ISDN does not transmit the leading '0' of the caller-id for an - incoming call, therefore you should configure it accordingly. - If the real number for the dialout e.g. is "09311234567" the number - to configure here is "9311234567". The pattern-match function - works similar to the shell mechanism. - - ? one arbitrary digit - * zero or arbitrary many digits - [123] one of the digits in the list - [1-5] one digit between '1' and '5' - a '^' as the first character in a list inverts the list - - - "isdnctrl secure off" - Switch off secure operation (default). - - "isdnctrl ihup [on|off]" - Switch the hang-up-timer for incoming calls on or off. - - "isdnctrl eaz " - Returns the EAZ of an interface. - - "isdnctrl delphone in|out " - Deletes a number from one of the access-lists of the interface. - - "isdnctrl delif " - Removes the interface (and possible slaves) from the kernel. - (You have to unregister it with "ifconfig down" before). - - "isdnctrl callback [on|off]" - Switches an interface to callback-mode. In this mode, an incoming call - will be rejected and after this the remote-station will be called. If - you test this feature by using ping, some routers will re-dial very - quickly, so that the callback from isdn4linux may not be recognized. - In this case use ping with the option -i to increase the interval - between echo-packets. - - "isdnctrl cbdelay [seconds]" - Sets the delay (default 5 sec) between an incoming call and start of - dialing when callback is enabled. - - "isdnctrl cbhup [on|off]" - This enables (default) or disables an active hangup (reject) when getting an - incoming call for an interface which is configured for callback. - - "isdnctrl encap " - Selects the type of packet-encapsulation. The encapsulation can be changed - only while an interface is down. - - At the moment the following values are supported: - - rawip (Default) Selects raw-IP-encapsulation. This means, MAC-headers - are stripped off. - ip IP with type-field. Same as IP but the type-field of the MAC-header - is preserved. - x25iface X.25 interface encapsulation (first byte semantics as defined in - ../networking/x25-iface.txt). Use this for running the linux - X.25 network protocol stack (AF_X25 sockets) on top of isdn. - cisco-h A special-mode for communicating with a Cisco, which is configured - to do "hdlc" - ethernet No stripping. Packets are sent with full MAC-header. - The Ethernet-address of the interface is faked, from its - IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values. - syncppp Synchronous PPP - - uihdlc HDLC with UI-frame-header (for use with DOS ISPA, option -h1) - - - NOTE: x25iface encapsulation is currently experimental. Please - read README.x25 for further details - - - Watching packets, using standard-tcpdump will fail for all encapsulations - except ethernet because tcpdump does not know how to handle packets - without MAC-header. A patch for tcpdump is included in the utility-package - mentioned above. - - "isdnctrl l2_prot " - Selects a layer-2-protocol. - (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available. - With other drivers, "x75ui", "x75bui", "x25dte", "x25dce" may be - possible too. See README.x25 for x25 related l2 protocols.) - - isdnctrl l3_prot - The same for layer-3. (At the moment only "trans" is allowed) - - "isdnctrl list " - Shows all parameters of an interface and the charge-info. - Try "all" as the interface name. - - "isdnctrl hangup " - Forces hangup of an interface. - - "isdnctrl bind , [exclusive]" - If you are using more than one ISDN card, it is sometimes necessary to - dial out using a specific card or even preserve a specific channel for - dialout of a specific net-interface. This can be done with the above - command. Replace by whatever you assigned while loading the - module. The is counted from zero. The upper limit - depends on the card used. At the moment no card supports more than - 2 channels, so the upper limit is one. - - "isdnctrl unbind " - unbinds a previously bound interface. - - "isdnctrl busreject on|off" - If switched on, isdn4linux replies a REJECT to incoming calls, it - cannot match to any configured interface. - If switched off, nothing happens in this case. - You normally should NOT enable this feature, if the ISDN adapter is not - the only device connected to the S0-bus. Otherwise it could happen that - isdn4linux rejects an incoming call, which belongs to another device on - the bus. - - "isdnctrl addslave - Creates a slave interface for channel-bundling. Slave interfaces are - not seen by the kernel, but their ISDN-part can be configured with - isdnctrl as usual. (Phone numbers, EAZ/MSN, timeouts etc.) If more - than two channels are to be bundled, feel free to create as many as you - want. InterfaceName must be a real interface, NOT a slave. Slave interfaces - start dialing, if the master interface resp. the previous slave interface - has a load of more than 7000 cps. They hangup if the load goes under 7000 - cps, according to their "huptimeout"-parameter. - - "isdnctrl sdelay secs." - This sets the minimum time an Interface has to be fully loaded, until - it sends a dial-request to its slave. - - "isdnctrl dial " - Forces an interface to start dialing even if no packets are to be - transferred. - - "isdnctrl mapping MSN0,MSN1,MSN2,...MSN9" - This installs a mapping table for EAZ<->MSN-mapping for a single line. - Missing MSN's have to be given as "-" or can be omitted, if at the end - of the commandline. - With this command, it's now possible to have an interface listening to - mixed 1TR6- and Euro-Type lines. In this case, the interface has to be - configured to a 1TR6-type EAZ (one digit). The mapping is also valid - for tty-emulation. Seen from the interface/tty-level the mapping - CAN be used, however it's possible to use single tty's/interfaces with - real MSN's (more digits) also, in which case the mapping will be ignored. - Here is an example: - - You have a 1TR6-type line with base-nr. 1234567 and a Euro-line with - MSN's 987654, 987655 and 987656. The DriverId for the Euro-line is "EURO". - - isdnctrl mapping EURO -,987654,987655,987656,-,987655 - ... - isdnctrl eaz isdn0 1 # listen on 12345671(1tr6) and 987654(euro) - ... - isdnctrl eaz isdn1 4 # listen on 12345674(1tr6) only. - ... - isdnctrl eaz isdn2 987654 # listen on 987654(euro) only. - - Same scheme is used with AT&E... at the tty's. - -6. If you want to write a new low-level-driver, you are welcome. - The interface to the link-level-module is described in the file INTERFACE. - If the interface should be expanded for any reason, don't do it - on your own, send me a mail containing the proposed changes and - some reasoning about them. - If other drivers will not be affected, I will include the changes - in the next release. - For developers only, there is a second mailing-list. Write to me - (fritz@isdn4linux.de), if you want to join that list. - -Have fun! - - -Fritz - diff --git a/Documentation/isdn/README.FAQ b/Documentation/isdn/README.FAQ deleted file mode 100644 index e5dd1addacdd..000000000000 --- a/Documentation/isdn/README.FAQ +++ /dev/null @@ -1,26 +0,0 @@ - -The FAQ for isdn4linux -====================== - -Please note that there is a big FAQ available in the isdn4k-utils. -You find it in: - isdn4k-utils/FAQ/i4lfaq.sgml - -In case you just want to see the FAQ online, or download the newest version, -you can have a look at my website: -https://www.mhessler.de/i4lfaq/ (view + download) -or: -https://www.isdn4linux.de/faq/4lfaq.html (view) - -As the extension tells, the FAQ is in SGML format, and you can convert it -into text/html/... format by using the sgml2txt/sgml2html/... tools. -Alternatively, you can also do a 'configure; make all' in the FAQ directory. - - -Please have a look at the FAQ before posting anything in the Mailinglist, -or the newsgroup! - - -Matthias Hessler -hessler@isdn4linux.de - diff --git a/Documentation/isdn/README.audio b/Documentation/isdn/README.audio deleted file mode 100644 index 8ebca19290d9..000000000000 --- a/Documentation/isdn/README.audio +++ /dev/null @@ -1,138 +0,0 @@ -$Id: README.audio,v 1.8 1999/07/11 17:17:29 armin Exp $ - -ISDN subsystem for Linux. - Description of audio mode. - -When enabled during kernel configuration, the tty emulator of the ISDN -subsystem is capable of a reduced set of commands to support audio. -This document describes the commands supported and the format of -audio data. - -Commands for enabling/disabling audio mode: - - AT+FCLASS=8 Enable audio mode. - This affects the following registers: - S18: Bits 0 and 2 are set. - S16: Set to 48 and any further change to - larger values is blocked. - AT+FCLASS=0 Disable audio mode. - Register 18 is set to 4. - AT+FCLASS=? Show possible modes. - AT+FCLASS? Report current mode (0 or 8). - -Commands supported in audio mode: - -All audio mode commands have one of the following forms: - - AT+Vxx? Show current setting. - AT+Vxx=? Show possible settings. - AT+Vxx=v Set simple parameter. - AT+Vxx=v,v ... Set complex parameter. - -where xx is a two-character code and v are alphanumerical parameters. -The following commands are supported: - - AT+VNH=x Auto hangup setting. NO EFFECT, supported - for compatibility only. - AT+VNH? Always reporting "1" - AT+VNH=? Always reporting "1" - - AT+VIP Reset all audio parameters. - - AT+VLS=x Line select. x is one of the following: - 0 = No device. - 2 = Phone line. - AT+VLS=? Always reporting "0,2" - AT+VLS? Show current line. - - AT+VRX Start recording. Emulator responds with - CONNECT and starts sending audio data to - the application. See below for data format - - AT+VSD=x,y Set silence-detection parameters. - Possible parameters: - x = 0 ... 31 sensitivity threshold level. - (default 0 , deactivated) - y = 0 ... 255 range of interval in units - of 0.1 second. (default 70) - AT+VSD=? Report possible parameters. - AT+VSD? Show current parameters. - - AT+VDD=x,y Set DTMF-detection parameters. - Only possible if online and during this connection. - Possible parameters: - x = 0 ... 15 sensitivity threshold level. - (default 0 , I4L soft-decode) - (1-15 soft-decode off, hardware on) - y = 0 ... 255 tone duration in units of 5ms. - Not for I4L soft decode (default 8, 40ms) - AT+VDD=? Report possible parameters. - AT+VDD? Show current parameters. - - AT+VSM=x Select audio data format. - Possible parameters: - 2 = ADPCM-2 - 3 = ADPCM-3 - 4 = ADPCM-4 - 5 = aLAW - 6 = uLAW - AT+VSM=? Show possible audio formats. - - AT+VTX Start audio playback. Emulator responds - with CONNECT and starts sending audio data - received from the application via phone line. -General behavior and description of data formats/protocol. - when a connection is made: - - On incoming calls, if the application responds to a RING - with ATA, depending on the calling service, the emulator - responds with either CONNECT (data call) or VCON (voice call). - - On outgoing voice calls, the emulator responds with VCON - upon connection setup. - - Audio recording. - - When receiving audio data, a kind of bisync protocol is used. - Upon AT+VRX command, the emulator responds with CONNECT, and - starts sending audio data to the application. There are several - escape sequences defined, all using DLE (0x10) as Escape char: - - End of audio data. (i.e. caused by a - hangup of the remote side) Emulator stops - recording, responding with VCON. - Abort recording, (send by appl.) Emulator - stops recording, sends DLE,ETX. - Escape sequence for DLE in data stream. - 0 Touchtone "0" received. - ... - 9 Touchtone "9" received. - # Touchtone "#" received. - * Touchtone "*" received. - A Touchtone "A" received. - B Touchtone "B" received. - C Touchtone "C" received. - D Touchtone "D" received. - - q quiet. Silence detected after non-silence. - s silence. Silence detected from the - start of recording. - - Currently unsupported DLE sequences: - - c FAX calling tone received. - b busy tone received. - - Audio playback. - - When sending audio data, upon AT+VTX command, emulator responds with - CONNECT, and starts transferring data from application to the phone line. - The same DLE sequences apply to this mode. - - Full-Duplex-Audio: - - When _both_ commands for recording and playback are given in _one_ - AT-command-line (i.e.: "AT+VTX+VRX"), full-duplex-mode is selected. - In this mode, the only way to stop recording is sending - and the only way to stop playback is to send . - diff --git a/Documentation/isdn/README.concap b/Documentation/isdn/README.concap deleted file mode 100644 index a76d74845a4c..000000000000 --- a/Documentation/isdn/README.concap +++ /dev/null @@ -1,259 +0,0 @@ -Description of the "concap" encapsulation protocol interface -============================================================ - -The "concap" interface is intended to be used by network device -drivers that need to process an encapsulation protocol. -It is assumed that the protocol interacts with a linux network device by -- data transmission -- connection control (establish, release) -Thus, the mnemonic: "CONnection CONtrolling eNCAPsulation Protocol". - -This is currently only used inside the isdn subsystem. But it might -also be useful to other kinds of network devices. Thus, if you want -to suggest changes that improve usability or performance of the -interface, please let me know. I'm willing to include them in future -releases (even if I needed to adapt the current isdn code to the -changed interface). - - -Why is this useful? -=================== - -The encapsulation protocol used on top of WAN connections or permanent -point-to-point links are frequently chosen upon bilateral agreement. -Thus, a device driver for a certain type of hardware must support -several different encapsulation protocols at once. - -The isdn device driver did already support several different -encapsulation protocols. The encapsulation protocol is configured by a -user space utility (isdnctrl). The isdn network interface code then -uses several case statements which select appropriate actions -depending on the currently configured encapsulation protocol. - -In contrast, LAN network interfaces always used a single encapsulation -protocol which is unique to the hardware type of the interface. The LAN -encapsulation is usually done by just sticking a header on the data. Thus, -traditional linux network device drivers used to process the -encapsulation protocol directly (usually by just providing a hard_header() -method in the device structure) using some hardware type specific support -functions. This is simple, direct and efficient. But it doesn't fit all -the requirements for complex WAN encapsulations. - - - The configurability of the encapsulation protocol to be used - makes isdn network interfaces more flexible, but also much more - complex than traditional lan network interfaces. - - -Many Encapsulation protocols used on top of WAN connections will not just -stick a header on the data. They also might need to set up or release -the WAN connection. They also might want to send other data for their -private purpose over the wire, e.g. ppp does a lot of link level -negotiation before the first piece of user data can be transmitted. -Such encapsulation protocols for WAN devices are typically more complex -than encapsulation protocols for lan devices. Thus, network interface -code for typical WAN devices also tends to be more complex. - - -In order to support Linux' x25 PLP implementation on top of -isdn network interfaces I could have introduced yet another branch to -the various case statements inside drivers/isdn/isdn_net.c. -This eventually made isdn_net.c even more complex. In addition, it made -isdn_net.c harder to maintain. Thus, by identifying an abstract -interface between the network interface code and the encapsulation -protocol, complexity could be reduced and maintainability could be -increased. - - -Likewise, a similar encapsulation protocol will frequently be needed by -several different interfaces of even different hardware type, e.g. the -synchronous ppp implementation used by the isdn driver and the -asynchronous ppp implementation used by the ppp driver have a lot of -similar code in them. By cleanly separating the encapsulation protocol -from the hardware specific interface stuff such code could be shared -better in future. - - -When operating over dial-up-connections (e.g. telephone lines via modem, -non-permanent virtual circuits of wide area networks, ISDN) many -encapsulation protocols will need to control the connection. Therefore, -some basic connection control primitives are supported. The type and -semantics of the connection (i.e the ISO layer where connection service -is provided) is outside our scope and might be different depending on -the encapsulation protocol used, e.g. for a ppp module using our service -on top of a modem connection a connect_request will result in dialing -a (somewhere else configured) remote phone number. For an X25-interface -module (LAPB semantics, as defined in Documentation/networking/x25-iface.txt) -a connect_request will ask for establishing a reliable lapb -datalink connection. - - -The encapsulation protocol currently provides the following -service primitives to the network device. - -- create a new encapsulation protocol instance -- delete encapsulation protocol instance and free all its resources -- initialize (open) the encapsulation protocol instance for use. -- deactivate (close) an encapsulation protocol instance. -- process (xmit) data handed down by upper protocol layer -- receive data from lower (hardware) layer -- process connect indication from lower (hardware) layer -- process disconnect indication from lower (hardware) layer - - -The network interface driver accesses those primitives via callbacks -provided by the encapsulation protocol instance within a -struct concap_proto_ops. - -struct concap_proto_ops{ - - /* create a new encapsulation protocol instance of same type */ - struct concap_proto * (*proto_new) (void); - - /* delete encapsulation protocol instance and free all its resources. - cprot may no longer be referenced after calling this */ - void (*proto_del)(struct concap_proto *cprot); - - /* initialize the protocol's data. To be called at interface startup - or when the device driver resets the interface. All services of the - encapsulation protocol may be used after this*/ - int (*restart)(struct concap_proto *cprot, - struct net_device *ndev, - struct concap_device_ops *dops); - - /* deactivate an encapsulation protocol instance. The encapsulation - protocol may not call any *dops methods after this. */ - int (*close)(struct concap_proto *cprot); - - /* process a frame handed down to us by upper layer */ - int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb); - - /* to be called for each data entity received from lower layer*/ - int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb); - - /* to be called when a connection was set up/down. - Protocols that don't process these primitives might fill in - dummy methods here */ - int (*connect_ind)(struct concap_proto *cprot); - int (*disconn_ind)(struct concap_proto *cprot); -}; - - -The data structures are defined in the header file include/linux/concap.h. - - -A Network interface using encapsulation protocols must also provide -some service primitives to the encapsulation protocol: - -- request data being submitted by lower layer (device hardware) -- request a connection being set up by lower layer -- request a connection being released by lower layer - -The encapsulation protocol accesses those primitives via callbacks -provided by the network interface within a struct concap_device_ops. - -struct concap_device_ops{ - - /* to request data be submitted by device */ - int (*data_req)(struct concap_proto *, struct sk_buff *); - - /* Control methods must be set to NULL by devices which do not - support connection control. */ - /* to request a connection be set up */ - int (*connect_req)(struct concap_proto *); - - /* to request a connection be released */ - int (*disconn_req)(struct concap_proto *); -}; - -The network interface does not explicitly provide a receive service -because the encapsulation protocol directly calls netif_rx(). - - - - -An encapsulation protocol itself is actually the -struct concap_proto{ - struct net_device *net_dev; /* net device using our service */ - struct concap_device_ops *dops; /* callbacks provided by device */ - struct concap_proto_ops *pops; /* callbacks provided by us */ - int flags; - void *proto_data; /* protocol specific private data, to - be accessed via *pops methods only*/ - /* - : - whatever - : - */ -}; - -Most of this is filled in when the device requests the protocol to -be reset (opend). The network interface must provide the net_dev and -dops pointers. Other concap_proto members should be considered private -data that are only accessed by the pops callback functions. Likewise, -a concap proto should access the network device's private data -only by means of the callbacks referred to by the dops pointer. - - -A possible extended device structure which uses the connection controlling -encapsulation services could look like this: - -struct concap_device{ - struct net_device net_dev; - struct my_priv /* device->local stuff */ - /* the my_priv struct might contain a - struct concap_device_ops *dops; - to provide the device specific callbacks - */ - struct concap_proto *cprot; /* callbacks provided by protocol */ -}; - - - -Misc Thoughts -============= - -The concept of the concap proto might help to reuse protocol code and -reduce the complexity of certain network interface implementations. -The trade off is that it introduces yet another procedure call layer -when processing the protocol. This has of course some impact on -performance. However, typically the concap interface will be used by -devices attached to slow lines (like telephone, isdn, leased synchronous -lines). For such slow lines, the overhead is probably negligible. -This might no longer hold for certain high speed WAN links (like -ATM). - - -If general linux network interfaces explicitly supported concap -protocols (e.g. by a member struct concap_proto* in struct net_device) -then the interface of the service function could be changed -by passing a pointer of type (struct net_device*) instead of -type (struct concap_proto*). Doing so would make many of the service -functions compatible to network device support functions. - -e.g. instead of the concap protocol's service function - - int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb); - -we could have - - int (*encap_and_xmit)(struct net_device *ndev, struct sk_buff *skb); - -As this is compatible to the dev->hard_start_xmit() method, the device -driver could directly register the concap protocol's encap_and_xmit() -function as its hard_start_xmit() method. This would eliminate one -procedure call layer. - - -The device's data request function could also be defined as - - int (*data_req)(struct net_device *ndev, struct sk_buff *skb); - -This might even allow for some protocol stacking. And the network -interface might even register the same data_req() function directly -as its hard_start_xmit() method when a zero layer encapsulation -protocol is configured. Thus, eliminating the performance penalty -of the concap interface when a trivial concap protocol is used. -Nevertheless, the device remains able to support encapsulation -protocol configuration. - diff --git a/Documentation/isdn/README.diversion b/Documentation/isdn/README.diversion deleted file mode 100644 index bddcd5fb86ff..000000000000 --- a/Documentation/isdn/README.diversion +++ /dev/null @@ -1,127 +0,0 @@ -The isdn diversion services are a supporting module working together with -the isdn4linux and the HiSax module for passive cards. -Active cards, TAs and cards using a own or other driver than the HiSax -module need to be adapted to the HL<->LL interface described in a separate -document. The diversion services may be used with all cards supported by -the HiSax driver. -The diversion kernel interface and controlling tool divertctrl were written -by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) under the -GNU General Public License. - - 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. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Table of contents -================= - -1. Features of the i4l diversion services - (Or what can the i4l diversion services do for me) - -2. Required hard- and software - -3. Compiling, installing and loading/unloading the module - Tracing calling and diversion information - -4. Tracing calling and diversion information - -5. Format of the divert device ASCII output - - -1. Features of the i4l diversion services - (Or what can the i4l diversion services do for me) - - The i4l diversion services offers call forwarding and logging normally - only supported by isdn phones. Incoming calls may be diverted - unconditionally (CFU), when not reachable (CFNR) or on busy condition - (CFB). - The diversions may be invoked statically in the providers exchange - as normally done by isdn phones. In this case all incoming calls - with a special (or all) service identifiers are forwarded if the - forwarding reason is met. Activated static services may also be - interrogated (queried). - The i4l diversion services additionally offers a dynamic version of - call forwarding which is not preprogrammed inside the providers exchange - but dynamically activated by i4l. - In this case all incoming calls are checked by rules that may be - compared to the mechanism of ipfwadm or ipchains. If a given rule matches - the checking process is finished and the rule matching will be applied - to the call. - The rules include primary and secondary service identifiers, called - number and subaddress, callers number and subaddress and whether the rule - matches to all filtered calls or only those when all B-channel resources - are exhausted. - Actions that may be invoked by a rule are ignore, proceed, reject, - direct divert or delayed divert of a call. - All incoming calls matching a rule except the ignore rule a reported and - logged as ASCII via the proc filesystem (/proc/net/isdn/divert). If proceed - is selected the call will be held in a proceeding state (without ringing) - for a certain amount of time to let an external program or client decide - how to handle the call. - - -2. Required hard- and software - - For using the i4l diversion services the isdn line must be of a EURO/DSS1 - type. Additionally the i4l services only work together with the HiSax - driver for passive isdn cards. All HiSax supported cards may be used for - the diversion purposes. - The static diversion services require the provider having static services - CFU, CFNR, CFB activated on an MSN-line. The static services may not be - used on a point-to-point connection. Further the static services are only - available in some countries (for example germany). Countries requiring the - keypad protocol for activating static diversions (like the netherlands) are - not supported but may use the tty devices for this purpose. - The dynamic diversion services may be used in all countries if the provider - enables the feature CF (call forwarding). This should work on both MSN- and - point-to-point lines. - To add and delete rules the additional divertctrl program is needed. This - program is part of the isdn4kutils package. - -3. Compiling, installing and loading/unloading the module - Tracing calling and diversion information - - - To compile the i4l code with diversion support you need to say yes to the - DSS1 diversion services when selecting the i4l options in the kernel - config (menuconfig or config). - After having properly activated a make modules and make modules_install all - required modules will be correctly installed in the needed modules dirs. - As the diversion services are currently not included in the scripts of most - standard distributions you will have to add a "insmod dss1_divert" after - having loaded the global isdn module. - The module can be loaded without any command line parameters. - If the module is actually loaded and active may be checked with a - "cat /proc/modules" or "ls /proc/net/isdn/divert". The divert file is - dynamically created by the diversion module and removed when the module is - unloaded. - - -4. Tracing calling and diversion information - - You also may put a "cat /proc/net/isdn/divert" in the background with the - output redirected to a file. Then all actions of the module are logged. - The divert file in the proc system may be opened more than once, so in - conjunction with inetd and a small remote client on other machines inside - your network incoming calls and reactions by the module may be shown on - every listening machine. - If a call is reported as proceeding an external program or client may - specify during a certain amount of time (normally 4 to 10 seconds) what - to do with that call. - To unload the module all open files to the device in the proc system must - be closed. Otherwise the module (and isdn.o) may not be unloaded. - -5. Format of the divert device ASCII output - - To be done later - diff --git a/Documentation/isdn/README.fax b/Documentation/isdn/README.fax deleted file mode 100644 index 5314958a8a6e..000000000000 --- a/Documentation/isdn/README.fax +++ /dev/null @@ -1,45 +0,0 @@ - -Fax with isdn4linux -=================== - -When enabled during kernel configuration, the tty emulator -of the ISDN subsystem is capable of the Fax Class 2 commands. - -This only makes sense under the following conditions : - -- You need the commands as dummy, because you are using - hylafax (with patch) for AVM capi. -- You want to use the fax capabilities of your isdn-card. - (supported cards are listed below) - - -NOTE: This implementation does *not* support fax with passive - ISDN-cards (known as softfax). The low-level driver of - the ISDN-card and/or the card itself must support this. - - -Supported ISDN-Cards --------------------- - -Eicon DIVA Server BRI/PCI - - full support with both B-channels. - -Eicon DIVA Server 4BRI/PCI - - full support with all B-channels. - -Eicon DIVA Server PRI/PCI - - full support on amount of B-channels - depending on DSPs on board. - - - -The command set is known as Class 2 (not Class 2.0) and -can be activated by AT+FCLASS=2 - - -The interface between the link-level-module and the hardware-level driver -is described in the files INTERFACE.fax and INTERFACE. - -Armin -mac@melware.de - diff --git a/Documentation/isdn/README.hfc-pci b/Documentation/isdn/README.hfc-pci deleted file mode 100644 index e8a4ef0226e8..000000000000 --- a/Documentation/isdn/README.hfc-pci +++ /dev/null @@ -1,41 +0,0 @@ -The driver for the HFC-PCI and HFC-PCI-A chips from CCD may be used -for many OEM cards using this chips. -Additionally the driver has a special feature which makes it possible -to read the echo-channel of the isdn bus. So all frames in both directions -may be logged. -When the echo logging feature is used the number of available B-channels -for a HFC-PCI card is reduced to 1. Of course this is only relevant to -the card, not to the isdn line. -To activate the echo mode the following ioctls must be entered: - -hisaxctrl 10 1 - -This reduces the available channels to 1. There must not be open connections -through this card when entering the command. -And then: - -hisaxctrl 12 1 - -This enables the echo mode. If Hex logging is activated the isdnctrlx -devices show a output with a line beginning of HEX: for the providers -exchange and ECHO: for isdn devices sending to the provider. - -If more than one HFC-PCI cards are installed, a specific card may be selected -at the hisax module load command line. Supply the load command with the desired -IO-address of the desired card. -Example: -There tree cards installed in your machine at IO-base addresses 0xd000, 0xd400 -and 0xdc00 -If you want to use the card at 0xd400 standalone you should supply the insmod -or depmod with type=35 io=0xd400. -If you want to use all three cards, but the order needs to be at 0xdc00,0xd400, -0xd000 you may give the parameters type=35,35,35 io=0xdc00,0xd400,0xd00 -Then the desired card will be the initialised in the desired order. -If the io parameter is used the io addresses of all used cards should be -supplied else the parameter is assumed 0 and a auto search for a free card is -invoked which may not give the wanted result. - -Comments and reports to werner@isdn4linux.de or werner@isdn-development.de - - - diff --git a/Documentation/isdn/README.syncppp b/Documentation/isdn/README.syncppp deleted file mode 100644 index 27d260095cce..000000000000 --- a/Documentation/isdn/README.syncppp +++ /dev/null @@ -1,58 +0,0 @@ -Some additional information for setting up a syncPPP -connection using network interfaces. ---------------------------------------------------------------- - -You need one thing beside the isdn4linux package: - - a patched pppd .. (I called it ipppd to show the difference) - -Compiling isdn4linux with sync PPP: ------------------------------------ -To compile isdn4linux with the sync PPP part, you have -to answer the appropriate question when doing a "make config" -Don't forget to load the slhc.o -module before the isdn.o module, if VJ-compression support -is not compiled into your kernel. (e.g if you have no PPP or -CSLIP in the kernel) - -Using isdn4linux with sync PPP: -------------------------------- -Sync PPP is just another encapsulation for isdn4linux. The -name to enable sync PPP encapsulation is 'syncppp' .. e.g: - - /sbin/isdnctrl encap ippp0 syncppp - -The name of the interface is here 'ippp0'. You need -one interface with the name 'ippp0' to saturate the -ipppd, which checks the ppp version via this interface. -Currently, all devices must have the name ipppX where -'X' is a decimal value. - -To set up a PPP connection you need the ipppd .. You must start -the ipppd once after installing the modules. The ipppd -communicates with the isdn4linux link-level driver using the -/dev/ippp0 to /dev/ippp15 devices. One ipppd can handle -all devices at once. If you want to use two PPP connections -at the same time, you have to connect the ipppd to two -devices .. and so on. -I've implemented one additional option for the ipppd: - 'useifip' will get (if set to not 0.0.0.0) the IP address - for the negotiation from the attached network-interface. -(also: ipppd will try to negotiate pointopoint IP as remote IP) -You must disable BSD-compression, this implementation can't -handle compressed packets. - -Check the etc/rc.isdn.syncppp in the isdn4kernel-util package -for an example setup script. - -To use the MPPP stuff, you must configure a slave device -with isdn4linux. Now call the ipppd with the '+mp' option. -To increase the number of links, you must use the -'addlink' option of the isdnctrl tool. (rc.isdn.syncppp.MPPP is -an example script) - -enjoy it, - michael - - - diff --git a/Documentation/isdn/README.x25 b/Documentation/isdn/README.x25 deleted file mode 100644 index e561a77c4e22..000000000000 --- a/Documentation/isdn/README.x25 +++ /dev/null @@ -1,184 +0,0 @@ - -X.25 support within isdn4linux -============================== - -This is alpha/beta test code. Use it completely at your own risk. -As new versions appear, the stuff described here might suddenly change -or become invalid without notice. - -Keep in mind: - -You are using several new parts of the 2.2.x kernel series which -have not been tested in a large scale. Therefore, you might encounter -more bugs as usual. - -- If you connect to an X.25 neighbour not operated by yourself, ASK the - other side first. Be prepared that bugs in the protocol implementation - might result in problems. - -- This implementation has never wiped out my whole hard disk yet. But as - this is experimental code, don't blame me if that happened to you. - Backing up important data will never harm. - -- Monitor your isdn connections while using this software. This should - prevent you from undesired phone bills in case of driver problems. - - - - -How to configure the kernel -=========================== - -The ITU-T (former CCITT) X.25 network protocol layer has been implemented -in the Linux source tree since version 2.1.16. The isdn subsystem might be -useful to run X.25 on top of ISDN. If you want to try it, select - - "CCITT X.25 Packet Layer" - -from the networking options as well as - - "ISDN Support" and "X.25 PLP on Top of ISDN" - -from the ISDN subsystem options when you configure your kernel for -compilation. You currently also need to enable -"Prompt for development and/or incomplete code/drivers" from the -"Code maturity level options" menu. For the x25trace utility to work -you also need to enable "Packet socket". - -For local testing it is also recommended to enable the isdnloop driver -from the isdn subsystem's configuration menu. - -For testing, it is recommended that all isdn drivers and the X.25 PLP -protocol are compiled as loadable modules. Like this, you can recover -from certain errors by simply unloading and reloading the modules. - - - -What's it for? How to use it? -============================= - -X.25 on top of isdn might be useful with two different scenarios: - -- You might want to access a public X.25 data network from your Linux box. - You can use i4l if you were physically connected to the X.25 switch - by an ISDN B-channel (leased line as well as dial up connection should - work). - - This corresponds to ITU-T recommendation X.31 Case A (circuit-mode - access to PSPDN [packet switched public data network]). - - NOTE: X.31 also covers a Case B (access to PSPDN via virtual - circuit / packet mode service). The latter mode (which in theory - also allows using the D-channel) is not supported by isdn4linux. - It should however be possible to establish such packet mode connections - with certain active isdn cards provided that the firmware supports X.31 - and the driver exports this functionality to the user. Currently, - the AVM B1 driver is the only driver which does so. (It should be - possible to access D-channel X.31 with active AVM cards using the - CAPI interface of the AVM-B1 driver). - -- Or you might want to operate certain ISDN teleservices on your linux - box. A lot of those teleservices run on top of the ISO-8208 - (DTE-DTE mode) network layer protocol. ISO-8208 is essentially the - same as ITU-T X.25. - - Popular candidates of such teleservices are EUROfile transfer or any - teleservice applying ITU-T recommendation T.90. - -To use the X.25 protocol on top of isdn, just create an isdn network -interface as usual, configure your own and/or peer's ISDN numbers, -and choose x25iface encapsulation by - - isdnctrl encap x25iface. - -Once encap is set like this, the device can be used by the X.25 packet layer. - -All the stuff needed for X.25 is implemented inside the isdn link -level (mainly isdn_net.c and some new source files). Thus, it should -work with every existing HL driver. I was able to successfully open X.25 -connections on top of the isdnloop driver and the hisax driver. -"x25iface"-encapsulation bypasses demand dialing. Dialing will be -initiated when the upper (X.25 packet) layer requests the lapb datalink to -be established. But hangup timeout is still active. Whenever a hangup -occurs, all existing X.25 connections on that link will be cleared -It is recommended to use sufficiently large hangup-timeouts for the -isdn interfaces. - - -In order to set up a conforming protocol stack you also need to -specify the proper l2_prot parameter: - -To operate in ISO-8208 X.25 DTE-DTE mode, use - - isdnctrl l2_prot x75i - -To access an X.25 network switch via isdn (your linux box is the DTE), use - - isdnctrl l2_prot x25dte - -To mimic an X.25 network switch (DCE side of the connection), use - - isdnctrl l2_prot x25dce - -However, x25dte or x25dce is currently not supported by any real HL -level driver. The main difference between x75i and x25dte/dce is that -x25d[tc]e uses fixed lap_b addresses. With x75i, the side which -initiates the isdn connection uses the DTE's lap_b address while the -called side used the DCE's lap_b address. Thus, l2_prot x75i might -probably work if you access a public X.25 network as long as the -corresponding isdn connection is set up by you. At least one test -was successful to connect via isdn4linux to an X.25 switch using this -trick. At the switch side, a terminal adapter X.21 was used to connect -it to the isdn. - - -How to set up a test installation? -================================== - -To test X.25 on top of isdn, you need to get - -- a recent version of the "isdnctrl" program that supports setting the new - X.25 specific parameters. - -- the x25-utils-2.X package from - ftp://ftp.hes.iki.fi/pub/ham/linux/ax25/x25utils-* - (don't confuse the x25-utils with the ax25-utils) - -- an application program that uses linux PF_X25 sockets (some are - contained in the x25-util package). - -Before compiling the user level utilities make sure that the compiler/ -preprocessor will fetch the proper kernel header files of this kernel -source tree. Either make /usr/include/linux a symbolic link pointing to -this kernel's include/linux directory or set the appropriate compiler flags. - -When all drivers and interfaces are loaded and configured you need to -ifconfig the network interfaces up and add X.25-routes to them. Use -the usual ifconfig tool. - -ifconfig up - -But a special x25route tool (distributed with the x25-util package) -is needed to set up X.25 routes. I.e. - -x25route add 01 - -will cause all x.25 connections to the destination X.25-address -"01" to be routed to your created isdn network interface. - -There are currently no real X.25 applications available. However, for -tests, the x25-utils package contains a modified version of telnet -and telnetd that uses X.25 sockets instead of tcp/ip sockets. You can -use those for your first tests. Furthermore, you might check -ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/ which contains some -alpha-test implementation ("eftp4linux") of the EUROfile transfer -protocol. - -The scripts distributed with the eftp4linux test releases might also -provide useful examples for setting up X.25 on top of isdn. - -The x25-utility package also contains an x25trace tool that can be -used to monitor X.25 packets received by the network interfaces. -The /proc/net/x25* files also contain useful information. - -- Henner diff --git a/Documentation/isdn/syncPPP.FAQ b/Documentation/isdn/syncPPP.FAQ deleted file mode 100644 index 3257a4bc0786..000000000000 --- a/Documentation/isdn/syncPPP.FAQ +++ /dev/null @@ -1,224 +0,0 @@ -simple isdn4linux PPP FAQ .. to be continued .. not 'debugged' -------------------------------------------------------------------- - -Q01: what's pppd, ipppd, syncPPP, asyncPPP ?? -Q02: error message "this system lacks PPP support" -Q03: strange information using 'ifconfig' -Q04: MPPP?? What's that and how can I use it ... -Q05: I tried MPPP but it doesn't work -Q06: can I use asynchronous PPP encapsulation with network devices -Q07: A SunISDN machine can't connect to my i4l system -Q08: I wanna talk to several machines, which need different configs -Q09: Starting the ipppd, I get only error messages from i4l -Q10: I wanna use dynamic IP address assignment -Q11: I can't connect. How can I check where the problem is. -Q12: How can I reduce login delay? - -------------------------------------------------------------------- - -Q01: pppd, ipppd, syncPPP, asyncPPP .. what is that ? - what should I use? -A: The pppd is for asynchronous PPP .. asynchronous means - here, the framing is character based. (e.g when - using ttyI* or tty* devices) - - The ipppd handles PPP packets coming in HDLC - frames (bit based protocol) ... The PPP driver - in isdn4linux pushes all IP packets direct - to the network layer and all PPP protocol - frames to the /dev/ippp* device. - So, the ipppd is a simple external network - protocol handler. - - If you login into a remote machine using the - /dev/ttyI* devices and then enable PPP on the - remote terminal server -> use the 'old' pppd - - If your remote side immediately starts to send - frames ... you probably connect to a - syncPPP machine .. use the network device part - of isdn4linux with the 'syncppp' encapsulation - and make sure, that the ipppd is running and - connected to at least one /dev/ippp*. Check the - isdn4linux manual on how to configure a network device. - --- - -Q02: when I start the ipppd .. I only get the - error message "this system lacks PPP support" -A: check that at least the device 'ippp0' exists. - (you can check this e.g with the program 'ifconfig') - The ipppd NEEDS this device under THIS name .. - If this device doesn't exists, use: - isdnctrl addif ippp0 - isdnctrl encap ippp0 syncppp - ... (see isdn4linux doc for more) ... -A: Maybe you have compiled the ipppd with another - kernel source tree than the kernel you currently - run ... - --- - -Q03: when I list the netdevices with ifconfig I see, that - my ISDN interface has a HWaddr and IRQ=0 and Base - address = 0 -A: The device is a fake ethernet device .. ignore IRQ and baseaddr - You need the HWaddr only for ethernet encapsulation. - --- - -Q04: MPPP?? What's that and how can I use it ... - -A: MPPP or MP or MPP (Warning: MP is also an - acronym for 'Multi Processor') stands for - Multi Point to Point and means bundling - of several channels to one logical stream. - To enable MPPP negotiation you must call the - ipppd with the '+mp' option. - You must also configure a slave device for - every additional channel. (see the i4l manual - for more) - To use channel bundling you must first activate - the 'master' or initial call. Now you can add - the slave channels with the command: - isdnctrl addlink - e.g: - isdnctrl addlink ippp0 - This is different from other encapsulations of - isdn4linux! With syncPPP, there is no automatic - activation of slave devices. - --- - -Q05: I tried MPPP but it doesn't work .. the ipppd - writes in the debug log something like: - .. rcvd [0][proto=0x3d] c0 00 00 00 80 fd 01 01 00 0a ... - .. sent [0][LCP ProtRej id=0x2 00 3d c0 00 00 00 80 fd 01 ... - -A: you forgot to compile MPPP/RFC1717 support into the - ISDN Subsystem. Recompile with this option enabled. - --- - -Q06: can I use asynchronous PPP encapsulation - over the network interface of isdn4linux .. - -A: No .. that's not possible .. Use the standard - PPP package over the /dev/ttyI* devices. You - must not use the ipppd for this. - --- - -Q07: A SunISDN machine tries to connect my i4l system, - which doesn't work. - Checking the debug log I just saw garbage like: -!![ ... fill in the line ... ]!! - -A: The Sun tries to talk asynchronous PPP ... i4l - can't understand this ... try to use the ttyI* - devices with the standard PPP/pppd package - -A: (from Alexanter Strauss: ) -!![ ... fill in mail ]!! - --- - -Q08: I wanna talk to remote machines, which need - a different configuration. The only way - I found to do this is to kill the ipppd and - start a new one with another config to connect - to the second machine. - -A: you must bind a network interface explicitly to - an ippp device, where you can connect a (for this - interface) individually configured ipppd. - --- - -Q09: When I start the ipppd I only get error messages - from the i4l driver .. - -A: When starting, the ipppd calls functions which may - trigger a network packet. (e.g gethostbyname()). - Without the ipppd (at this moment, it is not - fully started) we can't handle this network request. - Try to configure hostnames necessary for the ipppd - in your local /etc/hosts file or in a way, that - your system can resolve it without using an - isdn/ippp network-interface. - --- - -Q10: I wanna use dynamic IP address assignment ... How - must I configure the network device. - -A: At least you must have a route which forwards - a packet to the ippp network-interface to trigger - the dial-on-demand. - A default route to the ippp-interface will work. - Now you must choose a dummy IP address for your - interface. - If for some reason you can't set the default - route to the ippp interface, you may take any - address of the subnet from which you expect your - dynamic IP number and set a 'network route' for - this subnet to the ippp interface. - To allow overriding of the dummy address you - must call the ipppd with the 'ipcp-accept-local' option. - -A: You must know, how the ipppd gets the addresses it wanna - configure. If you don't give any option, the ipppd - tries to negotiate the local host address! - With the option 'noipdefault' it requests an address - from the remote machine. With 'useifip' it gets the - addresses from the net interface. Or you set the address - on the option line with the option. - Note: the IP address of the remote machine must be configured - locally or the remote machine must send it in an IPCP request. - If your side doesn't know the IP address after negotiation, it - closes the connection! - You must allow overriding of address with the 'ipcp-accept-*' - options, if you have set your own or the remote address - explicitly. - -A: Maybe you try these options .. e.g: - - /sbin/ipppd :$REMOTE noipdefault /dev/ippp0 - - where REMOTE must be the address of the remote machine (the - machine, which gives you your address) - --- - -Q11: I can't connect. How can I check where the problem is. - -A: A good help log is the debug output from the ipppd... - Check whether you can find there: - - only a few LCP-conf-req SENT messages (less then 10) - and then a Term-REQ: - -> check whether your ISDN card is well configured - it seems, that your machine doesn't dial - (IRQ,IO,Proto, etc problems) - Configure your ISDN card to print debug messages and - check the /dev/isdnctrl output next time. There - you can see, whether there is activity on the card/line. - - there are at least a few RECV messages in the log: - -> fine: your card is dialing and your remote machine - tries to talk with you. Maybe only a missing - authentication. Check your ipppd configuration again. - - the ipppd exits for some reason: - -> not good ... check /var/adm/syslog and /var/adm/daemon. - Could be a bug in the ipppd. - --- - -Q12: How can I reduce login delay? - -A: Log a login session ('debug' log) and check which options - your remote side rejects. Next time configure your ipppd - to not negotiate these options. Another 'side effect' is, that - this increases redundancy. (e.g your remote side is buggy and - rejects options in a wrong way). - - - diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 18735dc460a0..111636ad1bad 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -23,8 +23,8 @@ running, the suggested command should tell you. Again, keep in mind that this list assumes you are already functionally running a Linux kernel. Also, not all tools are necessary on all -systems; obviously, if you don't have any ISDN hardware, for example, -you probably needn't concern yourself with isdn4k-utils. +systems; obviously, if you don't have any PC Card hardware, for example, +you probably needn't concern yourself with pcmciautils. ====================== =============== ======================================== Program Minimal version Command to check the version @@ -45,7 +45,6 @@ btrfs-progs 0.18 btrfsck pcmciautils 004 pccardctl -V quota-tools 3.09 quota -V PPP 2.4.0 pppd --version -isdn4k-utils 3.1pre1 isdnctrl 2>&1|grep version nfs-utils 1.0.5 showmount --version procps 3.2.0 ps --version oprofile 0.9 oprofiled --version @@ -279,12 +278,6 @@ which can be made by:: as root. -Isdn4k-utils ------------- - -Due to changes in the length of the phone number field, isdn4k-utils -needs to be recompiled or (preferably) upgraded. - NFS-utils --------- @@ -448,11 +441,6 @@ PPP - -Isdn4k-utils ------------- - -- - NFS-utils --------- diff --git a/MAINTAINERS b/MAINTAINERS index 0c55b0fedbe2..3a761e680296 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8371,9 +8371,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/isdn-2.6.git S: Maintained F: Documentation/isdn/ F: drivers/isdn/ -F: include/linux/isdn.h F: include/linux/isdn/ -F: include/uapi/linux/isdn.h F: include/uapi/linux/isdn/ IT87 HARDWARE MONITORING DRIVER diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 1ca4d70d198a..6e3bf833c67e 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -21,27 +21,6 @@ menuconfig ISDN if ISDN -menuconfig ISDN_I4L - tristate "Old ISDN4Linux (deprecated)" - depends on TTY - ---help--- - This driver allows you to use an ISDN adapter for networking - connections and as dialin/out device. The isdn-tty's have a built - in AT-compatible modem emulator. Network devices support autodial, - channel-bundling, callback and caller-authentication without having - a daemon running. A reduced T.70 protocol is supported with tty's - suitable for German BTX. On D-Channel, the protocols EDSS1 - (Euro-ISDN) and 1TR6 (German style) are supported. See - for more information. - - ISDN support in the linux kernel is moving towards a new API, - called CAPI (Common ISDN Application Programming Interface). - Therefore the old ISDN4Linux layer will eventually become obsolete. - It is still available, though, for use with adapters that are not - supported by the new CAPI subsystem yet. - -source "drivers/isdn/i4l/Kconfig" - menuconfig ISDN_CAPI tristate "CAPI 2.0 subsystem" help @@ -71,9 +50,4 @@ source "drivers/isdn/hysdn/Kconfig" source "drivers/isdn/mISDN/Kconfig" -config ISDN_HDLC - tristate - select CRC_CCITT - select BITREVERSE - endif # ISDN diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 7487f0bbe855..379b4a03c321 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -7,7 +7,5 @@ obj-$(CONFIG_ISDN_I4L) += i4l/ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_MISDN) += mISDN/ obj-$(CONFIG_ISDN) += hardware/ -obj-$(CONFIG_ISDN_DIVERSION) += divert/ -obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/ obj-$(CONFIG_HYSDN) += hysdn/ obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/ diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index abaadce376c5..089dbee18f36 100644 --- a/drivers/isdn/capi/Kconfig +++ b/drivers/isdn/capi/Kconfig @@ -27,15 +27,6 @@ config ISDN_CAPI_MIDDLEWARE device. If you want to use pppd with pppdcapiplugin to dial up to your ISP, say Y here. -config ISDN_CAPI_CAPIDRV - tristate "CAPI2.0 capidrv interface support" - depends on ISDN_I4L - help - This option provides the glue code to hook up CAPI driven cards to - the legacy isdn4linux link layer. If you have a card which is - supported by a CAPI driver, but still want to use old features like - ippp interfaces or ttyI emulation, say Y/M here. - config ISDN_CAPI_CAPIDRV_VERBOSE bool "Verbose reason code reporting" depends on ISDN_CAPI_CAPIDRV diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c deleted file mode 100644 index e8949f3dcae1..000000000000 --- a/drivers/isdn/capi/capidrv.c +++ /dev/null @@ -1,2525 +0,0 @@ -/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $ - * - * ISDN4Linux Driver, using capi20 interface (kernelcapi) - * - * Copyright 1997 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "capidrv.h" - -static int debugmode = 0; - -MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); -module_param(debugmode, uint, S_IRUGO | S_IWUSR); - -/* -------- type definitions ----------------------------------------- */ - - -struct capidrv_contr { - - struct capidrv_contr *next; - struct module *owner; - u32 contrnr; - char name[20]; - - /* - * for isdn4linux - */ - isdn_if interface; - int myid; - - /* - * LISTEN state - */ - int state; - u32 cipmask; - u32 cipmask2; - struct timer_list listentimer; - - /* - * ID of capi message sent - */ - u16 msgid; - - /* - * B-Channels - */ - int nbchan; - struct capidrv_bchan { - struct capidrv_contr *contr; - u8 msn[ISDN_MSNLEN]; - int l2; - int l3; - u8 num[ISDN_MSNLEN]; - u8 mynum[ISDN_MSNLEN]; - int si1; - int si2; - int incoming; - int disconnecting; - struct capidrv_plci { - struct capidrv_plci *next; - u32 plci; - u32 ncci; /* ncci for CONNECT_ACTIVE_IND */ - u16 msgid; /* to identfy CONNECT_CONF */ - int chan; - int state; - int leasedline; - struct capidrv_ncci { - struct capidrv_ncci *next; - struct capidrv_plci *plcip; - u32 ncci; - u16 msgid; /* to identfy CONNECT_B3_CONF */ - int chan; - int state; - int oldstate; - /* */ - u16 datahandle; - struct ncci_datahandle_queue { - struct ncci_datahandle_queue *next; - u16 datahandle; - int len; - } *ackqueue; - } *ncci_list; - } *plcip; - struct capidrv_ncci *nccip; - } *bchans; - - struct capidrv_plci *plci_list; - - /* for q931 data */ - u8 q931_buf[4096]; - u8 *q931_read; - u8 *q931_write; - u8 *q931_end; -}; - - -struct capidrv_data { - struct capi20_appl ap; - int ncontr; - struct capidrv_contr *contr_list; -}; - -typedef struct capidrv_plci capidrv_plci; -typedef struct capidrv_ncci capidrv_ncci; -typedef struct capidrv_contr capidrv_contr; -typedef struct capidrv_data capidrv_data; -typedef struct capidrv_bchan capidrv_bchan; - -/* -------- data definitions ----------------------------------------- */ - -static capidrv_data global; -static DEFINE_SPINLOCK(global_lock); - -static void handle_dtrace_data(capidrv_contr *card, - int send, int level2, u8 *data, u16 len); - -/* -------- convert functions ---------------------------------------- */ - -static inline u32 b1prot(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - return 0; - case ISDN_PROTO_L2_HDLC: - default: - return 0; - case ISDN_PROTO_L2_TRANS: - return 1; - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - return 2; - case ISDN_PROTO_L2_FAX: - return 4; - case ISDN_PROTO_L2_MODEM: - return 8; - } -} - -static inline u32 b2prot(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - default: - return 0; - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_TRANS: - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - case ISDN_PROTO_L2_MODEM: - return 1; - case ISDN_PROTO_L2_FAX: - return 4; - } -} - -static inline u32 b3prot(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_TRANS: - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - case ISDN_PROTO_L2_MODEM: - default: - return 0; - case ISDN_PROTO_L2_FAX: - return 4; - } -} - -static _cstruct b1config_async_v110(u16 rate) -{ - /* CAPI-Spec "B1 Configuration" */ - static unsigned char buf[9]; - buf[0] = 8; /* len */ - /* maximum bitrate */ - buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff; - buf[3] = 8; buf[4] = 0; /* 8 bits per character */ - buf[5] = 0; buf[6] = 0; /* parity none */ - buf[7] = 0; buf[8] = 0; /* 1 stop bit */ - return buf; -} - -static _cstruct b1config(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_TRANS: - default: - return NULL; - case ISDN_PROTO_L2_V11096: - return b1config_async_v110(9600); - case ISDN_PROTO_L2_V11019: - return b1config_async_v110(19200); - case ISDN_PROTO_L2_V11038: - return b1config_async_v110(38400); - } -} - -static inline u16 si2cip(u8 si1, u8 si2) -{ - static const u8 cip[17][5] = - { - /* 0 1 2 3 4 */ - {0, 0, 0, 0, 0}, /*0 */ - {16, 16, 4, 26, 16}, /*1 */ - {17, 17, 17, 4, 4}, /*2 */ - {2, 2, 2, 2, 2}, /*3 */ - {18, 18, 18, 18, 18}, /*4 */ - {2, 2, 2, 2, 2}, /*5 */ - {0, 0, 0, 0, 0}, /*6 */ - {2, 2, 2, 2, 2}, /*7 */ - {2, 2, 2, 2, 2}, /*8 */ - {21, 21, 21, 21, 21}, /*9 */ - {19, 19, 19, 19, 19}, /*10 */ - {0, 0, 0, 0, 0}, /*11 */ - {0, 0, 0, 0, 0}, /*12 */ - {0, 0, 0, 0, 0}, /*13 */ - {0, 0, 0, 0, 0}, /*14 */ - {22, 22, 22, 22, 22}, /*15 */ - {27, 27, 27, 28, 27} /*16 */ - }; - if (si1 > 16) - si1 = 0; - if (si2 > 4) - si2 = 0; - - return (u16) cip[si1][si2]; -} - -static inline u8 cip2si1(u16 cipval) -{ - static const u8 si[32] = - {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */ - 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */ - 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */ - 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */ - - if (cipval > 31) - cipval = 0; /* .... */ - return si[cipval]; -} - -static inline u8 cip2si2(u16 cipval) -{ - static const u8 si[32] = - {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */ - 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */ - 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */ - 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */ - - if (cipval > 31) - cipval = 0; /* .... */ - return si[cipval]; -} - - -/* -------- controller management ------------------------------------- */ - -static inline capidrv_contr *findcontrbydriverid(int driverid) -{ - unsigned long flags; - capidrv_contr *p; - - spin_lock_irqsave(&global_lock, flags); - for (p = global.contr_list; p; p = p->next) - if (p->myid == driverid) - break; - spin_unlock_irqrestore(&global_lock, flags); - return p; -} - -static capidrv_contr *findcontrbynumber(u32 contr) -{ - unsigned long flags; - capidrv_contr *p = global.contr_list; - - spin_lock_irqsave(&global_lock, flags); - for (p = global.contr_list; p; p = p->next) - if (p->contrnr == contr) - break; - spin_unlock_irqrestore(&global_lock, flags); - return p; -} - - -/* -------- plci management ------------------------------------------ */ - -static capidrv_plci *new_plci(capidrv_contr *card, int chan) -{ - capidrv_plci *plcip; - - plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC); - - if (plcip == NULL) - return NULL; - - plcip->state = ST_PLCI_NONE; - plcip->plci = 0; - plcip->msgid = 0; - plcip->chan = chan; - plcip->next = card->plci_list; - card->plci_list = plcip; - card->bchans[chan].plcip = plcip; - - return plcip; -} - -static capidrv_plci *find_plci_by_plci(capidrv_contr *card, u32 plci) -{ - capidrv_plci *p; - for (p = card->plci_list; p; p = p->next) - if (p->plci == plci) - return p; - return NULL; -} - -static capidrv_plci *find_plci_by_msgid(capidrv_contr *card, u16 msgid) -{ - capidrv_plci *p; - for (p = card->plci_list; p; p = p->next) - if (p->msgid == msgid) - return p; - return NULL; -} - -static capidrv_plci *find_plci_by_ncci(capidrv_contr *card, u32 ncci) -{ - capidrv_plci *p; - for (p = card->plci_list; p; p = p->next) - if (p->plci == (ncci & 0xffff)) - return p; - return NULL; -} - -static void free_plci(capidrv_contr *card, capidrv_plci *plcip) -{ - capidrv_plci **pp; - - for (pp = &card->plci_list; *pp; pp = &(*pp)->next) { - if (*pp == plcip) { - *pp = (*pp)->next; - card->bchans[plcip->chan].plcip = NULL; - card->bchans[plcip->chan].disconnecting = 0; - card->bchans[plcip->chan].incoming = 0; - kfree(plcip); - return; - } - } - printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n", - card->contrnr, plcip, plcip->plci); -} - -/* -------- ncci management ------------------------------------------ */ - -static inline capidrv_ncci *new_ncci(capidrv_contr *card, - capidrv_plci *plcip, - u32 ncci) -{ - capidrv_ncci *nccip; - - nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC); - - if (nccip == NULL) - return NULL; - - nccip->ncci = ncci; - nccip->state = ST_NCCI_NONE; - nccip->plcip = plcip; - nccip->chan = plcip->chan; - nccip->datahandle = 0; - - nccip->next = plcip->ncci_list; - plcip->ncci_list = nccip; - - card->bchans[plcip->chan].nccip = nccip; - - return nccip; -} - -static inline capidrv_ncci *find_ncci(capidrv_contr *card, u32 ncci) -{ - capidrv_plci *plcip; - capidrv_ncci *p; - - if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) - return NULL; - - for (p = plcip->ncci_list; p; p = p->next) - if (p->ncci == ncci) - return p; - return NULL; -} - -static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr *card, - u32 ncci, u16 msgid) -{ - capidrv_plci *plcip; - capidrv_ncci *p; - - if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) - return NULL; - - for (p = plcip->ncci_list; p; p = p->next) - if (p->msgid == msgid) - return p; - return NULL; -} - -static void free_ncci(capidrv_contr *card, struct capidrv_ncci *nccip) -{ - struct capidrv_ncci **pp; - - for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) { - if (*pp == nccip) { - *pp = (*pp)->next; - break; - } - } - card->bchans[nccip->chan].nccip = NULL; - kfree(nccip); -} - -static int capidrv_add_ack(struct capidrv_ncci *nccip, - u16 datahandle, int len) -{ - struct ncci_datahandle_queue *n, **pp; - - n = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC); - if (!n) { - printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n"); - return -1; - } - n->next = NULL; - n->datahandle = datahandle; - n->len = len; - for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next); - *pp = n; - return 0; -} - -static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle) -{ - struct ncci_datahandle_queue **pp, *p; - int len; - - for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) { - if ((*pp)->datahandle == datahandle) { - p = *pp; - len = p->len; - *pp = (*pp)->next; - kfree(p); - return len; - } - } - return -1; -} - -/* -------- convert and send capi message ---------------------------- */ - -static void send_message(capidrv_contr *card, _cmsg *cmsg) -{ - struct sk_buff *skb; - size_t len; - - if (capi_cmsg2message(cmsg, cmsg->buf)) { - printk(KERN_ERR "capidrv::send_message: parser failure\n"); - return; - } - len = CAPIMSG_LEN(cmsg->buf); - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "capidrv::send_message: can't allocate mem\n"); - return; - } - skb_put_data(skb, cmsg->buf, len); - if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) - kfree_skb(skb); -} - -/* -------- state machine -------------------------------------------- */ - -struct listenstatechange { - int actstate; - int nextstate; - int event; -}; - -static struct listenstatechange listentable[] = -{ - {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {}, -}; - -static void listen_change_state(capidrv_contr *card, int event) -{ - struct listenstatechange *p = listentable; - while (p->event) { - if (card->state == p->actstate && p->event == event) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n", - card->contrnr, card->state, p->nextstate); - card->state = p->nextstate; - return; - } - p++; - } - printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n", - card->contrnr, card->state, event); - -} - -/* ------------------------------------------------------------------ */ - -static void p0(capidrv_contr *card, capidrv_plci *plci) -{ - isdn_ctrl cmd; - - card->bchans[plci->chan].contr = NULL; - cmd.command = ISDN_STAT_DHUP; - cmd.driver = card->myid; - cmd.arg = plci->chan; - card->interface.statcallb(&cmd); - free_plci(card, plci); -} - -/* ------------------------------------------------------------------ */ - -struct plcistatechange { - int actstate; - int nextstate; - int event; - void (*changefunc)(capidrv_contr *card, capidrv_plci *plci); -}; - -static struct plcistatechange plcitable[] = -{ - /* P-0 */ - {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL}, - {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL}, - {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL}, - {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL}, - /* P-0.1 */ - {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, - {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL}, - /* P-1 */ - {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-ACT */ - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL}, - /* P-2 */ - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL}, - /* P-3 */ - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-4 */ - {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-5 */ - {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-6 */ - {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, - /* P-0.Res */ - {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, - {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL}, - /* P-RES */ - {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL}, - /* P-HELD */ - {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL}, - {}, -}; - -static void plci_change_state(capidrv_contr *card, capidrv_plci *plci, int event) -{ - struct plcistatechange *p = plcitable; - while (p->event) { - if (plci->state == p->actstate && p->event == event) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n", - card->contrnr, plci->plci, plci->state, p->nextstate); - plci->state = p->nextstate; - if (p->changefunc) - p->changefunc(card, plci); - return; - } - p++; - } - printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n", - card->contrnr, plci->plci, plci->state, event); -} - -/* ------------------------------------------------------------------ */ - -static _cmsg cmsg; - -static void n0(capidrv_contr *card, capidrv_ncci *ncci) -{ - isdn_ctrl cmd; - - capi_fill_DISCONNECT_REQ(&cmsg, - global.ap.applid, - card->msgid++, - ncci->plcip->plci, - NULL, /* BChannelinformation */ - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ /* $$$$ */ - NULL /* Facilitydataarray */ - ); - plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); - send_message(card, &cmsg); - - cmd.command = ISDN_STAT_BHUP; - cmd.driver = card->myid; - cmd.arg = ncci->chan; - card->interface.statcallb(&cmd); - free_ncci(card, ncci); -} - -/* ------------------------------------------------------------------ */ - -struct nccistatechange { - int actstate; - int nextstate; - int event; - void (*changefunc)(capidrv_contr *card, capidrv_ncci *ncci); -}; - -static struct nccistatechange nccitable[] = -{ - /* N-0 */ - {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL}, - {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL}, - /* N-0.1 */ - {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL}, - {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, - /* N-1 */ - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-2 */ - {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-ACT */ - {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-3 */ - {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-4 */ - {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, NULL}, - /* N-5 */ - {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, - {}, -}; - -static void ncci_change_state(capidrv_contr *card, capidrv_ncci *ncci, int event) -{ - struct nccistatechange *p = nccitable; - while (p->event) { - if (ncci->state == p->actstate && p->event == event) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n", - card->contrnr, ncci->ncci, ncci->state, p->nextstate); - if (p->nextstate == ST_NCCI_PREVIOUS) { - ncci->state = ncci->oldstate; - ncci->oldstate = p->actstate; - } else { - ncci->oldstate = p->actstate; - ncci->state = p->nextstate; - } - if (p->changefunc) - p->changefunc(card, ncci); - return; - } - p++; - } - printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n", - card->contrnr, ncci->ncci, ncci->state, event); -} - -/* ------------------------------------------------------------------- */ - -static inline int new_bchan(capidrv_contr *card) -{ - int i; - for (i = 0; i < card->nbchan; i++) { - if (card->bchans[i].plcip == NULL) { - card->bchans[i].disconnecting = 0; - return i; - } - } - return -1; -} - -/* ------------------------------------------------------------------- */ -static char *capi_info2str(u16 reason) -{ -#ifndef CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE - return ".."; -#else - switch (reason) { - -/*-- informative values (corresponding message was processed) -----*/ - case 0x0001: - return "NCPI not supported by current protocol, NCPI ignored"; - case 0x0002: - return "Flags not supported by current protocol, flags ignored"; - case 0x0003: - return "Alert already sent by another application"; - -/*-- error information concerning CAPI_REGISTER -----*/ - case 0x1001: - return "Too many applications"; - case 0x1002: - return "Logical block size too small, must be at least 128 Bytes"; - case 0x1003: - return "Buffer exceeds 64 kByte"; - case 0x1004: - return "Message buffer size too small, must be at least 1024 Bytes"; - case 0x1005: - return "Max. number of logical connections not supported"; - case 0x1006: - return "Reserved"; - case 0x1007: - return "The message could not be accepted because of an internal busy condition"; - case 0x1008: - return "OS resource error (no memory ?)"; - case 0x1009: - return "CAPI not installed"; - case 0x100A: - return "Controller does not support external equipment"; - case 0x100B: - return "Controller does only support external equipment"; - -/*-- error information concerning message exchange functions -----*/ - case 0x1101: - return "Illegal application number"; - case 0x1102: - return "Illegal command or subcommand or message length less than 12 bytes"; - case 0x1103: - return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; - case 0x1104: - return "Queue is empty"; - case 0x1105: - return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; - case 0x1106: - return "Unknown notification parameter"; - case 0x1107: - return "The Message could not be accepted because of an internal busy condition"; - case 0x1108: - return "OS Resource error (no memory ?)"; - case 0x1109: - return "CAPI not installed"; - case 0x110A: - return "Controller does not support external equipment"; - case 0x110B: - return "Controller does only support external equipment"; - -/*-- error information concerning resource / coding problems -----*/ - case 0x2001: - return "Message not supported in current state"; - case 0x2002: - return "Illegal Controller / PLCI / NCCI"; - case 0x2003: - return "Out of PLCI"; - case 0x2004: - return "Out of NCCI"; - case 0x2005: - return "Out of LISTEN"; - case 0x2006: - return "Out of FAX resources (protocol T.30)"; - case 0x2007: - return "Illegal message parameter coding"; - -/*-- error information concerning requested services -----*/ - case 0x3001: - return "B1 protocol not supported"; - case 0x3002: - return "B2 protocol not supported"; - case 0x3003: - return "B3 protocol not supported"; - case 0x3004: - return "B1 protocol parameter not supported"; - case 0x3005: - return "B2 protocol parameter not supported"; - case 0x3006: - return "B3 protocol parameter not supported"; - case 0x3007: - return "B protocol combination not supported"; - case 0x3008: - return "NCPI not supported"; - case 0x3009: - return "CIP Value unknown"; - case 0x300A: - return "Flags not supported (reserved bits)"; - case 0x300B: - return "Facility not supported"; - case 0x300C: - return "Data length not supported by current protocol"; - case 0x300D: - return "Reset procedure not supported by current protocol"; - -/*-- informations about the clearing of a physical connection -----*/ - case 0x3301: - return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; - case 0x3302: - return "Protocol error layer 2"; - case 0x3303: - return "Protocol error layer 3"; - case 0x3304: - return "Another application got that call"; -/*-- T.30 specific reasons -----*/ - case 0x3311: - return "Connecting not successful (remote station is no FAX G3 machine)"; - case 0x3312: - return "Connecting not successful (training error)"; - case 0x3313: - return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; - case 0x3314: - return "Disconnected during transfer (remote abort)"; - case 0x3315: - return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; - case 0x3316: - return "Disconnected during transfer (local tx data underrun)"; - case 0x3317: - return "Disconnected during transfer (local rx data overflow)"; - case 0x3318: - return "Disconnected during transfer (local abort)"; - case 0x3319: - return "Illegal parameter coding (e.g. SFF coding error)"; - -/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/ - case 0x3481: return "Unallocated (unassigned) number"; - case 0x3482: return "No route to specified transit network"; - case 0x3483: return "No route to destination"; - case 0x3486: return "Channel unacceptable"; - case 0x3487: - return "Call awarded and being delivered in an established channel"; - case 0x3490: return "Normal call clearing"; - case 0x3491: return "User busy"; - case 0x3492: return "No user responding"; - case 0x3493: return "No answer from user (user alerted)"; - case 0x3495: return "Call rejected"; - case 0x3496: return "Number changed"; - case 0x349A: return "Non-selected user clearing"; - case 0x349B: return "Destination out of order"; - case 0x349C: return "Invalid number format"; - case 0x349D: return "Facility rejected"; - case 0x349E: return "Response to STATUS ENQUIRY"; - case 0x349F: return "Normal, unspecified"; - case 0x34A2: return "No circuit / channel available"; - case 0x34A6: return "Network out of order"; - case 0x34A9: return "Temporary failure"; - case 0x34AA: return "Switching equipment congestion"; - case 0x34AB: return "Access information discarded"; - case 0x34AC: return "Requested circuit / channel not available"; - case 0x34AF: return "Resources unavailable, unspecified"; - case 0x34B1: return "Quality of service unavailable"; - case 0x34B2: return "Requested facility not subscribed"; - case 0x34B9: return "Bearer capability not authorized"; - case 0x34BA: return "Bearer capability not presently available"; - case 0x34BF: return "Service or option not available, unspecified"; - case 0x34C1: return "Bearer capability not implemented"; - case 0x34C2: return "Channel type not implemented"; - case 0x34C5: return "Requested facility not implemented"; - case 0x34C6: return "Only restricted digital information bearer capability is available"; - case 0x34CF: return "Service or option not implemented, unspecified"; - case 0x34D1: return "Invalid call reference value"; - case 0x34D2: return "Identified channel does not exist"; - case 0x34D3: return "A suspended call exists, but this call identity does not"; - case 0x34D4: return "Call identity in use"; - case 0x34D5: return "No call suspended"; - case 0x34D6: return "Call having the requested call identity has been cleared"; - case 0x34D8: return "Incompatible destination"; - case 0x34DB: return "Invalid transit network selection"; - case 0x34DF: return "Invalid message, unspecified"; - case 0x34E0: return "Mandatory information element is missing"; - case 0x34E1: return "Message type non-existent or not implemented"; - case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented"; - case 0x34E3: return "Information element non-existent or not implemented"; - case 0x34E4: return "Invalid information element contents"; - case 0x34E5: return "Message not compatible with call state"; - case 0x34E6: return "Recovery on timer expiry"; - case 0x34EF: return "Protocol error, unspecified"; - case 0x34FF: return "Interworking, unspecified"; - - default: return "No additional information"; - } -#endif -} - -static void handle_controller(_cmsg *cmsg) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - return; - } - switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { - - case CAPI_LISTEN_CONF: /* Controller */ - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n", - card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); - if (cmsg->Info) { - listen_change_state(card, EV_LISTEN_CONF_ERROR); - } else if (card->cipmask == 0) { - listen_change_state(card, EV_LISTEN_CONF_EMPTY); - } else { - listen_change_state(card, EV_LISTEN_CONF_OK); - } - break; - - case CAPI_MANUFACTURER_IND: /* Controller */ - if (cmsg->ManuID == 0x214D5641 - && cmsg->Class == 0 - && cmsg->Function == 1) { - u8 *data = cmsg->ManuData + 3; - u16 len = cmsg->ManuData[0]; - u16 layer; - int direction; - if (len == 255) { - len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8)); - data += 2; - } - len -= 2; - layer = ((*(data - 1)) << 8) | *(data - 2); - if (layer & 0x300) - direction = (layer & 0x200) ? 0 : 1; - else direction = (layer & 0x800) ? 0 : 1; - if (layer & 0x0C00) { - if ((layer & 0xff) == 0x80) { - handle_dtrace_data(card, direction, 1, data, len); - break; - } - } else if ((layer & 0xff) < 0x80) { - handle_dtrace_data(card, direction, 0, data, len); - break; - } - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController, layer); - break; - } - goto ignored; - case CAPI_MANUFACTURER_CONF: /* Controller */ - if (cmsg->ManuID == 0x214D5641) { - char *s = NULL; - switch (cmsg->Class) { - case 0: break; - case 1: s = "unknown class"; break; - case 2: s = "unknown function"; break; - default: s = "unknown error"; break; - } - if (s) - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController, - cmsg->Function, s); - break; - } - goto ignored; - case CAPI_FACILITY_IND: /* Controller/plci/ncci */ - goto ignored; - case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ - goto ignored; - case CAPI_INFO_IND: /* Controller/plci */ - goto ignored; - case CAPI_INFO_CONF: /* Controller/plci */ - goto ignored; - - default: - printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController); - } - return; - -ignored: - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController); -} - -static void handle_incoming_call(capidrv_contr *card, _cmsg *cmsg) -{ - capidrv_plci *plcip; - capidrv_bchan *bchan; - isdn_ctrl cmd; - int chan; - - if ((chan = new_bchan(card)) == -1) { - printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr); - return; - } - bchan = &card->bchans[chan]; - if ((plcip = new_plci(card, chan)) == NULL) { - printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr); - return; - } - bchan->incoming = 1; - plcip->plci = cmsg->adr.adrPLCI; - plci_change_state(card, plcip, EV_PLCI_CONNECT_IND); - - cmd.command = ISDN_STAT_ICALL; - cmd.driver = card->myid; - cmd.arg = chan; - memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup)); - strncpy(cmd.parm.setup.phone, - cmsg->CallingPartyNumber + 3, - cmsg->CallingPartyNumber[0] - 2); - strncpy(cmd.parm.setup.eazmsn, - cmsg->CalledPartyNumber + 2, - cmsg->CalledPartyNumber[0] - 1); - cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue); - cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue); - cmd.parm.setup.plan = cmsg->CallingPartyNumber[1]; - cmd.parm.setup.screen = cmsg->CallingPartyNumber[2]; - - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - - if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) { - printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n", - card->contrnr, - cmd.parm.setup.si2); - cmd.parm.setup.si2 = 0; - } - - switch (card->interface.statcallb(&cmd)) { - case 0: - case 3: - /* No device matching this call. - * and isdn_common.c has send a HANGUP command - * which is ignored in state ST_PLCI_INCOMING, - * so we send RESP to ignore the call - */ - capi_cmsg_answer(cmsg); - cmsg->Reject = 1; /* ignore */ - plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - send_message(card, cmsg); - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - break; - case 1: - /* At least one device matching this call (RING on ttyI) - * HL-driver may send ALERTING on the D-channel in this - * case. - * really means: RING on ttyI or a net interface - * accepted this call already. - * - * If the call was accepted, state has already changed, - * and CONNECT_RESP already sent. - */ - if (plcip->state == ST_PLCI_INCOMING) { - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - capi_fill_ALERT_REQ(cmsg, - global.ap.applid, - card->msgid++, - plcip->plci, /* adr */ - NULL,/* BChannelinformation */ - NULL,/* Keypadfacility */ - NULL,/* Useruserdata */ - NULL /* Facilitydataarray */ - ); - plcip->msgid = cmsg->Messagenumber; - send_message(card, cmsg); - } else { - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - } - break; - - case 2: /* Call will be rejected. */ - capi_cmsg_answer(cmsg); - cmsg->Reject = 2; /* reject call, normal call clearing */ - plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - send_message(card, cmsg); - break; - - default: - /* An error happened. (Invalid parameters for example.) */ - capi_cmsg_answer(cmsg); - cmsg->Reject = 8; /* reject call, - destination out of order */ - plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - send_message(card, cmsg); - break; - } - return; -} - -static void handle_plci(_cmsg *cmsg) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - capidrv_plci *plcip; - isdn_ctrl cmd; - _cdebbuf *cdb; - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - return; - } - switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { - - case CAPI_DISCONNECT_IND: /* plci */ - if (cmsg->Reason) { - printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); - } - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) { - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - goto notfound; - } - card->bchans[plcip->chan].disconnecting = 1; - plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND); - capi_cmsg_answer(cmsg); - plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP); - send_message(card, cmsg); - break; - - case CAPI_DISCONNECT_CONF: /* plci */ - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrPLCI); - } - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) - goto notfound; - - card->bchans[plcip->chan].disconnecting = 1; - break; - - case CAPI_ALERT_CONF: /* plci */ - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrPLCI); - } - break; - - case CAPI_CONNECT_IND: /* plci */ - handle_incoming_call(card, cmsg); - break; - - case CAPI_CONNECT_CONF: /* plci */ - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrPLCI); - } - if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber))) - goto notfound; - - plcip->plci = cmsg->adr.adrPLCI; - if (cmsg->Info) { - plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR); - } else { - plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK); - } - break; - - case CAPI_CONNECT_ACTIVE_IND: /* plci */ - - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) - goto notfound; - - if (card->bchans[plcip->chan].incoming) { - capi_cmsg_answer(cmsg); - plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); - send_message(card, cmsg); - } else { - capidrv_ncci *nccip; - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - - nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI); - - if (!nccip) { - printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); - break; /* $$$$ */ - } - capi_fill_CONNECT_B3_REQ(cmsg, - global.ap.applid, - card->msgid++, - plcip->plci, /* adr */ - NULL /* NCPI */ - ); - nccip->msgid = cmsg->Messagenumber; - plci_change_state(card, plcip, - EV_PLCI_CONNECT_ACTIVE_IND); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); - send_message(card, cmsg); - cmd.command = ISDN_STAT_DCONN; - cmd.driver = card->myid; - cmd.arg = plcip->chan; - card->interface.statcallb(&cmd); - } - break; - - case CAPI_INFO_IND: /* Controller/plci */ - - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) - goto notfound; - - if (cmsg->InfoNumber == 0x4000) { - if (cmsg->InfoElement[0] == 4) { - cmd.command = ISDN_STAT_CINF; - cmd.driver = card->myid; - cmd.arg = plcip->chan; - sprintf(cmd.parm.num, "%lu", - (unsigned long) - ((u32) cmsg->InfoElement[1] - | ((u32) (cmsg->InfoElement[2]) << 8) - | ((u32) (cmsg->InfoElement[3]) << 16) - | ((u32) (cmsg->InfoElement[4]) << 24))); - card->interface.statcallb(&cmd); - break; - } - } - cdb = capi_cmsg2str(cmsg); - if (cdb) { - printk(KERN_WARNING "capidrv-%d: %s\n", - card->contrnr, cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n", - card->contrnr, cmsg->InfoNumber); - - break; - - case CAPI_CONNECT_ACTIVE_CONF: /* plci */ - goto ignored; - case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */ - goto ignored; - case CAPI_FACILITY_IND: /* Controller/plci/ncci */ - goto ignored; - case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ - goto ignored; - - case CAPI_INFO_CONF: /* Controller/plci */ - goto ignored; - - default: - printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrPLCI); - } - return; -ignored: - printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrPLCI); - return; -notfound: - printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrPLCI); - return; -} - -static void handle_ncci(_cmsg *cmsg) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - capidrv_plci *plcip; - capidrv_ncci *nccip; - isdn_ctrl cmd; - int len; - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - return; - } - switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { - - case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - - capi_cmsg_answer(cmsg); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND); - send_message(card, cmsg); - - cmd.command = ISDN_STAT_BCONN; - cmd.driver = card->myid; - cmd.arg = nccip->chan; - card->interface.statcallb(&cmd); - - printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n", - card->contrnr, nccip->chan, nccip->ncci); - break; - - case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */ - goto ignored; - - case CAPI_CONNECT_B3_IND: /* ncci */ - - plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI); - if (plcip) { - nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI); - if (nccip) { - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND); - capi_fill_CONNECT_B3_RESP(cmsg, - global.ap.applid, - card->msgid++, - nccip->ncci, /* adr */ - 0, /* Reject */ - NULL /* NCPI */ - ); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); - send_message(card, cmsg); - break; - } - printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); - } else { - printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - } - capi_fill_CONNECT_B3_RESP(cmsg, - global.ap.applid, - card->msgid++, - cmsg->adr.adrNCCI, - 2, /* Reject */ - NULL /* NCPI */ - ); - send_message(card, cmsg); - break; - - case CAPI_CONNECT_B3_CONF: /* ncci */ - - if (!(nccip = find_ncci_by_msgid(card, - cmsg->adr.adrNCCI, - cmsg->Messagenumber))) - goto notfound; - - nccip->ncci = cmsg->adr.adrNCCI; - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrNCCI); - } - - if (cmsg->Info) - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR); - else - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK); - break; - - case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */ - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - break; - - case CAPI_DATA_B3_IND: /* ncci */ - /* handled in handle_data() */ - goto ignored; - - case CAPI_DATA_B3_CONF: /* ncci */ - if (cmsg->Info) { - printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n", - cmsg->Info, capi_info2str(cmsg->Info)); - } - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - - len = capidrv_del_ack(nccip, cmsg->DataHandle); - if (len < 0) - break; - cmd.command = ISDN_STAT_BSENT; - cmd.driver = card->myid; - cmd.arg = nccip->chan; - cmd.parm.length = len; - card->interface.statcallb(&cmd); - break; - - case CAPI_DISCONNECT_B3_IND: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - - card->bchans[nccip->chan].disconnecting = 1; - ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND); - capi_cmsg_answer(cmsg); - ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP); - send_message(card, cmsg); - break; - - case CAPI_DISCONNECT_B3_CONF: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrNCCI); - ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR); - } - break; - - case CAPI_RESET_B3_IND: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND); - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - break; - - case CAPI_RESET_B3_CONF: /* ncci */ - goto ignored; /* $$$$ */ - - case CAPI_FACILITY_IND: /* Controller/plci/ncci */ - goto ignored; - case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ - goto ignored; - - default: - printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - } - return; -ignored: - printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - return; -notfound: - printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); -} - - -static void handle_data(_cmsg *cmsg, struct sk_buff *skb) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - capidrv_ncci *nccip; - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - kfree_skb(skb); - return; - } - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) { - printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - kfree_skb(skb); - return; - } - (void) skb_pull(skb, CAPIMSG_LEN(skb->data)); - card->interface.rcvcallb_skb(card->myid, nccip->chan, skb); - capi_cmsg_answer(cmsg); - send_message(card, cmsg); -} - -static _cmsg s_cmsg; - -static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) -{ - if (capi_message2cmsg(&s_cmsg, skb->data)) { - printk(KERN_ERR "capidrv: applid=%d: received invalid message\n", - ap->applid); - kfree_skb(skb); - return; - } - if (debugmode > 3) { - _cdebbuf *cdb = capi_cmsg2str(&s_cmsg); - - if (cdb) { - printk(KERN_DEBUG "%s: applid=%d %s\n", __func__, - ap->applid, cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_DEBUG "%s: applid=%d %s not traced\n", - __func__, ap->applid, - capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); - } - if (s_cmsg.Command == CAPI_DATA_B3 - && s_cmsg.Subcommand == CAPI_IND) { - handle_data(&s_cmsg, skb); - return; - } - if ((s_cmsg.adr.adrController & 0xffffff00) == 0) - handle_controller(&s_cmsg); - else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) - handle_plci(&s_cmsg); - else - handle_ncci(&s_cmsg); - /* - * data of skb used in s_cmsg, - * free data when s_cmsg is not used again - * thanks to Lars Heete - */ - kfree_skb(skb); -} - -/* ------------------------------------------------------------------- */ - -#define PUTBYTE_TO_STATUS(card, byte) \ - do { \ - *(card)->q931_write++ = (byte); \ - if ((card)->q931_write > (card)->q931_end) \ - (card)->q931_write = (card)->q931_buf; \ - } while (0) - -static void handle_dtrace_data(capidrv_contr *card, - int send, int level2, u8 *data, u16 len) -{ - u8 *p, *end; - isdn_ctrl cmd; - - if (!len) { - printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", - card->contrnr, len); - return; - } - - if (level2) { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '2'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } else { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '3'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } - - for (p = data, end = data + len; p < end; p++) { - PUTBYTE_TO_STATUS(card, ' '); - PUTBYTE_TO_STATUS(card, hex_asc_hi(*p)); - PUTBYTE_TO_STATUS(card, hex_asc_lo(*p)); - } - PUTBYTE_TO_STATUS(card, '\n'); - - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = len * 3 + 5; - card->interface.statcallb(&cmd); -} - -/* ------------------------------------------------------------------- */ - -static _cmsg cmdcmsg; - -static int capidrv_ioctl(isdn_ctrl *c, capidrv_contr *card) -{ - switch (c->arg) { - case 1: - debugmode = (int)(*((unsigned int *)c->parm.num)); - printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n", - card->contrnr, debugmode); - return 0; - default: - printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n", - card->contrnr, c->arg); - return -EINVAL; - } - return -EINVAL; -} - -/* - * Handle leased lines (CAPI-Bundling) - */ - -struct internal_bchannelinfo { - unsigned short channelalloc; - unsigned short operation; - unsigned char cmask[31]; -}; - -static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) -{ - unsigned long bmask = 0; - int active = !0; - char *s; - int i; - - if (strncmp(teln, "FV:", 3) != 0) - return 1; - s = teln + 3; - while (*s && *s == ' ') s++; - if (!*s) return -2; - if (*s == 'p' || *s == 'P') { - active = 0; - s++; - } - if (*s == 'a' || *s == 'A') { - active = !0; - s++; - } - while (*s) { - int digit1 = 0; - int digit2 = 0; - char *endp; - - digit1 = simple_strtoul(s, &endp, 10); - if (s == endp) - return -3; - s = endp; - - if (digit1 <= 0 || digit1 > 30) return -4; - if (*s == 0 || *s == ',' || *s == ' ') { - bmask |= (1 << digit1); - digit1 = 0; - if (*s) s++; - continue; - } - if (*s != '-') return -5; - s++; - - digit2 = simple_strtoul(s, &endp, 10); - if (s == endp) - return -3; - s = endp; - - if (digit2 <= 0 || digit2 > 30) return -4; - if (*s == 0 || *s == ',' || *s == ' ') { - if (digit1 > digit2) - for (i = digit2; i <= digit1; i++) - bmask |= (1 << i); - else - for (i = digit1; i <= digit2; i++) - bmask |= (1 << i); - digit1 = digit2 = 0; - if (*s) s++; - continue; - } - return -6; - } - if (activep) *activep = active; - if (bmaskp) *bmaskp = bmask; - return 0; -} - -static int FVteln2capi20(char *teln, u8 AdditionalInfo[1 + 2 + 2 + 31]) -{ - unsigned long bmask; - int active; - int rc, i; - - rc = decodeFVteln(teln, &bmask, &active); - if (rc) return rc; - /* Length */ - AdditionalInfo[0] = 2 + 2 + 31; - /* Channel: 3 => use channel allocation */ - AdditionalInfo[1] = 3; AdditionalInfo[2] = 0; - /* Operation: 0 => DTE mode, 1 => DCE mode */ - if (active) { - AdditionalInfo[3] = 0; AdditionalInfo[4] = 0; - } else { - AdditionalInfo[3] = 1; AdditionalInfo[4] = 0; - } - /* Channel mask array */ - AdditionalInfo[5] = 0; /* no D-Channel */ - for (i = 1; i <= 30; i++) - AdditionalInfo[5 + i] = (bmask & (1 << i)) ? 0xff : 0; - return 0; -} - -static int capidrv_command(isdn_ctrl *c, capidrv_contr *card) -{ - isdn_ctrl cmd; - struct capidrv_bchan *bchan; - struct capidrv_plci *plcip; - u8 AdditionalInfo[1 + 2 + 2 + 31]; - int rc, isleasedline = 0; - - if (c->command == ISDN_CMD_IOCTL) - return capidrv_ioctl(c, card); - - switch (c->command) { - case ISDN_CMD_DIAL: { - u8 calling[ISDN_MSNLEN + 3]; - u8 called[ISDN_MSNLEN + 2]; - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", - card->contrnr, - c->arg, - c->parm.setup.phone, - c->parm.setup.si1, - c->parm.setup.si2, - c->parm.setup.eazmsn); - - bchan = &card->bchans[c->arg % card->nbchan]; - - if (bchan->plcip) { - printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", - card->contrnr, - c->arg, - c->parm.setup.phone, - c->parm.setup.si1, - c->parm.setup.si2, - c->parm.setup.eazmsn, - bchan->plcip->plci); - return 0; - } - bchan->si1 = c->parm.setup.si1; - bchan->si2 = c->parm.setup.si2; - - strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); - strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); - rc = FVteln2capi20(bchan->num, AdditionalInfo); - isleasedline = (rc == 0); - if (rc < 0) - printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num); - - if (isleasedline) { - calling[0] = 0; - called[0] = 0; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr); - } else { - calling[0] = strlen(bchan->mynum) + 2; - calling[1] = 0; - calling[2] = 0x80; - strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); - called[0] = strlen(bchan->num) + 1; - called[1] = 0x80; - strncpy(called + 2, bchan->num, ISDN_MSNLEN); - } - - capi_fill_CONNECT_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - card->contrnr, /* adr */ - si2cip(bchan->si1, bchan->si2), /* cipvalue */ - called, /* CalledPartyNumber */ - calling, /* CallingPartyNumber */ - NULL, /* CalledPartySubaddress */ - NULL, /* CallingPartySubaddress */ - b1prot(bchan->l2, bchan->l3), /* B1protocol */ - b2prot(bchan->l2, bchan->l3), /* B2protocol */ - b3prot(bchan->l2, bchan->l3), /* B3protocol */ - b1config(bchan->l2, bchan->l3), /* B1configuration */ - NULL, /* B2configuration */ - NULL, /* B3configuration */ - NULL, /* BC */ - NULL, /* LLC */ - NULL, /* HLC */ - /* BChannelinformation */ - isleasedline ? AdditionalInfo : NULL, - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) { - cmd.command = ISDN_STAT_DHUP; - cmd.driver = card->myid; - cmd.arg = (c->arg % card->nbchan); - card->interface.statcallb(&cmd); - return -1; - } - plcip->msgid = cmdcmsg.Messagenumber; - plcip->leasedline = isleasedline; - plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); - send_message(card, &cmdcmsg); - return 0; - } - - case ISDN_CMD_ACCEPTD: - - bchan = &card->bchans[c->arg % card->nbchan]; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n", - card->contrnr, - c->arg, bchan->l2, bchan->l3); - - capi_fill_CONNECT_RESP(&cmdcmsg, - global.ap.applid, - card->msgid++, - bchan->plcip->plci, /* adr */ - 0, /* Reject */ - b1prot(bchan->l2, bchan->l3), /* B1protocol */ - b2prot(bchan->l2, bchan->l3), /* B2protocol */ - b3prot(bchan->l2, bchan->l3), /* B3protocol */ - b1config(bchan->l2, bchan->l3), /* B1configuration */ - NULL, /* B2configuration */ - NULL, /* B3configuration */ - NULL, /* ConnectedNumber */ - NULL, /* ConnectedSubaddress */ - NULL, /* LLC */ - NULL, /* BChannelinformation */ - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - if (capi_cmsg2message(&cmdcmsg, cmdcmsg.buf)) { - printk(KERN_ERR "capidrv-%d: capidrv_command: parser failure\n", - card->contrnr); - return -EINVAL; - } - plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); - send_message(card, &cmdcmsg); - return 0; - - case ISDN_CMD_ACCEPTB: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n", - card->contrnr, - c->arg); - return -ENOSYS; - - case ISDN_CMD_HANGUP: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n", - card->contrnr, - c->arg); - bchan = &card->bchans[c->arg % card->nbchan]; - - if (bchan->disconnecting) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n", - card->contrnr, - c->arg); - return 0; - } - if (bchan->nccip) { - bchan->disconnecting = 1; - capi_fill_DISCONNECT_B3_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - bchan->nccip->ncci, - NULL /* NCPI */ - ); - ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); - send_message(card, &cmdcmsg); - return 0; - } else if (bchan->plcip) { - if (bchan->plcip->state == ST_PLCI_INCOMING) { - /* - * just ignore, we a called from - * isdn_status_callback(), - * which will return 0 or 2, this is handled - * by the CONNECT_IND handler - */ - bchan->disconnecting = 1; - return 0; - } else if (bchan->plcip->plci) { - bchan->disconnecting = 1; - capi_fill_DISCONNECT_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - bchan->plcip->plci, - NULL, /* BChannelinformation */ - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); - send_message(card, &cmdcmsg); - return 0; - } else { - printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n", - card->contrnr, - c->arg); - return -EINVAL; - } - } - printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n", - card->contrnr, - c->arg); - return -EINVAL; -/* ready */ - - case ISDN_CMD_SETL2: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n", - card->contrnr, - (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; - bchan->l2 = (c->arg >> 8); - return 0; - - case ISDN_CMD_SETL3: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n", - card->contrnr, - (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; - bchan->l3 = (c->arg >> 8); - return 0; - - case ISDN_CMD_SETEAZ: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n", - card->contrnr, - c->parm.num, c->arg); - bchan = &card->bchans[c->arg % card->nbchan]; - strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); - return 0; - - case ISDN_CMD_CLREAZ: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", - card->contrnr, c->arg); - bchan = &card->bchans[c->arg % card->nbchan]; - bchan->msn[0] = 0; - return 0; - - default: - printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", - card->contrnr, c->command); - return -EINVAL; - } - return 0; -} - -static int if_command(isdn_ctrl *c) -{ - capidrv_contr *card = findcontrbydriverid(c->driver); - - if (card) - return capidrv_command(c, card); - - printk(KERN_ERR - "capidrv: if_command %d called with invalid driverId %d!\n", - c->command, c->driver); - return -ENODEV; -} - -static _cmsg sendcmsg; - -static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) -{ - capidrv_contr *card = findcontrbydriverid(id); - capidrv_bchan *bchan; - capidrv_ncci *nccip; - int len = skb->len; - int msglen; - u16 errcode; - u16 datahandle; - u32 data; - - if (!card) { - printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", - id); - return 0; - } - if (debugmode > 4) - printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n", - card->contrnr, len, skb, doack); - bchan = &card->bchans[channel % card->nbchan]; - nccip = bchan->nccip; - if (!nccip || nccip->state != ST_NCCI_ACTIVE) { - printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n", - card->contrnr, card->name, channel); - return 0; - } - datahandle = nccip->datahandle; - - /* - * Here we copy pointer skb->data into the 32-bit 'Data' field. - * The 'Data' field is not used in practice in linux kernel - * (neither in 32 or 64 bit), but should have some value, - * since a CAPI message trace will display it. - * - * The correct value in the 32 bit case is the address of the - * data, in 64 bit it makes no sense, we use 0 there. - */ - -#ifdef CONFIG_64BIT - data = 0; -#else - data = (unsigned long) skb->data; -#endif - - capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++, - nccip->ncci, /* adr */ - data, /* Data */ - skb->len, /* DataLength */ - datahandle, /* DataHandle */ - 0 /* Flags */ - ); - - if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0) - return 0; - - if (capi_cmsg2message(&sendcmsg, sendcmsg.buf)) { - printk(KERN_ERR "capidrv-%d: if_sendbuf: parser failure\n", - card->contrnr); - return -EINVAL; - } - msglen = CAPIMSG_LEN(sendcmsg.buf); - if (skb_headroom(skb) < msglen) { - struct sk_buff *nskb = skb_realloc_headroom(skb, msglen); - if (!nskb) { - printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", - card->contrnr); - (void)capidrv_del_ack(nccip, datahandle); - return 0; - } - printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n", - card->contrnr, skb_headroom(skb), msglen); - memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen); - errcode = capi20_put_message(&global.ap, nskb); - if (errcode == CAPI_NOERROR) { - dev_kfree_skb(skb); - nccip->datahandle++; - return len; - } - if (debugmode > 3) - printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", - card->contrnr, errcode, capi_info2str(errcode)); - (void)capidrv_del_ack(nccip, datahandle); - dev_kfree_skb(nskb); - return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; - } else { - memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen); - errcode = capi20_put_message(&global.ap, skb); - if (errcode == CAPI_NOERROR) { - nccip->datahandle++; - return len; - } - if (debugmode > 3) - printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", - card->contrnr, errcode, capi_info2str(errcode)); - skb_pull(skb, msglen); - (void)capidrv_del_ack(nccip, datahandle); - return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; - } -} - -static int if_readstat(u8 __user *buf, int len, int id, int channel) -{ - capidrv_contr *card = findcontrbydriverid(id); - int count; - u8 __user *p; - - if (!card) { - printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", - id); - return -ENODEV; - } - - for (p = buf, count = 0; count < len; p++, count++) { - if (put_user(*card->q931_read++, p)) - return -EFAULT; - if (card->q931_read > card->q931_end) - card->q931_read = card->q931_buf; - } - return count; - -} - -static void enable_dchannel_trace(capidrv_contr *card) -{ - u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - u16 contr = card->contrnr; - u16 errcode; - u16 avmversion[3]; - - errcode = capi20_get_manufacturer(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; - } - if (strstr(manufacturer, "AVM") == NULL) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; - } - errcode = capi20_get_version(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; - } - avmversion[0] = (version.majormanuversion >> 4) & 0x0f; - avmversion[1] = (version.majormanuversion << 4) & 0xf0; - avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; - avmversion[2] |= version.minormanuversion & 0x0f; - - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { - printk(KERN_INFO "%s: D2 trace enabled\n", card->name); - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\200\014\000\000"); - } else { - printk(KERN_INFO "%s: D3 trace enabled\n", card->name); - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\002\003\000\000"); - } - send_message(card, &cmdcmsg); -} - - -static void send_listen(capidrv_contr *card) -{ - capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid, - card->msgid++, - card->contrnr, /* controller */ - 1 << 6, /* Infomask */ - card->cipmask, - card->cipmask2, - NULL, NULL); - listen_change_state(card, EV_LISTEN_REQ); - send_message(card, &cmdcmsg); -} - -static void listentimerfunc(struct timer_list *t) -{ - capidrv_contr *card = from_timer(card, t, listentimer); - if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) - printk(KERN_ERR "%s: controller dead ??\n", card->name); - send_listen(card); - mod_timer(&card->listentimer, jiffies + 60 * HZ); -} - - -static int capidrv_addcontr(u16 contr, struct capi_profile *profp) -{ - capidrv_contr *card; - unsigned long flags; - isdn_ctrl cmd; - char id[20]; - int i; - - sprintf(id, "capidrv-%d", contr); - if (!try_module_get(THIS_MODULE)) { - printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id); - return -1; - } - if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { - printk(KERN_WARNING - "capidrv: (%s) Could not allocate contr-struct.\n", id); - return -1; - } - card->owner = THIS_MODULE; - timer_setup(&card->listentimer, listentimerfunc, 0); - strcpy(card->name, id); - card->contrnr = contr; - card->nbchan = profp->nbchannel; - card->bchans = kmalloc_array(card->nbchan, sizeof(capidrv_bchan), - GFP_ATOMIC); - if (!card->bchans) { - printk(KERN_WARNING - "capidrv: (%s) Could not allocate bchan-structs.\n", id); - module_put(card->owner); - kfree(card); - return -1; - } - card->interface.channels = profp->nbchannel; - card->interface.maxbufsize = 2048; - card->interface.command = if_command; - card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = NULL; - card->interface.readstat = if_readstat; - card->interface.features = - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN | - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_X75UI | - ISDN_FEATURE_L2_X75BUI; - if (profp->support1 & (1 << 2)) - card->interface.features |= - ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | - ISDN_FEATURE_L2_V11038; - if (profp->support1 & (1 << 8)) - card->interface.features |= ISDN_FEATURE_L2_MODEM; - card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ - strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); - - - card->q931_read = card->q931_buf; - card->q931_write = card->q931_buf; - card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1; - - if (!register_isdn(&card->interface)) { - printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); - kfree(card->bchans); - module_put(card->owner); - kfree(card); - return -1; - } - card->myid = card->interface.channels; - memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); - for (i = 0; i < card->nbchan; i++) { - card->bchans[i].contr = card; - } - - spin_lock_irqsave(&global_lock, flags); - card->next = global.contr_list; - global.contr_list = card; - global.ncontr++; - spin_unlock_irqrestore(&global_lock, flags); - - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - - card->cipmask = 0x1FFF03FF; /* any */ - card->cipmask2 = 0; - - send_listen(card); - mod_timer(&card->listentimer, jiffies + 60 * HZ); - - printk(KERN_INFO "%s: now up (%d B channels)\n", - card->name, card->nbchan); - - enable_dchannel_trace(card); - - return 0; -} - -static int capidrv_delcontr(u16 contr) -{ - capidrv_contr **pp, *card; - unsigned long flags; - isdn_ctrl cmd; - - spin_lock_irqsave(&global_lock, flags); - for (card = global.contr_list; card; card = card->next) { - if (card->contrnr == contr) - break; - } - if (!card) { - spin_unlock_irqrestore(&global_lock, flags); - printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); - return -1; - } - - /* FIXME: maybe a race condition the card should be removed - * here from global list /kkeil - */ - spin_unlock_irqrestore(&global_lock, flags); - - del_timer(&card->listentimer); - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", - card->contrnr, card->myid); - - cmd.command = ISDN_STAT_STOP; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - - while (card->nbchan) { - - cmd.command = ISDN_STAT_DISCH; - cmd.driver = card->myid; - cmd.arg = card->nbchan - 1; - cmd.parm.num[0] = 0; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n", - card->contrnr, card->myid, cmd.arg); - card->interface.statcallb(&cmd); - - if (card->bchans[card->nbchan - 1].nccip) - free_ncci(card, card->bchans[card->nbchan - 1].nccip); - if (card->bchans[card->nbchan - 1].plcip) - free_plci(card, card->bchans[card->nbchan - 1].plcip); - if (card->plci_list) - printk(KERN_ERR "capidrv: bug in free_plci()\n"); - card->nbchan--; - } - kfree(card->bchans); - card->bchans = NULL; - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", - card->contrnr, card->myid); - - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n", - card->contrnr, card->myid); - - spin_lock_irqsave(&global_lock, flags); - for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { - if (*pp == card) { - *pp = (*pp)->next; - card->next = NULL; - global.ncontr--; - break; - } - } - spin_unlock_irqrestore(&global_lock, flags); - - module_put(card->owner); - printk(KERN_INFO "%s: now down.\n", card->name); - kfree(card); - return 0; -} - - -static int -lower_callback(struct notifier_block *nb, unsigned long val, void *v) -{ - capi_profile profile; - u32 contr = (long)v; - - switch (val) { - case CAPICTR_UP: - printk(KERN_INFO "capidrv: controller %hu up\n", contr); - if (capi20_get_profile(contr, &profile) == CAPI_NOERROR) - (void) capidrv_addcontr(contr, &profile); - break; - case CAPICTR_DOWN: - printk(KERN_INFO "capidrv: controller %hu down\n", contr); - (void) capidrv_delcontr(contr); - break; - } - return NOTIFY_OK; -} - -/* - * /proc/capi/capidrv: - * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt - */ -static int __maybe_unused capidrv_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%lu %lu %lu %lu\n", - global.ap.nrecvctlpkt, - global.ap.nrecvdatapkt, - global.ap.nsentctlpkt, - global.ap.nsentdatapkt); - return 0; -} - -static void __init proc_init(void) -{ - proc_create_single("capi/capidrv", 0, NULL, capidrv_proc_show); -} - -static void __exit proc_exit(void) -{ - remove_proc_entry("capi/capidrv", NULL); -} - -static struct notifier_block capictr_nb = { - .notifier_call = lower_callback, -}; - -static int __init capidrv_init(void) -{ - capi_profile profile; - u32 ncontr, contr; - u16 errcode; - - global.ap.rparam.level3cnt = -2; /* number of bchannels twice */ - global.ap.rparam.datablkcnt = 16; - global.ap.rparam.datablklen = 2048; - - global.ap.recv_message = capidrv_recv_message; - errcode = capi20_register(&global.ap); - if (errcode) { - return -EIO; - } - - register_capictr_notifier(&capictr_nb); - - errcode = capi20_get_profile(0, &profile); - if (errcode != CAPI_NOERROR) { - unregister_capictr_notifier(&capictr_nb); - capi20_release(&global.ap); - return -EIO; - } - - ncontr = profile.ncontroller; - for (contr = 1; contr <= ncontr; contr++) { - errcode = capi20_get_profile(contr, &profile); - if (errcode != CAPI_NOERROR) - continue; - (void) capidrv_addcontr(contr, &profile); - } - proc_init(); - - return 0; -} - -static void __exit capidrv_exit(void) -{ - unregister_capictr_notifier(&capictr_nb); - capi20_release(&global.ap); - - proc_exit(); -} - -module_init(capidrv_init); -module_exit(capidrv_exit); diff --git a/drivers/isdn/capi/capidrv.h b/drivers/isdn/capi/capidrv.h deleted file mode 100644 index 4466b2e0176d..000000000000 --- a/drivers/isdn/capi/capidrv.h +++ /dev/null @@ -1,140 +0,0 @@ -/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $ - * - * ISDN4Linux Driver, using capi20 interface (kernelcapi) - * - * Copyright 1997 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __CAPIDRV_H__ -#define __CAPIDRV_H__ - -/* - * LISTEN state machine - */ -#define ST_LISTEN_NONE 0 /* L-0 */ -#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */ -#define ST_LISTEN_ACTIVE 2 /* L-1 */ -#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */ - - -#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1 - L-1 -> L-1.1 */ -#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0 - L-1.1 -> L-1 */ -#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0 - L-1.1 -> L-0 */ -#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1 - L-1.1 -> L.1 */ - -/* - * per plci state machine - */ -#define ST_PLCI_NONE 0 /* P-0 */ -#define ST_PLCI_OUTGOING 1 /* P-0.1 */ -#define ST_PLCI_ALLOCATED 2 /* P-1 */ -#define ST_PLCI_ACTIVE 3 /* P-ACT */ -#define ST_PLCI_INCOMING 4 /* P-2 */ -#define ST_PLCI_FACILITY_IND 5 /* P-3 */ -#define ST_PLCI_ACCEPTING 6 /* P-4 */ -#define ST_PLCI_DISCONNECTING 7 /* P-5 */ -#define ST_PLCI_DISCONNECTED 8 /* P-6 */ -#define ST_PLCI_RESUMEING 9 /* P-0.Res */ -#define ST_PLCI_RESUME 10 /* P-Res */ -#define ST_PLCI_HELD 11 /* P-HELD */ - -#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 - */ -#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 - */ -#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 - */ -#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 - */ -#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 - */ -#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT - */ -#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 - P-3 -> P-5 - */ -#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 - P-2 -> P-5 - P-3 -> P-5 - P-4 -> P-5 - P-ACT -> P-5 - P-Res -> P-5 (*) - P-HELD -> P-5 (*) - */ -#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 - P-2 -> P-6 - P-3 -> P-6 - P-4 -> P-6 - P-5 -> P-6 - P-ACT -> P-6 - P-Res -> P-6 (*) - P-HELD -> P-6 (*) - */ -#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 - P-1 -> P-5 - P-ACT -> P-5 - P-2 -> P-5 - P-3 -> P-5 - P-4 -> P-5 - */ -#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 - */ -#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 - */ - -#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res - */ -#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res - */ -#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0 - */ -#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT - */ -#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD - */ -#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT - */ -#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5 - */ -#define EV_PLCI_CD_IND 20 /* P-2 -> P-5 - */ - -/* - * per ncci state machine - */ -#define ST_NCCI_PREVIOUS -1 -#define ST_NCCI_NONE 0 /* N-0 */ -#define ST_NCCI_OUTGOING 1 /* N-0.1 */ -#define ST_NCCI_INCOMING 2 /* N-1 */ -#define ST_NCCI_ALLOCATED 3 /* N-2 */ -#define ST_NCCI_ACTIVE 4 /* N-ACT */ -#define ST_NCCI_RESETING 5 /* N-3 */ -#define ST_NCCI_DISCONNECTING 6 /* N-4 */ -#define ST_NCCI_DISCONNECTED 7 /* N-5 */ - -#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */ -#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */ -#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */ -#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */ -#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */ -#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */ -#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */ -#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */ -#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */ -#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */ -#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */ -#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4 - N-2 -> N-4 - N-3 -> N-4 - N-ACT -> N-4 */ -#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */ - -#endif /* __CAPIDRV_H__ */ diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile deleted file mode 100644 index 07684fe53537..000000000000 --- a/drivers/isdn/divert/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the dss1_divert ISDN module - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o - -# Multipart objects. - -dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c deleted file mode 100644 index 267dede13bfd..000000000000 --- a/drivers/isdn/divert/divert_init.c +++ /dev/null @@ -1,82 +0,0 @@ -/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $ - * - * Module init for DSS1 diversion services for i4l. - * - * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include - -#include "isdn_divert.h" - -MODULE_DESCRIPTION("ISDN4Linux: Call diversion support"); -MODULE_AUTHOR("Werner Cornelius"); -MODULE_LICENSE("GPL"); - -/****************************************/ -/* structure containing interface to hl */ -/****************************************/ -isdn_divert_if divert_if = { - DIVERT_IF_MAGIC, /* magic value */ - DIVERT_CMD_REG, /* register cmd */ - ll_callback, /* callback routine from ll */ - NULL, /* command still not specified */ - NULL, /* drv_to_name */ - NULL, /* name_to_drv */ -}; - -/*************************/ -/* Module interface code */ -/* no cmd line parms */ -/*************************/ -static int __init divert_init(void) -{ - int i; - - if (divert_dev_init()) { - printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n"); - return (-EIO); - } - if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) { - divert_dev_deinit(); - printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i); - return (-EIO); - } - printk(KERN_INFO "dss1_divert module successfully installed\n"); - return (0); -} - -/**********************/ -/* Module deinit code */ -/**********************/ -static void __exit divert_exit(void) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&divert_lock, flags); - divert_if.cmd = DIVERT_CMD_REL; /* release */ - if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) { - printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i); - spin_unlock_irqrestore(&divert_lock, flags); - return; - } - if (divert_dev_deinit()) { - printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n"); - spin_unlock_irqrestore(&divert_lock, flags); - return; - } - spin_unlock_irqrestore(&divert_lock, flags); - deleterule(-1); /* delete all rules and free mem */ - deleteprocs(); - printk(KERN_INFO "dss1_divert module successfully removed \n"); -} - -module_init(divert_init); -module_exit(divert_exit); diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c deleted file mode 100644 index 342585e04fd3..000000000000 --- a/drivers/isdn/divert/divert_procfs.c +++ /dev/null @@ -1,336 +0,0 @@ -/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $ - * - * Filesystem handling for the diversion supplementary services. - * - * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#ifdef CONFIG_PROC_FS -#include -#else -#include -#endif -#include -#include -#include -#include -#include "isdn_divert.h" - - -/*********************************/ -/* Variables for interface queue */ -/*********************************/ -ulong if_used = 0; /* number of interface users */ -static DEFINE_MUTEX(isdn_divert_mutex); -static struct divert_info *divert_info_head = NULL; /* head of queue */ -static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */ -static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */ -static wait_queue_head_t rd_queue; - -/*********************************/ -/* put an info buffer into queue */ -/*********************************/ -void -put_info_buffer(char *cp) -{ - struct divert_info *ib; - unsigned long flags; - - if (if_used <= 0) - return; - if (!cp) - return; - if (!*cp) - return; - if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC))) - return; /* no memory */ - strcpy(ib->info_start, cp); /* set output string */ - ib->next = NULL; - spin_lock_irqsave(&divert_info_lock, flags); - ib->usage_cnt = if_used; - if (!divert_info_head) - divert_info_head = ib; /* new head */ - else - divert_info_tail->next = ib; /* follows existing messages */ - divert_info_tail = ib; /* new tail */ - - /* delete old entrys */ - while (divert_info_head->next) { - if ((divert_info_head->usage_cnt <= 0) && - (divert_info_head->next->usage_cnt <= 0)) { - ib = divert_info_head; - divert_info_head = divert_info_head->next; - kfree(ib); - } else - break; - } /* divert_info_head->next */ - spin_unlock_irqrestore(&divert_info_lock, flags); - wake_up_interruptible(&(rd_queue)); -} /* put_info_buffer */ - -#ifdef CONFIG_PROC_FS - -/**********************************/ -/* deflection device read routine */ -/**********************************/ -static ssize_t -isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - struct divert_info *inf; - int len; - - if (!(inf = *((struct divert_info **) file->private_data))) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - wait_event_interruptible(rd_queue, (inf = - *((struct divert_info **) file->private_data))); - } - if (!inf) - return (0); - - inf->usage_cnt--; /* new usage count */ - file->private_data = &inf->next; /* next structure */ - if ((len = strlen(inf->info_start)) <= count) { - if (copy_to_user(buf, inf->info_start, len)) - return -EFAULT; - *off += len; - return (len); - } - return (0); -} /* isdn_divert_read */ - -/**********************************/ -/* deflection device write routine */ -/**********************************/ -static ssize_t -isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - return (-ENODEV); -} /* isdn_divert_write */ - - -/***************************************/ -/* select routines for various kernels */ -/***************************************/ -static __poll_t -isdn_divert_poll(struct file *file, poll_table *wait) -{ - __poll_t mask = 0; - - poll_wait(file, &(rd_queue), wait); - /* mask = EPOLLOUT | EPOLLWRNORM; */ - if (*((struct divert_info **) file->private_data)) { - mask |= EPOLLIN | EPOLLRDNORM; - } - return mask; -} /* isdn_divert_poll */ - -/****************/ -/* Open routine */ -/****************/ -static int -isdn_divert_open(struct inode *ino, struct file *filep) -{ - unsigned long flags; - - spin_lock_irqsave(&divert_info_lock, flags); - if_used++; - if (divert_info_head) - filep->private_data = &(divert_info_tail->next); - else - filep->private_data = &divert_info_head; - spin_unlock_irqrestore(&divert_info_lock, flags); - /* start_divert(); */ - return nonseekable_open(ino, filep); -} /* isdn_divert_open */ - -/*******************/ -/* close routine */ -/*******************/ -static int -isdn_divert_close(struct inode *ino, struct file *filep) -{ - struct divert_info *inf; - unsigned long flags; - - spin_lock_irqsave(&divert_info_lock, flags); - if_used--; - inf = *((struct divert_info **) filep->private_data); - while (inf) { - inf->usage_cnt--; - inf = inf->next; - } - if (if_used <= 0) - while (divert_info_head) { - inf = divert_info_head; - divert_info_head = divert_info_head->next; - kfree(inf); - } - spin_unlock_irqrestore(&divert_info_lock, flags); - return (0); -} /* isdn_divert_close */ - -/*********/ -/* IOCTL */ -/*********/ -static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg) -{ - divert_ioctl dioctl; - int i; - unsigned long flags; - divert_rule *rulep; - char *cp; - - if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl))) - return -EFAULT; - - switch (cmd) { - case IIOCGETVER: - dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */ - break; - - case IIOCGETDRV: - if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0) - return (-EINVAL); - break; - - case IIOCGETNAM: - cp = divert_if.drv_to_name(dioctl.getid.drvid); - if (!cp) - return (-EINVAL); - if (!*cp) - return (-EINVAL); - strcpy(dioctl.getid.drvnam, cp); - break; - - case IIOCGETRULE: - if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) - return (-EINVAL); - dioctl.getsetrule.rule = *rulep; /* copy data */ - break; - - case IIOCMODRULE: - if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) - return (-EINVAL); - spin_lock_irqsave(&divert_lock, flags); - *rulep = dioctl.getsetrule.rule; /* copy data */ - spin_unlock_irqrestore(&divert_lock, flags); - return (0); /* no copy required */ - break; - - case IIOCINSRULE: - return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule)); - break; - - case IIOCDELRULE: - return (deleterule(dioctl.getsetrule.ruleidx)); - break; - - case IIOCDODFACT: - return (deflect_extern_action(dioctl.fwd_ctrl.subcmd, - dioctl.fwd_ctrl.callid, - dioctl.fwd_ctrl.to_nr)); - - case IIOCDOCFACT: - case IIOCDOCFDIS: - case IIOCDOCFINT: - if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid)) - return (-EINVAL); /* invalid driver */ - if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) == - sizeof(dioctl.cf_ctrl.msn)) - return -EINVAL; - if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) == - sizeof(dioctl.cf_ctrl.fwd_nr)) - return -EINVAL; - if ((i = cf_command(dioctl.cf_ctrl.drvid, - (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2, - dioctl.cf_ctrl.cfproc, - dioctl.cf_ctrl.msn, - dioctl.cf_ctrl.service, - dioctl.cf_ctrl.fwd_nr, - &dioctl.cf_ctrl.procid))) - return (i); - break; - - default: - return (-EINVAL); - } /* switch cmd */ - return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0; -} /* isdn_divert_ioctl */ - -static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg) -{ - long ret; - - mutex_lock(&isdn_divert_mutex); - ret = isdn_divert_ioctl_unlocked(file, cmd, arg); - mutex_unlock(&isdn_divert_mutex); - - return ret; -} - -static const struct file_operations isdn_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_divert_read, - .write = isdn_divert_write, - .poll = isdn_divert_poll, - .unlocked_ioctl = isdn_divert_ioctl, - .open = isdn_divert_open, - .release = isdn_divert_close, -}; - -/****************************/ -/* isdn subdir in /proc/net */ -/****************************/ -static struct proc_dir_entry *isdn_proc_entry = NULL; -static struct proc_dir_entry *isdn_divert_entry = NULL; -#endif /* CONFIG_PROC_FS */ - -/***************************************************************************/ -/* divert_dev_init must be called before the proc filesystem may be used */ -/***************************************************************************/ -int -divert_dev_init(void) -{ - - init_waitqueue_head(&rd_queue); - -#ifdef CONFIG_PROC_FS - isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); - if (!isdn_proc_entry) - return (-1); - isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO, - isdn_proc_entry, &isdn_fops); - if (!isdn_divert_entry) { - remove_proc_entry("isdn", init_net.proc_net); - return (-1); - } -#endif /* CONFIG_PROC_FS */ - - return (0); -} /* divert_dev_init */ - -/***************************************************************************/ -/* divert_dev_deinit must be called before leaving isdn when included as */ -/* a module. */ -/***************************************************************************/ -int -divert_dev_deinit(void) -{ - -#ifdef CONFIG_PROC_FS - remove_proc_entry("divert", isdn_proc_entry); - remove_proc_entry("isdn", init_net.proc_net); -#endif /* CONFIG_PROC_FS */ - - return (0); -} /* divert_dev_deinit */ diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c deleted file mode 100644 index 5620fd2c6009..000000000000 --- a/drivers/isdn/divert/isdn_divert.c +++ /dev/null @@ -1,846 +0,0 @@ -/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $ - * - * DSS1 main diversion supplementary handling for i4l. - * - * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include - -#include "isdn_divert.h" - -/**********************************/ -/* structure keeping calling info */ -/**********************************/ -struct call_struc { - isdn_ctrl ics; /* delivered setup + driver parameters */ - ulong divert_id; /* Id delivered to user */ - unsigned char akt_state; /* actual state */ - char deflect_dest[35]; /* deflection destination */ - struct timer_list timer; /* timer control structure */ - char info[90]; /* device info output */ - struct call_struc *next; /* pointer to next entry */ - struct call_struc *prev; -}; - - -/********************************************/ -/* structure keeping deflection table entry */ -/********************************************/ -struct deflect_struc { - struct deflect_struc *next, *prev; - divert_rule rule; /* used rule */ -}; - - -/*****************************************/ -/* variables for main diversion services */ -/*****************************************/ -/* diversion/deflection processes */ -static struct call_struc *divert_head = NULL; /* head of remembered entrys */ -static ulong next_id = 1; /* next info id */ -static struct deflect_struc *table_head = NULL; -static struct deflect_struc *table_tail = NULL; -static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */ - -DEFINE_SPINLOCK(divert_lock); - -/***************************/ -/* timer callback function */ -/***************************/ -static void deflect_timer_expire(struct timer_list *t) -{ - unsigned long flags; - struct call_struc *cs = from_timer(cs, t, timer); - - spin_lock_irqsave(&divert_lock, flags); - del_timer(&cs->timer); /* delete active timer */ - spin_unlock_irqrestore(&divert_lock, flags); - - switch (cs->akt_state) { - case DEFLECT_PROCEED: - cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */ - divert_if.ll_cmd(&cs->ics); - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - break; - - case DEFLECT_ALERT: - cs->ics.command = ISDN_CMD_REDIR; /* protocol */ - strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone)); - strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed"); - divert_if.ll_cmd(&cs->ics); - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - break; - - case DEFLECT_AUTODEL: - default: - spin_lock_irqsave(&divert_lock, flags); - if (cs->prev) - cs->prev->next = cs->next; /* forward link */ - else - divert_head = cs->next; - if (cs->next) - cs->next->prev = cs->prev; /* back link */ - spin_unlock_irqrestore(&divert_lock, flags); - kfree(cs); - return; - - } /* switch */ -} /* deflect_timer_func */ - - -/*****************************************/ -/* handle call forwarding de/activations */ -/* 0 = deact, 1 = act, 2 = interrogate */ -/*****************************************/ -int cf_command(int drvid, int mode, - u_char proc, char *msn, - u_char service, char *fwd_nr, ulong *procid) -{ - unsigned long flags; - int retval, msnlen; - int fwd_len; - char *p, *ielenp, tmp[60]; - struct call_struc *cs; - - if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */ - if ((proc & 0x7F) > 2) return (-EINVAL); - proc &= 3; - p = tmp; - *p++ = 0x30; /* enumeration */ - ielenp = p++; /* remember total length position */ - *p++ = 0xa; /* proc tag */ - *p++ = 1; /* length */ - *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */ - *p++ = 0xa; /* service tag */ - *p++ = 1; /* length */ - *p++ = service; /* service to handle */ - - if (mode == 1) { - if (!*fwd_nr) return (-EINVAL); /* destination missing */ - if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */ - fwd_len = strlen(fwd_nr); - *p++ = 0x30; /* number enumeration */ - *p++ = fwd_len + 2; /* complete forward to len */ - *p++ = 0x80; /* fwd to nr */ - *p++ = fwd_len; /* length of number */ - strcpy(p, fwd_nr); /* copy number */ - p += fwd_len; /* pointer beyond fwd */ - } /* activate */ - - msnlen = strlen(msn); - *p++ = 0x80; /* msn number */ - if (msnlen > 1) { - *p++ = msnlen; /* length */ - strcpy(p, msn); - p += msnlen; - } else - *p++ = 0; - - *ielenp = p - ielenp - 1; /* set total IE length */ - - /* allocate mem for information struct */ - if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) - return (-ENOMEM); /* no memory */ - timer_setup(&cs->timer, deflect_timer_expire, 0); - cs->info[0] = '\0'; - cs->ics.driver = drvid; - cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */ - cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */ - cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */ - cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */ - cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */ - cs->ics.parm.dss1_io.data = tmp; /* start of buffer */ - - spin_lock_irqsave(&divert_lock, flags); - cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */ - spin_unlock_irqrestore(&divert_lock, flags); - *procid = cs->ics.parm.dss1_io.ll_id; - - sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n", - (!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT, - cs->ics.parm.dss1_io.ll_id, - (mode != 2) ? "" : "0 ", - divert_if.drv_to_name(cs->ics.driver), - msn, - service & 0xFF, - proc, - (mode != 1) ? "" : " 0 ", - (mode != 1) ? "" : fwd_nr); - - retval = divert_if.ll_cmd(&cs->ics); /* execute command */ - - if (!retval) { - cs->prev = NULL; - spin_lock_irqsave(&divert_lock, flags); - cs->next = divert_head; - divert_head = cs; - spin_unlock_irqrestore(&divert_lock, flags); - } else - kfree(cs); - return (retval); -} /* cf_command */ - - -/****************************************/ -/* handle a external deflection command */ -/****************************************/ -int deflect_extern_action(u_char cmd, ulong callid, char *to_nr) -{ - struct call_struc *cs; - isdn_ctrl ic; - unsigned long flags; - int i; - - if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */ - cs = divert_head; /* start of parameter list */ - while (cs) { - if (cs->divert_id == callid) break; /* found */ - cs = cs->next; - } /* search entry */ - if (!cs) return (-EINVAL); /* invalid callid */ - - ic.driver = cs->ics.driver; - ic.arg = cs->ics.arg; - i = -EINVAL; - if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */ - switch (cmd & 0x7F) { - case 0: /* hangup */ - del_timer(&cs->timer); - ic.command = ISDN_CMD_HANGUP; - i = divert_if.ll_cmd(&ic); - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - break; - - case 1: /* alert */ - if (cs->akt_state == DEFLECT_ALERT) return (0); - cmd &= 0x7F; /* never wait */ - del_timer(&cs->timer); - ic.command = ISDN_CMD_ALERT; - if ((i = divert_if.ll_cmd(&ic))) { - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - } else - cs->akt_state = DEFLECT_ALERT; - break; - - case 2: /* redir */ - del_timer(&cs->timer); - strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone)); - strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual"); - ic.command = ISDN_CMD_REDIR; - if ((i = divert_if.ll_cmd(&ic))) { - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - } else - cs->akt_state = DEFLECT_ALERT; - break; - - } /* switch */ - return (i); -} /* deflect_extern_action */ - -/********************************/ -/* insert a new rule before idx */ -/********************************/ -int insertrule(int idx, divert_rule *newrule) -{ - struct deflect_struc *ds, *ds1 = NULL; - unsigned long flags; - - if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL))) - return (-ENOMEM); /* no memory */ - - ds->rule = *newrule; /* set rule */ - - spin_lock_irqsave(&divert_lock, flags); - - if (idx >= 0) { - ds1 = table_head; - while ((ds1) && (idx > 0)) - { idx--; - ds1 = ds1->next; - } - if (!ds1) idx = -1; - } - - if (idx < 0) { - ds->prev = table_tail; /* previous entry */ - ds->next = NULL; /* end of chain */ - if (ds->prev) - ds->prev->next = ds; /* last forward */ - else - table_head = ds; /* is first entry */ - table_tail = ds; /* end of queue */ - } else { - ds->next = ds1; /* next entry */ - ds->prev = ds1->prev; /* prev entry */ - ds1->prev = ds; /* backward chain old element */ - if (!ds->prev) - table_head = ds; /* first element */ - } - - spin_unlock_irqrestore(&divert_lock, flags); - return (0); -} /* insertrule */ - -/***********************************/ -/* delete the rule at position idx */ -/***********************************/ -int deleterule(int idx) -{ - struct deflect_struc *ds, *ds1; - unsigned long flags; - - if (idx < 0) { - spin_lock_irqsave(&divert_lock, flags); - ds = table_head; - table_head = NULL; - table_tail = NULL; - spin_unlock_irqrestore(&divert_lock, flags); - while (ds) { - ds1 = ds; - ds = ds->next; - kfree(ds1); - } - return (0); - } - - spin_lock_irqsave(&divert_lock, flags); - ds = table_head; - - while ((ds) && (idx > 0)) { - idx--; - ds = ds->next; - } - - if (!ds) { - spin_unlock_irqrestore(&divert_lock, flags); - return (-EINVAL); - } - - if (ds->next) - ds->next->prev = ds->prev; /* backward chain */ - else - table_tail = ds->prev; /* end of chain */ - - if (ds->prev) - ds->prev->next = ds->next; /* forward chain */ - else - table_head = ds->next; /* start of chain */ - - spin_unlock_irqrestore(&divert_lock, flags); - kfree(ds); - return (0); -} /* deleterule */ - -/*******************************************/ -/* get a pointer to a specific rule number */ -/*******************************************/ -divert_rule *getruleptr(int idx) -{ - struct deflect_struc *ds = table_head; - - if (idx < 0) return (NULL); - while ((ds) && (idx >= 0)) { - if (!(idx--)) { - return (&ds->rule); - break; - } - ds = ds->next; - } - return (NULL); -} /* getruleptr */ - -/*************************************************/ -/* called from common module on an incoming call */ -/*************************************************/ -static int isdn_divert_icall(isdn_ctrl *ic) -{ - int retval = 0; - unsigned long flags; - struct call_struc *cs = NULL; - struct deflect_struc *dv; - char *p, *p1; - u_char accept; - - /* first check the internal deflection table */ - for (dv = table_head; dv; dv = dv->next) { - /* scan table */ - if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) || - ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL))) - continue; /* call option check */ - if (!(dv->rule.drvid & (1L << ic->driver))) - continue; /* driver not matching */ - if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1)) - continue; /* si1 not matching */ - if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2)) - continue; /* si2 not matching */ - - p = dv->rule.my_msn; - p1 = ic->parm.setup.eazmsn; - accept = 0; - while (*p) { - /* complete compare */ - if (*p == '-') { - accept = 1; /* call accepted */ - break; - } - if (*p++ != *p1++) - break; /* not accepted */ - if ((!*p) && (!*p1)) - accept = 1; - } /* complete compare */ - if (!accept) continue; /* not accepted */ - - if ((strcmp(dv->rule.caller, "0")) || - (ic->parm.setup.phone[0])) { - p = dv->rule.caller; - p1 = ic->parm.setup.phone; - accept = 0; - while (*p) { - /* complete compare */ - if (*p == '-') { - accept = 1; /* call accepted */ - break; - } - if (*p++ != *p1++) - break; /* not accepted */ - if ((!*p) && (!*p1)) - accept = 1; - } /* complete compare */ - if (!accept) continue; /* not accepted */ - } - - switch (dv->rule.action) { - case DEFLECT_IGNORE: - return 0; - - case DEFLECT_ALERT: - case DEFLECT_PROCEED: - case DEFLECT_REPORT: - case DEFLECT_REJECT: - if (dv->rule.action == DEFLECT_PROCEED) - if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime))) - return (0); /* no external deflection needed */ - if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) - return (0); /* no memory */ - timer_setup(&cs->timer, deflect_timer_expire, 0); - cs->info[0] = '\0'; - - cs->ics = *ic; /* copy incoming data */ - if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0"); - if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0"); - cs->ics.parm.setup.screen = dv->rule.screen; - if (dv->rule.waittime) - cs->timer.expires = jiffies + (HZ * dv->rule.waittime); - else if (dv->rule.action == DEFLECT_PROCEED) - cs->timer.expires = jiffies + (HZ * extern_wait_max); - else - cs->timer.expires = 0; - cs->akt_state = dv->rule.action; - spin_lock_irqsave(&divert_lock, flags); - cs->divert_id = next_id++; /* new sequence number */ - spin_unlock_irqrestore(&divert_lock, flags); - cs->prev = NULL; - if (cs->akt_state == DEFLECT_ALERT) { - strcpy(cs->deflect_dest, dv->rule.to_nr); - if (!cs->timer.expires) { - strcpy(ic->parm.setup.eazmsn, - "Testtext direct"); - ic->parm.setup.screen = dv->rule.screen; - strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone)); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - retval = 5; - } else - retval = 1; /* alerting */ - } else { - cs->deflect_dest[0] = '\0'; - retval = 4; /* only proceed */ - } - snprintf(cs->info, sizeof(cs->info), - "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n", - cs->akt_state, - cs->divert_id, - divert_if.drv_to_name(cs->ics.driver), - (ic->command == ISDN_STAT_ICALLW) ? "1" : "0", - cs->ics.parm.setup.phone, - cs->ics.parm.setup.eazmsn, - cs->ics.parm.setup.si1, - cs->ics.parm.setup.si2, - cs->ics.parm.setup.screen, - dv->rule.waittime, - cs->deflect_dest); - if ((dv->rule.action == DEFLECT_REPORT) || - (dv->rule.action == DEFLECT_REJECT)) { - put_info_buffer(cs->info); - kfree(cs); /* remove */ - return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */ - } - break; - - default: - return 0; /* ignore call */ - } /* switch action */ - break; /* will break the 'for' looping */ - } /* scan_table */ - - if (cs) { - cs->prev = NULL; - spin_lock_irqsave(&divert_lock, flags); - cs->next = divert_head; - divert_head = cs; - if (cs->timer.expires) add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - - put_info_buffer(cs->info); - return (retval); - } else - return (0); -} /* isdn_divert_icall */ - - -void deleteprocs(void) -{ - struct call_struc *cs, *cs1; - unsigned long flags; - - spin_lock_irqsave(&divert_lock, flags); - cs = divert_head; - divert_head = NULL; - while (cs) { - del_timer(&cs->timer); - cs1 = cs; - cs = cs->next; - kfree(cs1); - } - spin_unlock_irqrestore(&divert_lock, flags); -} /* deleteprocs */ - -/****************************************************/ -/* put a address including address type into buffer */ -/****************************************************/ -static int put_address(char *st, u_char *p, int len) -{ - u_char retval = 0; - u_char adr_typ = 0; /* network standard */ - - if (len < 2) return (retval); - if (*p == 0xA1) { - retval = *(++p) + 2; /* total length */ - if (retval > len) return (0); /* too short */ - len = retval - 2; /* remaining length */ - if (len < 3) return (0); - if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0); - adr_typ = *(++p); - len -= 3; - p++; - if (len < 2) return (0); - if (*p++ != 0x12) return (0); - if (*p > len) return (0); /* check number length */ - len = *p++; - } else if (*p == 0x80) { - retval = *(++p) + 2; /* total length */ - if (retval > len) return (0); - len = retval - 2; - p++; - } else - return (0); /* invalid address information */ - - sprintf(st, "%d ", adr_typ); - st += strlen(st); - if (!len) - *st++ = '-'; - else - while (len--) - *st++ = *p++; - *st = '\0'; - return (retval); -} /* put_address */ - -/*************************************/ -/* report a successful interrogation */ -/*************************************/ -static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) -{ - char *src = ic->parm.dss1_io.data; - int restlen = ic->parm.dss1_io.datalen; - int cnt = 1; - u_char n, n1; - char st[90], *p, *stp; - - if (restlen < 2) return (-100); /* frame too short */ - if (*src++ != 0x30) return (-101); - if ((n = *src++) > 0x81) return (-102); /* invalid length field */ - restlen -= 2; /* remaining bytes */ - if (n == 0x80) { - if (restlen < 2) return (-103); - if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104); - restlen -= 2; - } else if (n == 0x81) { - n = *src++; - restlen--; - if (n > restlen) return (-105); - restlen = n; - } else if (n > restlen) - return (-106); - else - restlen = n; /* standard format */ - if (restlen < 3) return (-107); /* no procedure */ - if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108); - restlen -= 3; - if (restlen < 2) return (-109); /* list missing */ - if (*src == 0x31) { - src++; - if ((n = *src++) > 0x81) return (-110); /* invalid length field */ - restlen -= 2; /* remaining bytes */ - if (n == 0x80) { - if (restlen < 2) return (-111); - if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112); - restlen -= 2; - } else if (n == 0x81) { - n = *src++; - restlen--; - if (n > restlen) return (-113); - restlen = n; - } else if (n > restlen) - return (-114); - else - restlen = n; /* standard format */ - } /* result list header */ - - while (restlen >= 2) { - stp = st; - sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id, - cnt++, divert_if.drv_to_name(ic->driver)); - stp += strlen(stp); - if (*src++ != 0x30) return (-115); /* invalid enum */ - n = *src++; - restlen -= 2; - if (n > restlen) return (-116); /* enum length wrong */ - restlen -= n; - p = src; /* one entry */ - src += n; - if (!(n1 = put_address(stp, p, n & 0xFF))) continue; - stp += strlen(stp); - p += n1; - n -= n1; - if (n < 6) continue; /* no service and proc */ - if ((*p++ != 0x0A) || (*p++ != 1)) continue; - sprintf(stp, " 0x%02x ", (*p++) & 0xFF); - stp += strlen(stp); - if ((*p++ != 0x0A) || (*p++ != 1)) continue; - sprintf(stp, "%d ", (*p++) & 0xFF); - stp += strlen(stp); - n -= 6; - if (n > 2) { - if (*p++ != 0x30) continue; - if (*p > (n - 2)) continue; - n = *p++; - if (!(n1 = put_address(stp, p, n & 0xFF))) continue; - stp += strlen(stp); - } - sprintf(stp, "\n"); - put_info_buffer(st); - } /* while restlen */ - if (restlen) return (-117); - return (0); -} /* interrogate_success */ - -/*********************************************/ -/* callback for protocol specific extensions */ -/*********************************************/ -static int prot_stat_callback(isdn_ctrl *ic) -{ - struct call_struc *cs, *cs1; - int i; - unsigned long flags; - - cs = divert_head; /* start of list */ - cs1 = NULL; - while (cs) { - if (ic->driver == cs->ics.driver) { - switch (cs->ics.arg) { - case DSS1_CMD_INVOKE: - if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) && - (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) { - switch (ic->arg) { - case DSS1_STAT_INVOKE_ERR: - sprintf(cs->info, "128 0x%lx 0x%x\n", - ic->parm.dss1_io.ll_id, - ic->parm.dss1_io.timeout); - put_info_buffer(cs->info); - break; - - case DSS1_STAT_INVOKE_RES: - switch (cs->ics.parm.dss1_io.proc) { - case 7: - case 8: - put_info_buffer(cs->info); - break; - - case 11: - i = interrogate_success(ic, cs); - if (i) - sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT, - ic->parm.dss1_io.ll_id, i); - put_info_buffer(cs->info); - break; - - default: - printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc); - break; - } - - break; - - default: - printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg); - break; - } - cs1 = cs; /* remember structure */ - cs = NULL; - continue; /* abort search */ - } /* id found */ - break; - - case DSS1_CMD_INVOKE_ABORT: - printk(KERN_WARNING "dss1_divert unhandled invoke abort\n"); - break; - - default: - printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg); - break; - } /* switch ics.arg */ - cs = cs->next; - } /* driver ok */ - } - - if (!cs1) { - printk(KERN_WARNING "dss1_divert unhandled process\n"); - return (0); - } - - if (cs1->ics.driver == -1) { - spin_lock_irqsave(&divert_lock, flags); - del_timer(&cs1->timer); - if (cs1->prev) - cs1->prev->next = cs1->next; /* forward link */ - else - divert_head = cs1->next; - if (cs1->next) - cs1->next->prev = cs1->prev; /* back link */ - spin_unlock_irqrestore(&divert_lock, flags); - kfree(cs1); - } - - return (0); -} /* prot_stat_callback */ - - -/***************************/ -/* status callback from HL */ -/***************************/ -static int isdn_divert_stat_callback(isdn_ctrl *ic) -{ - struct call_struc *cs, *cs1; - unsigned long flags; - int retval; - - retval = -1; - cs = divert_head; /* start of list */ - while (cs) { - if ((ic->driver == cs->ics.driver) && - (ic->arg == cs->ics.arg)) { - switch (ic->command) { - case ISDN_STAT_DHUP: - sprintf(cs->info, "129 0x%lx\n", cs->divert_id); - del_timer(&cs->timer); - cs->ics.driver = -1; - break; - - case ISDN_STAT_CAUSE: - sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num); - break; - - case ISDN_STAT_REDIR: - sprintf(cs->info, "131 0x%lx\n", cs->divert_id); - del_timer(&cs->timer); - cs->ics.driver = -1; - break; - - default: - sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command)); - break; - } - put_info_buffer(cs->info); - retval = 0; - } - cs1 = cs; - cs = cs->next; - if (cs1->ics.driver == -1) { - spin_lock_irqsave(&divert_lock, flags); - if (cs1->prev) - cs1->prev->next = cs1->next; /* forward link */ - else - divert_head = cs1->next; - if (cs1->next) - cs1->next->prev = cs1->prev; /* back link */ - spin_unlock_irqrestore(&divert_lock, flags); - kfree(cs1); - } - } - return (retval); /* not found */ -} /* isdn_divert_stat_callback */ - - -/********************/ -/* callback from ll */ -/********************/ -int ll_callback(isdn_ctrl *ic) -{ - switch (ic->command) { - case ISDN_STAT_ICALL: - case ISDN_STAT_ICALLW: - return (isdn_divert_icall(ic)); - break; - - case ISDN_STAT_PROT: - if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) { - if (ic->arg != DSS1_STAT_INVOKE_BRD) - return (prot_stat_callback(ic)); - else - return (0); /* DSS1 invoke broadcast */ - } else - return (-1); /* protocol not euro */ - - default: - return (isdn_divert_stat_callback(ic)); - } -} /* ll_callback */ diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h deleted file mode 100644 index 55033dd872c0..000000000000 --- a/drivers/isdn/divert/isdn_divert.h +++ /dev/null @@ -1,132 +0,0 @@ -/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $ - * - * Header for the diversion supplementary ioctl interface. - * - * Copyright 1998 by Werner Cornelius (werner@ikt.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include - -/******************************************/ -/* IOCTL codes for interface to user prog */ -/******************************************/ -#define DIVERT_IIOC_VERSION 0x01 /* actual version */ -#define IIOCGETVER _IO('I', 1) /* get version of interface */ -#define IIOCGETDRV _IO('I', 2) /* get driver number */ -#define IIOCGETNAM _IO('I', 3) /* get driver name */ -#define IIOCGETRULE _IO('I', 4) /* read one rule */ -#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */ -#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */ -#define IIOCDELRULE _IO('I', 7) /* delete a rule */ -#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */ -#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */ -#define IIOCDOCFDIS _IO('I', 10) /* deactivate control forwarding in PBX */ -#define IIOCDOCFINT _IO('I', 11) /* interrogate control forwarding in PBX */ - -/*************************************/ -/* states reported through interface */ -/*************************************/ -#define DEFLECT_IGNORE 0 /* ignore incoming call */ -#define DEFLECT_REPORT 1 /* only report */ -#define DEFLECT_PROCEED 2 /* deflect when externally triggered */ -#define DEFLECT_ALERT 3 /* alert and deflect after delay */ -#define DEFLECT_REJECT 4 /* reject immediately */ -#define DIVERT_ACTIVATE 5 /* diversion activate */ -#define DIVERT_DEACTIVATE 6 /* diversion deactivate */ -#define DIVERT_REPORT 7 /* interrogation result */ -#define DEFLECT_AUTODEL 255 /* only for internal use */ - -#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */ - -typedef struct { - ulong drvid; /* driver ids, bit mapped */ - char my_msn[35]; /* desired msn, subaddr allowed */ - char caller[35]; /* caller id, partial string with * + subaddr allowed */ - char to_nr[35]; /* deflected to number incl. subaddress */ - u_char si1, si2; /* service indicators, si1=bitmask, si1+2 0 = all */ - u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */ - u_char callopt; /* option for call handling: - 0 = all calls - 1 = only non waiting calls - 2 = only waiting calls */ - u_char action; /* desired action: - 0 = don't report call -> ignore - 1 = report call, do not allow/proceed for deflection - 2 = report call, send proceed, wait max waittime secs - 3 = report call, alert and deflect after waittime - 4 = report call, reject immediately - actions 1-2 only take place if interface is opened - */ - u_char waittime; /* maximum wait time for proceeding */ -} divert_rule; - -typedef union { - int drv_version; /* return of driver version */ - struct { - int drvid; /* id of driver */ - char drvnam[30]; /* name of driver */ - } getid; - struct { - int ruleidx; /* index of rule */ - divert_rule rule; /* rule parms */ - } getsetrule; - struct { - u_char subcmd; /* 0 = hangup/reject, - 1 = alert, - 2 = deflect */ - ulong callid; /* id of call delivered by ascii output */ - char to_nr[35]; /* destination when deflect, - else uus1 string (maxlen 31), - data from rule used if empty */ - } fwd_ctrl; - struct { - int drvid; /* id of driver */ - u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */ - ulong procid; /* process id returned when no error */ - u_char service; /* basically coded service, 0 = all */ - char msn[25]; /* desired msn, empty = all */ - char fwd_nr[35];/* forwarded to number + subaddress */ - } cf_ctrl; -} divert_ioctl; - -#ifdef __KERNEL__ - -#include -#include - -#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */ - -/**************************************************/ -/* structure keeping ascii info for device output */ -/**************************************************/ -struct divert_info { - struct divert_info *next; - ulong usage_cnt; /* number of files still to work */ - char info_start[2]; /* info string start */ -}; - - -/**************/ -/* Prototypes */ -/**************/ -extern spinlock_t divert_lock; - -extern ulong if_used; /* number of interface users */ -extern int divert_dev_deinit(void); -extern int divert_dev_init(void); -extern void put_info_buffer(char *); -extern int ll_callback(isdn_ctrl *); -extern isdn_divert_if divert_if; -extern divert_rule *getruleptr(int); -extern int insertrule(int, divert_rule *); -extern int deleterule(int); -extern void deleteprocs(void); -extern int deflect_extern_action(u_char, ulong, char *); -extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *); - -#endif /* __KERNEL__ */ diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig deleted file mode 100644 index cacde8de38a3..000000000000 --- a/drivers/isdn/i4l/Kconfig +++ /dev/null @@ -1,127 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Old ISDN4Linux config -# - -if ISDN_I4L - -config ISDN_PPP - bool "Support synchronous PPP" - depends on INET - select SLHC - help - Over digital connections such as ISDN, there is no need to - synchronize sender and recipient's clocks with start and stop bits - as is done over analog telephone lines. Instead, one can use - "synchronous PPP". Saying Y here will include this protocol. This - protocol is used by Cisco and Sun for example. So you want to say Y - here if the other end of your ISDN connection supports it. You will - need a special version of pppd (called ipppd) for using this - feature. See and - for more information. - -config ISDN_PPP_VJ - bool "Use VJ-compression with synchronous PPP" - depends on ISDN_PPP - help - This enables Van Jacobson header compression for synchronous PPP. - Say Y if the other end of the connection supports it. - -config ISDN_MPP - bool "Support generic MP (RFC 1717)" - depends on ISDN_PPP - help - With synchronous PPP enabled, it is possible to increase throughput - by bundling several ISDN-connections, using this protocol. See - for more information. - -config IPPP_FILTER - bool "Filtering for synchronous PPP" - depends on ISDN_PPP - help - Say Y here if you want to be able to filter the packets passing over - IPPP interfaces. This allows you to control which packets count as - activity (i.e. which packets will reset the idle timer or bring up - a demand-dialled link) and which packets are to be dropped entirely. - You need to say Y here if you wish to use the pass-filter and - active-filter options to ipppd. - -config ISDN_PPP_BSDCOMP - tristate "Support BSD compression" - depends on ISDN_PPP - help - Support for the BSD-Compress compression method for PPP, which uses - the LZW compression method to compress each PPP packet before it is - sent over the wire. The machine at the other end of the PPP link - (usually your ISP) has to support the BSD-Compress compression - method as well for this to be useful. Even if they don't support it, - it is safe to say Y here. - -config ISDN_AUDIO - bool "Support audio via ISDN" - help - If you say Y here, the modem-emulator will support a subset of the - EIA Class 8 Voice commands. Using a getty with voice-support - (mgetty+sendfax by with an extension, available - with the ISDN utility package for example), you will be able to use - your Linux box as an ISDN-answering machine. Of course, this must be - supported by the lowlevel driver also. Currently, the HiSax driver - is the only voice-supporting driver. See - for more information. - -config ISDN_TTY_FAX - bool "Support AT-Fax Class 1 and 2 commands" - depends on ISDN_AUDIO - help - If you say Y here, the modem-emulator will support a subset of the - Fax Class 1 and 2 commands. Using a getty with fax-support - (mgetty+sendfax, hylafax), you will be able to use your Linux box as - an ISDN-fax-machine. This must be supported by the lowlevel driver - also. See for more information. - -config ISDN_X25 - bool "X.25 PLP on top of ISDN" - depends on X25 - help - This feature provides the X.25 protocol over ISDN connections. - See for more information - if you are thinking about using this. - - -menu "ISDN feature submodules" - -config ISDN_DRV_LOOP - tristate "isdnloop support" - depends on BROKEN_ON_SMP - help - This driver provides a virtual ISDN card. Its primary purpose is - testing of linklevel features or configuration without getting - charged by your service-provider for lots of phone calls. - You need will need the loopctrl utility from the latest isdn4k-utils - package to set up this driver. - -config ISDN_DIVERSION - tristate "Support isdn diversion services" - help - This option allows you to use some supplementary diversion - services in conjunction with the HiSax driver on an EURO/DSS1 - line. - - Supported options are CD (call deflection), CFU (Call forward - unconditional), CFB (Call forward when busy) and CFNR (call forward - not reachable). Additionally the actual CFU, CFB and CFNR state may - be interrogated. - - The use of CFU, CFB, CFNR and interrogation may be limited to some - countries. The keypad protocol is still not implemented. CD should - work in all countries if the service has been subscribed to. - - Please read the file . - -endmenu - -comment "ISDN4Linux hardware drivers" - -# end ISDN_I4L -endif - diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile index be77500c9e86..11fe697739d5 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile @@ -3,18 +3,4 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN_I4L) += isdn.o -obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o - -# Multipart objects. - -isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o - -# Optional parts of multipart objects. - -isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o -isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o -isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o -isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o - diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c deleted file mode 100644 index b6bcd1eca128..000000000000 --- a/drivers/isdn/i4l/isdn_audio.c +++ /dev/null @@ -1,711 +0,0 @@ -/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $ - * - * Linux ISDN subsystem, audio conversion and compression (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) - * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include "isdn_audio.h" -#include "isdn_common.h" - -char *isdn_audio_revision = "$Revision: 1.1.2.2 $"; - -/* - * Misc. lookup-tables. - */ - -/* ulaw -> signed 16-bit */ -static short isdn_audio_ulaw_to_s16[] = -{ - 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, - 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, - 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, - 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, - 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, - 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, - 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, - 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, - 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, - 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, - 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, - 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, - 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, - 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, - 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, - 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, - 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, - 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, - 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, - 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, - 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, - 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, - 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, - 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, - 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, - 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, - 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, - 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, - 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, - 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, - 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, - 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 -}; - -/* alaw -> signed 16-bit */ -static short isdn_audio_alaw_to_s16[] = -{ - 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, - 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, - 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, - 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, - 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, - 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, - 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, - 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, - 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, - 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, - 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, - 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, - 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, - 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, - 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, - 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, - 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, - 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, - 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, - 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, - 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, - 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, - 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, - 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, - 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, - 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, - 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, - 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, - 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, - 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, - 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, - 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 -}; - -/* alaw -> ulaw */ -static char isdn_audio_alaw_to_ulaw[] = -{ - 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, - 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, - 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, - 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, - 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, - 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, - 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, - 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, - 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, - 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, - 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, - 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, - 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, - 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, - 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, - 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, - 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, - 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, - 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, - 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, - 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, - 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, - 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, - 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, - 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, - 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, - 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, - 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, - 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, - 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, - 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, - 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 -}; - -/* ulaw -> alaw */ -static char isdn_audio_ulaw_to_alaw[] = -{ - 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, - 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, - 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, - 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, - 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, - 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, - 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, - 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, - 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, - 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, - 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, - 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, - 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, - 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, - 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, - 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, - 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, - 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, - 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, - 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, - 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, - 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, - 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, - 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, - 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, - 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, - 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, - 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, - 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, - 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, - 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, - 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a -}; - -#define NCOEFF 8 /* number of frequencies to be analyzed */ -#define DTMF_TRESH 4000 /* above this is dtmf */ -#define SILENCE_TRESH 200 /* below this is silence */ -#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */ -#define LOGRP 0 -#define HIGRP 1 - -/* For DTMF recognition: - * 2 * cos(2 * PI * k / N) precalculated for all k - */ -static int cos2pik[NCOEFF] = -{ - 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332 -}; - -static char dtmf_matrix[4][4] = -{ - {'1', '2', '3', 'A'}, - {'4', '5', '6', 'B'}, - {'7', '8', '9', 'C'}, - {'*', '0', '#', 'D'} -}; - -static inline void -isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n) -{ -#ifdef __i386__ - unsigned long d0, d1, d2, d3; - __asm__ __volatile__( - "cld\n" - "1:\tlodsb\n\t" - "xlatb\n\t" - "stosb\n\t" - "loop 1b\n\t" - : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3) - : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) - : "memory", "ax"); -#else - while (n--) - *buff = table[*(unsigned char *)buff], buff++; -#endif -} - -void -isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) -{ - isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); -} - -void -isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len) -{ - isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); -} - -/* - * linear <-> adpcm conversion stuff - * Most parts from the mgetty-package. - * (C) by Gert Doering and Klaus Weidner - * Used by permission of Gert Doering - */ - - -#define ZEROTRAP /* turn on the trap as per the MIL-STD */ -#undef ZEROTRAP -#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ -#define CLIP 32635 - -static unsigned char -isdn_audio_linear2ulaw(int sample) -{ - static int exp_lut[256] = - { - 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - }; - int sign, - exponent, - mantissa; - unsigned char ulawbyte; - - /* Get the sample into sign-magnitude. */ - sign = (sample >> 8) & 0x80; /* set aside the sign */ - if (sign != 0) - sample = -sample; /* get magnitude */ - if (sample > CLIP) - sample = CLIP; /* clip the magnitude */ - - /* Convert from 16 bit linear to ulaw. */ - sample = sample + BIAS; - exponent = exp_lut[(sample >> 7) & 0xFF]; - mantissa = (sample >> (exponent + 3)) & 0x0F; - ulawbyte = ~(sign | (exponent << 4) | mantissa); -#ifdef ZEROTRAP - /* optional CCITT trap */ - if (ulawbyte == 0) - ulawbyte = 0x02; -#endif - return (ulawbyte); -} - - -static int Mx[3][8] = -{ - {0x3800, 0x5600, 0, 0, 0, 0, 0, 0}, - {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0}, - {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607}, -}; - -static int bitmask[9] = -{ - 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff -}; - -static int -isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len) -{ - while (s->nleft < s->nbits) { - int d = *((*in)++); - (*len)--; - s->word = (s->word << 8) | d; - s->nleft += 8; - } - s->nleft -= s->nbits; - return (s->word >> s->nleft) & bitmask[s->nbits]; -} - -static void -isdn_audio_put_bits(int data, int nbits, adpcm_state *s, - unsigned char **out, int *len) -{ - s->word = (s->word << nbits) | (data & bitmask[nbits]); - s->nleft += nbits; - while (s->nleft >= 8) { - int d = (s->word >> (s->nleft - 8)); - *(out[0]++) = d & 255; - (*len)++; - s->nleft -= 8; - } -} - -adpcm_state * -isdn_audio_adpcm_init(adpcm_state *s, int nbits) -{ - if (!s) - s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC); - if (s) { - s->a = 0; - s->d = 5; - s->word = 0; - s->nleft = 0; - s->nbits = nbits; - } - return s; -} - -dtmf_state * -isdn_audio_dtmf_init(dtmf_state *s) -{ - if (!s) - s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC); - if (s) { - s->idx = 0; - s->last = ' '; - } - return s; -} - -/* - * Decompression of adpcm data to a/u-law - * - */ - -int -isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in, - unsigned char *out, int len) -{ - int a = s->a; - int d = s->d; - int nbits = s->nbits; - int olen = 0; - - while (len) { - int e = isdn_audio_get_bits(s, &in, &len); - int sign; - - if (nbits == 4 && e == 0) - d = 4; - sign = (e >> (nbits - 1)) ? -1 : 1; - e &= bitmask[nbits - 1]; - a += sign * ((e << 1) + 1) * d >> 1; - if (d & 1) - a++; - if (fmt) - *out++ = isdn_audio_ulaw_to_alaw[ - isdn_audio_linear2ulaw(a << 2)]; - else - *out++ = isdn_audio_linear2ulaw(a << 2); - olen++; - d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; - if (d < 5) - d = 5; - } - s->a = a; - s->d = d; - return olen; -} - -int -isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in, - unsigned char *out, int len) -{ - int a = s->a; - int d = s->d; - int nbits = s->nbits; - int olen = 0; - - while (len--) { - int e = 0, - nmax = 1 << (nbits - 1); - int sign, - delta; - - if (fmt) - delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a; - else - delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a; - if (delta < 0) { - e = nmax; - delta = -delta; - } - while (--nmax && delta > d) { - delta -= d; - e++; - } - if (nbits == 4 && ((e & 0x0f) == 0)) - e = 8; - isdn_audio_put_bits(e, nbits, s, &out, &olen); - sign = (e >> (nbits - 1)) ? -1 : 1; - e &= bitmask[nbits - 1]; - - a += sign * ((e << 1) + 1) * d >> 1; - if (d & 1) - a++; - d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; - if (d < 5) - d = 5; - } - s->a = a; - s->d = d; - return olen; -} - -/* - * Goertzel algorithm. - * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/ - * for more info. - * Result is stored into an sk_buff and queued up for later - * evaluation. - */ -static void -isdn_audio_goertzel(int *sample, modem_info *info) -{ - int sk, - sk1, - sk2; - int k, - n; - struct sk_buff *skb; - int *result; - - skb = dev_alloc_skb(sizeof(int) * NCOEFF); - if (!skb) { - printk(KERN_WARNING - "isdn_audio: Could not alloc DTMF result for ttyI%d\n", - info->line); - return; - } - result = skb_put(skb, sizeof(int) * NCOEFF); - for (k = 0; k < NCOEFF; k++) { - sk = sk1 = sk2 = 0; - for (n = 0; n < DTMF_NPOINTS; n++) { - sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2; - sk2 = sk1; - sk1 = sk; - } - /* Avoid overflows */ - sk >>= 1; - sk2 >>= 1; - /* compute |X(k)|**2 */ - /* report overflows. This should not happen. */ - /* Comment this out if desired */ - if (sk < -32768 || sk > 32767) - printk(KERN_DEBUG - "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk); - if (sk2 < -32768 || sk2 > 32767) - printk(KERN_DEBUG - "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2); - result[k] = - ((sk * sk) >> AMP_BITS) - - ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) + - ((sk2 * sk2) >> AMP_BITS); - } - skb_queue_tail(&info->dtmf_queue, skb); - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); -} - -void -isdn_audio_eval_dtmf(modem_info *info) -{ - struct sk_buff *skb; - int *result; - dtmf_state *s; - int silence; - int i; - int di; - int ch; - int grp[2]; - char what; - char *p; - int thresh; - - while ((skb = skb_dequeue(&info->dtmf_queue))) { - result = (int *) skb->data; - s = info->dtmf_state; - grp[LOGRP] = grp[HIGRP] = -1; - silence = 0; - thresh = 0; - for (i = 0; i < NCOEFF; i++) { - if (result[i] > DTMF_TRESH) { - if (result[i] > thresh) - thresh = result[i]; - } - else if (result[i] < SILENCE_TRESH) - silence++; - } - if (silence == NCOEFF) - what = ' '; - else { - if (thresh > 0) { - thresh = thresh >> 4; /* touchtones must match within 12 dB */ - for (i = 0; i < NCOEFF; i++) { - if (result[i] < thresh) - continue; /* ignore */ - /* good level found. This is allowed only one time per group */ - if (i < NCOEFF / 2) { - /* lowgroup*/ - if (grp[LOGRP] >= 0) { - // Bad. Another tone found. */ - grp[LOGRP] = -1; - break; - } - else - grp[LOGRP] = i; - } - else { /* higroup */ - if (grp[HIGRP] >= 0) { // Bad. Another tone found. */ - grp[HIGRP] = -1; - break; - } - else - grp[HIGRP] = i - NCOEFF/2; - } - } - if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { - what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]]; - if (s->last != ' ' && s->last != '.') - s->last = what; /* min. 1 non-DTMF between DTMF */ - } else - what = '.'; - } - else - what = '.'; - } - if ((what != s->last) && (what != ' ') && (what != '.')) { - printk(KERN_DEBUG "dtmf: tt='%c'\n", what); - p = skb->data; - *p++ = 0x10; - *p = what; - skb_trim(skb, 2); - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; - di = info->isdn_driver; - ch = info->isdn_channel; - __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); - dev->drv[di]->rcvcount[ch] += 2; - /* Schedule dequeuing */ - if ((dev->modempoll) && (info->rcvsched)) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); - } else - kfree_skb(skb); - s->last = what; - } -} - -/* - * Decode DTMF tones, queue result in separate sk_buf for - * later examination. - * Parameters: - * s = pointer to state-struct. - * buf = input audio data - * len = size of audio data. - * fmt = audio data format (0 = ulaw, 1 = alaw) - */ -void -isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt) -{ - dtmf_state *s = info->dtmf_state; - int i; - int c; - - while (len) { - c = DTMF_NPOINTS - s->idx; - if (c > len) - c = len; - if (c <= 0) - break; - for (i = 0; i < c; i++) { - if (fmt) - s->buf[s->idx++] = - isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS); - else - s->buf[s->idx++] = - isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS); - } - if (s->idx == DTMF_NPOINTS) { - isdn_audio_goertzel(s->buf, info); - s->idx = 0; - } - len -= c; - } -} - -silence_state * -isdn_audio_silence_init(silence_state *s) -{ - if (!s) - s = kmalloc(sizeof(silence_state), GFP_ATOMIC); - if (s) { - s->idx = 0; - s->state = 0; - } - return s; -} - -void -isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt) -{ - silence_state *s = info->silence_state; - int i; - signed char c; - - if (!info->emu.vpar[1]) return; - - for (i = 0; i < len; i++) { - if (fmt) - c = isdn_audio_alaw_to_ulaw[*buf++]; - else - c = *buf++; - - if (c > 0) c -= 128; - c = abs(c); - - if (c > (info->emu.vpar[1] * 4)) { - s->idx = 0; - s->state = 1; - } else { - if (s->idx < 210000) s->idx++; - } - } -} - -void -isdn_audio_put_dle_code(modem_info *info, u_char code) -{ - struct sk_buff *skb; - int di; - int ch; - char *p; - - skb = dev_alloc_skb(2); - if (!skb) { - printk(KERN_WARNING - "isdn_audio: Could not alloc skb for ttyI%d\n", - info->line); - return; - } - p = skb_put(skb, 2); - p[0] = 0x10; - p[1] = code; - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; - di = info->isdn_driver; - ch = info->isdn_channel; - __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); - dev->drv[di]->rcvcount[ch] += 2; - /* Schedule dequeuing */ - if ((dev->modempoll) && (info->rcvsched)) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); -} - -void -isdn_audio_eval_silence(modem_info *info) -{ - silence_state *s = info->silence_state; - char what; - - what = ' '; - - if (s->idx > (info->emu.vpar[2] * 800)) { - s->idx = 0; - if (!s->state) { /* silence from beginning of rec */ - what = 's'; - } else { - what = 'q'; - } - } - if ((what == 's') || (what == 'q')) { - printk(KERN_DEBUG "ttyI%d: %s\n", info->line, - (what == 's') ? "silence" : "quiet"); - isdn_audio_put_dle_code(info, what); - } -} diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h deleted file mode 100644 index 013c3582e0d1..000000000000 --- a/drivers/isdn/i4l/isdn_audio.h +++ /dev/null @@ -1,44 +0,0 @@ -/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $ - * - * Linux ISDN subsystem, audio conversion and compression (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */ -typedef struct adpcm_state { - int a; - int d; - int word; - int nleft; - int nbits; -} adpcm_state; - -typedef struct dtmf_state { - char last; - char llast; - int idx; - int buf[DTMF_NPOINTS]; -} dtmf_state; - -typedef struct silence_state { - int state; - unsigned int idx; -} silence_state; - -extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); -extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); -extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); -extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); -extern void isdn_audio_eval_dtmf(modem_info *); -dtmf_state *isdn_audio_dtmf_init(dtmf_state *); -extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int); -extern void isdn_audio_eval_silence(modem_info *); -silence_state *isdn_audio_silence_init(silence_state *); -extern void isdn_audio_put_dle_code(modem_info *, u_char); diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c deleted file mode 100644 index 7f28b967ed19..000000000000 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - * BSD compression module - * - * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp - * The whole module is now SKB based. - * - */ - -/* - * Update: The Berkeley copyright was changed, and the change - * is retroactive to all "true" BSD software (ie everything - * from UCB as opposed to other peoples code that just carried - * the same license). The new copyright doesn't clash with the - * GPL, so the module-only restriction has been removed.. - */ - -/* - * Original copyright notice: - * - * Copyright (c) 1985, 1986 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * James A. Woods, derived from original work by Spencer Thomas - * and Joseph Orost. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* used in new tty drivers */ -#include /* used in new tty drivers */ -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "isdn_ppp.h" - -MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN"); -MODULE_LICENSE("Dual BSD/GPL"); - -#define BSD_VERSION(x) ((x) >> 5) -#define BSD_NBITS(x) ((x) & 0x1F) - -#define BSD_CURRENT_VERSION 1 - -#define DEBUG 1 - -/* - * A dictionary for doing BSD compress. - */ - -struct bsd_dict { - u32 fcode; - u16 codem1; /* output of hash table -1 */ - u16 cptr; /* map code to hash table entry */ -}; - -struct bsd_db { - int totlen; /* length of this structure */ - unsigned int hsize; /* size of the hash table */ - unsigned char hshift; /* used in hash function */ - unsigned char n_bits; /* current bits/code */ - unsigned char maxbits; /* maximum bits/code */ - unsigned char debug; /* non-zero if debug desired */ - unsigned char unit; /* ppp unit number */ - u16 seqno; /* sequence # of next packet */ - unsigned int mru; /* size of receive (decompress) bufr */ - unsigned int maxmaxcode; /* largest valid code */ - unsigned int max_ent; /* largest code in use */ - unsigned int in_count; /* uncompressed bytes, aged */ - unsigned int bytes_out; /* compressed bytes, aged */ - unsigned int ratio; /* recent compression ratio */ - unsigned int checkpoint; /* when to next check the ratio */ - unsigned int clear_count; /* times dictionary cleared */ - unsigned int incomp_count; /* incompressible packets */ - unsigned int incomp_bytes; /* incompressible bytes */ - unsigned int uncomp_count; /* uncompressed packets */ - unsigned int uncomp_bytes; /* uncompressed bytes */ - unsigned int comp_count; /* compressed packets */ - unsigned int comp_bytes; /* compressed bytes */ - unsigned short *lens; /* array of lengths of codes */ - struct bsd_dict *dict; /* dictionary */ - int xmit; -}; - -#define BSD_OVHD 2 /* BSD compress overhead/packet */ -#define MIN_BSD_BITS 9 -#define BSD_INIT_BITS MIN_BSD_BITS -#define MAX_BSD_BITS 15 - -/* - * the next two codes should not be changed lightly, as they must not - * lie within the contiguous general code space. - */ -#define CLEAR 256 /* table clear output code */ -#define FIRST 257 /* first free entry */ -#define LAST 255 - -#define MAXCODE(b) ((1 << (b)) - 1) -#define BADCODEM1 MAXCODE(MAX_BSD_BITS) - -#define BSD_HASH(prefix, suffix, hshift) ((((unsigned long)(suffix)) << (hshift)) \ - ^ (unsigned long)(prefix)) -#define BSD_KEY(prefix, suffix) ((((unsigned long)(suffix)) << 16) \ - + (unsigned long)(prefix)) - -#define CHECK_GAP 10000 /* Ratio check interval */ - -#define RATIO_SCALE_LOG 8 -#define RATIO_SCALE (1 << RATIO_SCALE_LOG) -#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG) - -/* - * clear the dictionary - */ - -static void bsd_clear(struct bsd_db *db) -{ - db->clear_count++; - db->max_ent = FIRST - 1; - db->n_bits = BSD_INIT_BITS; - db->bytes_out = 0; - db->in_count = 0; - db->incomp_count = 0; - db->ratio = 0; - db->checkpoint = CHECK_GAP; -} - -/* - * If the dictionary is full, then see if it is time to reset it. - * - * Compute the compression ratio using fixed-point arithmetic - * with 8 fractional bits. - * - * Since we have an infinite stream instead of a single file, - * watch only the local compression ratio. - * - * Since both peers must reset the dictionary at the same time even in - * the absence of CLEAR codes (while packets are incompressible), they - * must compute the same ratio. - */ -static int bsd_check(struct bsd_db *db) /* 1=output CLEAR */ -{ - unsigned int new_ratio; - - if (db->in_count >= db->checkpoint) - { - /* age the ratio by limiting the size of the counts */ - if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) - { - db->in_count -= (db->in_count >> 2); - db->bytes_out -= (db->bytes_out >> 2); - } - - db->checkpoint = db->in_count + CHECK_GAP; - - if (db->max_ent >= db->maxmaxcode) - { - /* Reset the dictionary only if the ratio is worse, - * or if it looks as if it has been poisoned - * by incompressible data. - * - * This does not overflow, because - * db->in_count <= RATIO_MAX. - */ - - new_ratio = db->in_count << RATIO_SCALE_LOG; - if (db->bytes_out != 0) - { - new_ratio /= db->bytes_out; - } - - if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) - { - bsd_clear(db); - return 1; - } - db->ratio = new_ratio; - } - } - return 0; -} - -/* - * Return statistics. - */ - -static void bsd_stats(void *state, struct compstat *stats) -{ - struct bsd_db *db = (struct bsd_db *) state; - - stats->unc_bytes = db->uncomp_bytes; - stats->unc_packets = db->uncomp_count; - stats->comp_bytes = db->comp_bytes; - stats->comp_packets = db->comp_count; - stats->inc_bytes = db->incomp_bytes; - stats->inc_packets = db->incomp_count; - stats->in_count = db->in_count; - stats->bytes_out = db->bytes_out; -} - -/* - * Reset state, as on a CCP ResetReq. - */ -static void bsd_reset(void *state, unsigned char code, unsigned char id, - unsigned char *data, unsigned len, - struct isdn_ppp_resetparams *rsparm) -{ - struct bsd_db *db = (struct bsd_db *) state; - - bsd_clear(db); - db->seqno = 0; - db->clear_count = 0; -} - -/* - * Release the compression structure - */ -static void bsd_free(void *state) -{ - struct bsd_db *db = (struct bsd_db *) state; - - if (db) { - /* - * Release the dictionary - */ - vfree(db->dict); - db->dict = NULL; - - /* - * Release the string buffer - */ - vfree(db->lens); - db->lens = NULL; - - /* - * Finally release the structure itself. - */ - kfree(db); - } -} - - -/* - * Allocate space for a (de) compressor. - */ -static void *bsd_alloc(struct isdn_ppp_comp_data *data) -{ - int bits; - unsigned int hsize, hshift, maxmaxcode; - struct bsd_db *db; - int decomp; - - static unsigned int htab[][2] = { - { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , - { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 } - }; - - if (data->optlen != 1 || data->num != CI_BSD_COMPRESS - || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION) - return NULL; - - bits = BSD_NBITS(data->options[0]); - - if (bits < 9 || bits > 15) - return NULL; - - hsize = htab[bits - 9][0]; - hshift = htab[bits - 9][1]; - - /* - * Allocate the main control structure for this instance. - */ - maxmaxcode = MAXCODE(bits); - db = kzalloc(sizeof(struct bsd_db), GFP_KERNEL); - if (!db) - return NULL; - - db->xmit = data->flags & IPPP_COMP_FLAG_XMIT; - decomp = db->xmit ? 0 : 1; - - /* - * Allocate space for the dictionary. This may be more than one page in - * length. - */ - db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict))); - if (!db->dict) { - bsd_free(db); - return NULL; - } - - /* - * If this is the compression buffer then there is no length data. - * For decompression, the length information is needed as well. - */ - if (!decomp) - db->lens = NULL; - else { - db->lens = vmalloc(array_size(sizeof(db->lens[0]), - maxmaxcode + 1)); - if (!db->lens) { - bsd_free(db); - return (NULL); - } - } - - /* - * Initialize the data information for the compression code - */ - db->totlen = sizeof(struct bsd_db) + (sizeof(struct bsd_dict) * hsize); - db->hsize = hsize; - db->hshift = hshift; - db->maxmaxcode = maxmaxcode; - db->maxbits = bits; - - return (void *)db; -} - -/* - * Initialize the database. - */ -static int bsd_init(void *state, struct isdn_ppp_comp_data *data, int unit, int debug) -{ - struct bsd_db *db = state; - int indx; - int decomp; - - if (!state || !data) { - printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n", unit, (long)state, (long)data); - return 0; - } - - decomp = db->xmit ? 0 : 1; - - if (data->optlen != 1 || data->num != CI_BSD_COMPRESS - || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION) - || (BSD_NBITS(data->options[0]) != db->maxbits) - || (decomp && db->lens == NULL)) { - printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n", data->optlen, data->num, data->options[0], decomp, (unsigned long)db->lens); - return 0; - } - - if (decomp) - for (indx = LAST; indx >= 0; indx--) - db->lens[indx] = 1; - - indx = db->hsize; - while (indx-- != 0) { - db->dict[indx].codem1 = BADCODEM1; - db->dict[indx].cptr = 0; - } - - db->unit = unit; - db->mru = 0; - - db->debug = 1; - - bsd_reset(db, 0, 0, NULL, 0, NULL); - - return 1; -} - -/* - * Obtain pointers to the various structures in the compression tables - */ - -#define dict_ptrx(p, idx) &(p->dict[idx]) -#define lens_ptrx(p, idx) &(p->lens[idx]) - -#ifdef DEBUG -static unsigned short *lens_ptr(struct bsd_db *db, int idx) -{ - if ((unsigned int) idx > (unsigned int) db->maxmaxcode) { - printk(KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx); - idx = 0; - } - return lens_ptrx(db, idx); -} - -static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx) -{ - if ((unsigned int) idx >= (unsigned int) db->hsize) { - printk(KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx); - idx = 0; - } - return dict_ptrx(db, idx); -} - -#else -#define lens_ptr(db, idx) lens_ptrx(db, idx) -#define dict_ptr(db, idx) dict_ptrx(db, idx) -#endif - -/* - * compress a packet - */ -static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, int proto) -{ - struct bsd_db *db; - int hshift; - unsigned int max_ent; - unsigned int n_bits; - unsigned int bitno; - unsigned long accm; - int ent; - unsigned long fcode; - struct bsd_dict *dictp; - unsigned char c; - int hval, disp, ilen, mxcode; - unsigned char *rptr = skb_in->data; - int isize = skb_in->len; - -#define OUTPUT(ent) \ - { \ - bitno -= n_bits; \ - accm |= ((ent) << bitno); \ - do { \ - if (skb_out && skb_tailroom(skb_out) > 0) \ - skb_put_u8(skb_out, (u8)(accm >> 24)); \ - accm <<= 8; \ - bitno += 8; \ - } while (bitno <= 24); \ - } - - /* - * If the protocol is not in the range we're interested in, - * just return without compressing the packet. If it is, - * the protocol becomes the first byte to compress. - */ - printk(KERN_DEBUG "bsd_compress called with %x\n", proto); - - ent = proto; - if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1)) - return 0; - - db = (struct bsd_db *) state; - hshift = db->hshift; - max_ent = db->max_ent; - n_bits = db->n_bits; - bitno = 32; - accm = 0; - mxcode = MAXCODE(n_bits); - - /* This is the PPP header information */ - if (skb_out && skb_tailroom(skb_out) >= 2) { - char *v = skb_put(skb_out, 2); - /* we only push our own data on the header, - AC,PC and protos is pushed by caller */ - v[0] = db->seqno >> 8; - v[1] = db->seqno; - } - - ilen = ++isize; /* This is off by one, but that is what is in draft! */ - - while (--ilen > 0) { - c = *rptr++; - fcode = BSD_KEY(ent, c); - hval = BSD_HASH(ent, c, hshift); - dictp = dict_ptr(db, hval); - - /* Validate and then check the entry. */ - if (dictp->codem1 >= max_ent) - goto nomatch; - - if (dictp->fcode == fcode) { - ent = dictp->codem1 + 1; - continue; /* found (prefix,suffix) */ - } - - /* continue probing until a match or invalid entry */ - disp = (hval == 0) ? 1 : hval; - - do { - hval += disp; - if (hval >= db->hsize) - hval -= db->hsize; - dictp = dict_ptr(db, hval); - if (dictp->codem1 >= max_ent) - goto nomatch; - } while (dictp->fcode != fcode); - - ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ - continue; - - nomatch: - OUTPUT(ent); /* output the prefix */ - - /* code -> hashtable */ - if (max_ent < db->maxmaxcode) { - struct bsd_dict *dictp2; - struct bsd_dict *dictp3; - int indx; - - /* expand code size if needed */ - if (max_ent >= mxcode) { - db->n_bits = ++n_bits; - mxcode = MAXCODE(n_bits); - } - - /* - * Invalidate old hash table entry using - * this code, and then take it over. - */ - dictp2 = dict_ptr(db, max_ent + 1); - indx = dictp2->cptr; - dictp3 = dict_ptr(db, indx); - - if (dictp3->codem1 == max_ent) - dictp3->codem1 = BADCODEM1; - - dictp2->cptr = hval; - dictp->codem1 = max_ent; - dictp->fcode = fcode; - db->max_ent = ++max_ent; - - if (db->lens) { - unsigned short *len1 = lens_ptr(db, max_ent); - unsigned short *len2 = lens_ptr(db, ent); - *len1 = *len2 + 1; - } - } - ent = c; - } - - OUTPUT(ent); /* output the last code */ - - if (skb_out) - db->bytes_out += skb_out->len; /* Do not count bytes from here */ - db->uncomp_bytes += isize; - db->in_count += isize; - ++db->uncomp_count; - ++db->seqno; - - if (bitno < 32) - ++db->bytes_out; /* must be set before calling bsd_check */ - - /* - * Generate the clear command if needed - */ - - if (bsd_check(db)) - OUTPUT(CLEAR); - - /* - * Pad dribble bits of last code with ones. - * Do not emit a completely useless byte of ones. - */ - if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) - skb_put_u8(skb_out, - (unsigned char)((accm | (0xff << (bitno - 8))) >> 24)); - - /* - * Increase code size if we would have without the packet - * boundary because the decompressor will do so. - */ - if (max_ent >= mxcode && max_ent < db->maxmaxcode) - db->n_bits++; - - /* If output length is too large then this is an incompressible frame. */ - if (!skb_out || skb_out->len >= skb_in->len) { - ++db->incomp_count; - db->incomp_bytes += isize; - return 0; - } - - /* Count the number of compressed frames */ - ++db->comp_count; - db->comp_bytes += skb_out->len; - return skb_out->len; - -#undef OUTPUT -} - -/* - * Update the "BSD Compress" dictionary on the receiver for - * incompressible data by pretending to compress the incoming data. - */ -static void bsd_incomp(void *state, struct sk_buff *skb_in, int proto) -{ - bsd_compress(state, skb_in, NULL, proto); -} - -/* - * Decompress "BSD Compress". - */ -static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, - struct isdn_ppp_resetparams *rsparm) -{ - struct bsd_db *db; - unsigned int max_ent; - unsigned long accm; - unsigned int bitno; /* 1st valid bit in accm */ - unsigned int n_bits; - unsigned int tgtbitno; /* bitno when we have a code */ - struct bsd_dict *dictp; - int seq; - unsigned int incode; - unsigned int oldcode; - unsigned int finchar; - unsigned char *p, *ibuf; - int ilen; - int codelen; - int extra; - - db = (struct bsd_db *) state; - max_ent = db->max_ent; - accm = 0; - bitno = 32; /* 1st valid bit in accm */ - n_bits = db->n_bits; - tgtbitno = 32 - n_bits; /* bitno when we have a code */ - - printk(KERN_DEBUG "bsd_decompress called\n"); - - if (!skb_in || !skb_out) { - printk(KERN_ERR "bsd_decompress called with NULL parameter\n"); - return DECOMP_ERROR; - } - - /* - * Get the sequence number. - */ - if ((p = skb_pull(skb_in, 2)) == NULL) { - return DECOMP_ERROR; - } - p -= 2; - seq = (p[0] << 8) + p[1]; - ilen = skb_in->len; - ibuf = skb_in->data; - - /* - * Check the sequence number and give up if it differs from - * the value we're expecting. - */ - if (seq != db->seqno) { - if (db->debug) { - printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n", - db->unit, seq, db->seqno - 1); - } - return DECOMP_ERROR; - } - - ++db->seqno; - db->bytes_out += ilen; - - if (skb_tailroom(skb_out) > 0) - skb_put_u8(skb_out, 0); - else - return DECOMP_ERR_NOMEM; - - oldcode = CLEAR; - - /* - * Keep the checkpoint correctly so that incompressible packets - * clear the dictionary at the proper times. - */ - - for (;;) { - if (ilen-- <= 0) { - db->in_count += (skb_out->len - 1); /* don't count the header */ - break; - } - - /* - * Accumulate bytes until we have a complete code. - * Then get the next code, relying on the 32-bit, - * unsigned accm to mask the result. - */ - - bitno -= 8; - accm |= *ibuf++ << bitno; - if (tgtbitno < bitno) - continue; - - incode = accm >> tgtbitno; - accm <<= n_bits; - bitno += n_bits; - - /* - * The dictionary must only be cleared at the end of a packet. - */ - - if (incode == CLEAR) { - if (ilen > 0) { - if (db->debug) - printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit); - return DECOMP_FATALERROR; /* probably a bug */ - } - bsd_clear(db); - break; - } - - if ((incode > max_ent + 2) || (incode > db->maxmaxcode) - || (incode > max_ent && oldcode == CLEAR)) { - if (db->debug) { - printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ", - db->unit, incode, oldcode); - printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n", - max_ent, skb_out->len, db->seqno); - } - return DECOMP_FATALERROR; /* probably a bug */ - } - - /* Special case for KwKwK string. */ - if (incode > max_ent) { - finchar = oldcode; - extra = 1; - } else { - finchar = incode; - extra = 0; - } - - codelen = *(lens_ptr(db, finchar)); - if (skb_tailroom(skb_out) < codelen + extra) { - if (db->debug) { - printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit); -#ifdef DEBUG - printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n", - ilen, finchar, codelen, skb_out->len); -#endif - } - return DECOMP_FATALERROR; - } - - /* - * Decode this code and install it in the decompressed buffer. - */ - - p = skb_put(skb_out, codelen); - p += codelen; - while (finchar > LAST) { - struct bsd_dict *dictp2 = dict_ptr(db, finchar); - - dictp = dict_ptr(db, dictp2->cptr); - -#ifdef DEBUG - if (--codelen <= 0 || dictp->codem1 != finchar - 1) { - if (codelen <= 0) { - printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit); - printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent); - } else { - if (dictp->codem1 != finchar - 1) { - printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar); - printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1); - } - } - return DECOMP_FATALERROR; - } -#endif - - { - u32 fcode = dictp->fcode; - *--p = (fcode >> 16) & 0xff; - finchar = fcode & 0xffff; - } - } - *--p = finchar; - -#ifdef DEBUG - if (--codelen != 0) - printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent); -#endif - - if (extra) /* the KwKwK case again */ - skb_put_u8(skb_out, finchar); - - /* - * If not first code in a packet, and - * if not out of code space, then allocate a new code. - * - * Keep the hash table correct so it can be used - * with uncompressed packets. - */ - if (oldcode != CLEAR && max_ent < db->maxmaxcode) { - struct bsd_dict *dictp2, *dictp3; - u16 *lens1, *lens2; - unsigned long fcode; - int hval, disp, indx; - - fcode = BSD_KEY(oldcode, finchar); - hval = BSD_HASH(oldcode, finchar, db->hshift); - dictp = dict_ptr(db, hval); - - /* look for a free hash table entry */ - if (dictp->codem1 < max_ent) { - disp = (hval == 0) ? 1 : hval; - do { - hval += disp; - if (hval >= db->hsize) - hval -= db->hsize; - dictp = dict_ptr(db, hval); - } while (dictp->codem1 < max_ent); - } - - /* - * Invalidate previous hash table entry - * assigned this code, and then take it over - */ - - dictp2 = dict_ptr(db, max_ent + 1); - indx = dictp2->cptr; - dictp3 = dict_ptr(db, indx); - - if (dictp3->codem1 == max_ent) - dictp3->codem1 = BADCODEM1; - - dictp2->cptr = hval; - dictp->codem1 = max_ent; - dictp->fcode = fcode; - db->max_ent = ++max_ent; - - /* Update the length of this string. */ - lens1 = lens_ptr(db, max_ent); - lens2 = lens_ptr(db, oldcode); - *lens1 = *lens2 + 1; - - /* Expand code size if needed. */ - if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) { - db->n_bits = ++n_bits; - tgtbitno = 32-n_bits; - } - } - oldcode = incode; - } - - ++db->comp_count; - ++db->uncomp_count; - db->comp_bytes += skb_in->len - BSD_OVHD; - db->uncomp_bytes += skb_out->len; - - if (bsd_check(db)) { - if (db->debug) - printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n", - db->unit, db->seqno - 1); - } - return skb_out->len; -} - -/************************************************************* - * Table of addresses for the BSD compression module - *************************************************************/ - -static struct isdn_ppp_compressor ippp_bsd_compress = { - .owner = THIS_MODULE, - .num = CI_BSD_COMPRESS, - .alloc = bsd_alloc, - .free = bsd_free, - .init = bsd_init, - .reset = bsd_reset, - .compress = bsd_compress, - .decompress = bsd_decompress, - .incomp = bsd_incomp, - .stat = bsd_stats, -}; - -/************************************************************* - * Module support routines - *************************************************************/ - -static int __init isdn_bsdcomp_init(void) -{ - int answer = isdn_ppp_register_compressor(&ippp_bsd_compress); - if (answer == 0) - printk(KERN_INFO "PPP BSD Compression module registered\n"); - return answer; -} - -static void __exit isdn_bsdcomp_exit(void) -{ - isdn_ppp_unregister_compressor(&ippp_bsd_compress); -} - -module_init(isdn_bsdcomp_init); -module_exit(isdn_bsdcomp_exit); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c deleted file mode 100644 index 74ee00f5b310..000000000000 --- a/drivers/isdn/i4l/isdn_common.c +++ /dev/null @@ -1,2368 +0,0 @@ -/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ - * - * Linux ISDN subsystem, common used functions (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "isdn_common.h" -#include "isdn_tty.h" -#include "isdn_net.h" -#include "isdn_ppp.h" -#ifdef CONFIG_ISDN_AUDIO -#include "isdn_audio.h" -#endif -#ifdef CONFIG_ISDN_DIVERSION_MODULE -#define CONFIG_ISDN_DIVERSION -#endif -#ifdef CONFIG_ISDN_DIVERSION -#include -#endif /* CONFIG_ISDN_DIVERSION */ -#include "isdn_v110.h" - -/* Debugflags */ -#undef ISDN_DEBUG_STATCALLB - -MODULE_DESCRIPTION("ISDN4Linux: link layer"); -MODULE_AUTHOR("Fritz Elfert"); -MODULE_LICENSE("GPL"); - -isdn_dev *dev; - -static DEFINE_MUTEX(isdn_mutex); -static char *isdn_revision = "$Revision: 1.1.2.3 $"; - -extern char *isdn_net_revision; -#ifdef CONFIG_ISDN_PPP -extern char *isdn_ppp_revision; -#else -static char *isdn_ppp_revision = ": none $"; -#endif -#ifdef CONFIG_ISDN_AUDIO -extern char *isdn_audio_revision; -#else -static char *isdn_audio_revision = ": none $"; -#endif -extern char *isdn_v110_revision; - -#ifdef CONFIG_ISDN_DIVERSION -static isdn_divert_if *divert_if; /* = NULL */ -#endif /* CONFIG_ISDN_DIVERSION */ - - -static int isdn_writebuf_stub(int, int, const u_char __user *, int); -static void set_global_features(void); -static int isdn_wildmat(char *s, char *p); -static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding); - -static inline void -isdn_lock_driver(isdn_driver_t *drv) -{ - try_module_get(drv->interface->owner); - drv->locks++; -} - -void -isdn_lock_drivers(void) -{ - int i; - - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (!dev->drv[i]) - continue; - isdn_lock_driver(dev->drv[i]); - } -} - -static inline void -isdn_unlock_driver(isdn_driver_t *drv) -{ - if (drv->locks > 0) { - drv->locks--; - module_put(drv->interface->owner); - } -} - -void -isdn_unlock_drivers(void) -{ - int i; - - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (!dev->drv[i]) - continue; - isdn_unlock_driver(dev->drv[i]); - } -} - -#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -void -isdn_dumppkt(char *s, u_char *p, int len, int dumplen) -{ - int dumpc; - - printk(KERN_DEBUG "%s(%d) ", s, len); - for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++) - printk(" %02x", *p++); - printk("\n"); -} -#endif - -/* - * I picked the pattern-matching-functions from an old GNU-tar version (1.10) - * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) - */ -static int -isdn_star(char *s, char *p) -{ - while (isdn_wildmat(s, p)) { - if (*++s == '\0') - return (2); - } - return (0); -} - -/* - * Shell-type Pattern-matching for incoming caller-Ids - * This function gets a string in s and checks, if it matches the pattern - * given in p. - * - * Return: - * 0 = match. - * 1 = no match. - * 2 = no match. Would eventually match, if s would be longer. - * - * Possible Patterns: - * - * '?' matches one character - * '*' matches zero or more characters - * [xyz] matches the set of characters in brackets. - * [^xyz] matches any single character not in the set of characters - */ - -static int -isdn_wildmat(char *s, char *p) -{ - register int last; - register int matched; - register int reverse; - register int nostar = 1; - - if (!(*s) && !(*p)) - return (1); - for (; *p; s++, p++) - switch (*p) { - case '\\': - /* Literal match with following character. */ - p++; - /* fall through */ - default: - if (*s != *p) - return (*s == '\0') ? 2 : 1; - continue; - case '?': - /* Match anything. */ - if (*s == '\0') - return (2); - continue; - case '*': - nostar = 0; - /* Trailing star matches everything. */ - return (*++p ? isdn_star(s, p) : 0); - case '[': - /* [^....] means inverse character class. */ - if ((reverse = (p[1] == '^'))) - p++; - for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) - /* This next line requires a good C compiler. */ - if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) - matched = 1; - if (matched == reverse) - return (1); - continue; - } - return (*s == '\0') ? 0 : nostar; -} - -int isdn_msncmp(const char *msn1, const char *msn2) -{ - char TmpMsn1[ISDN_MSNLEN]; - char TmpMsn2[ISDN_MSNLEN]; - char *p; - - for (p = TmpMsn1; *msn1 && *msn1 != ':';) // Strip off a SPID - *p++ = *msn1++; - *p = '\0'; - - for (p = TmpMsn2; *msn2 && *msn2 != ':';) // Strip off a SPID - *p++ = *msn2++; - *p = '\0'; - - return isdn_wildmat(TmpMsn1, TmpMsn2); -} - -int -isdn_dc2minor(int di, int ch) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->chanmap[i] == ch && dev->drvmap[i] == di) - return i; - return -1; -} - -static int isdn_timer_cnt1 = 0; -static int isdn_timer_cnt2 = 0; -static int isdn_timer_cnt3 = 0; - -static void -isdn_timer_funct(struct timer_list *unused) -{ - int tf = dev->tflags; - if (tf & ISDN_TIMER_FAST) { - if (tf & ISDN_TIMER_MODEMREAD) - isdn_tty_readmodem(); - if (tf & ISDN_TIMER_MODEMPLUS) - isdn_tty_modem_escape(); - if (tf & ISDN_TIMER_MODEMXMIT) - isdn_tty_modem_xmit(); - } - if (tf & ISDN_TIMER_SLOW) { - if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) { - isdn_timer_cnt1 = 0; - if (tf & ISDN_TIMER_NETDIAL) - isdn_net_dial(); - } - if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { - isdn_timer_cnt2 = 0; - if (tf & ISDN_TIMER_NETHANGUP) - isdn_net_autohup(); - if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) { - isdn_timer_cnt3 = 0; - if (tf & ISDN_TIMER_MODEMRING) - isdn_tty_modem_ring(); - } - if (tf & ISDN_TIMER_CARRIER) - isdn_tty_carrier_timeout(); - } - } - if (tf) - mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES); -} - -void -isdn_timer_ctrl(int tf, int onoff) -{ - unsigned long flags; - int old_tflags; - - spin_lock_irqsave(&dev->timerlock, flags); - if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) { - /* If the slow-timer wasn't activated until now */ - isdn_timer_cnt1 = 0; - isdn_timer_cnt2 = 0; - } - old_tflags = dev->tflags; - if (onoff) - dev->tflags |= tf; - else - dev->tflags &= ~tf; - if (dev->tflags && !old_tflags) - mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES); - spin_unlock_irqrestore(&dev->timerlock, flags); -} - -/* - * Receive a packet from B-Channel. (Called from low-level-module) - */ -static void -isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) -{ - int i; - - if ((i = isdn_dc2minor(di, channel)) == -1) { - dev_kfree_skb(skb); - return; - } - /* Update statistics */ - dev->ibytes[i] += skb->len; - - /* First, try to deliver data to network-device */ - if (isdn_net_rcv_skb(i, skb)) - return; - - /* V.110 handling - * makes sense for async streams only, so it is - * called after possible net-device delivery. - */ - if (dev->v110[i]) { - atomic_inc(&dev->v110use[i]); - skb = isdn_v110_decode(dev->v110[i], skb); - atomic_dec(&dev->v110use[i]); - if (!skb) - return; - } - - /* No network-device found, deliver to tty or raw-channel */ - if (skb->len) { - if (isdn_tty_rcv_skb(i, di, channel, skb)) - return; - wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]); - } else - dev_kfree_skb(skb); -} - -/* - * Intercept command from Linklevel to Lowlevel. - * If layer 2 protocol is V.110 and this is not supported by current - * lowlevel-driver, use driver's transparent mode and handle V.110 in - * linklevel instead. - */ -int -isdn_command(isdn_ctrl *cmd) -{ - if (cmd->driver == -1) { - printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command); - return (1); - } - if (!dev->drv[cmd->driver]) { - printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n", - cmd->command, cmd->driver); - return (1); - } - if (!dev->drv[cmd->driver]->interface) { - printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n", - cmd->command, cmd->driver); - return (1); - } - if (cmd->command == ISDN_CMD_SETL2) { - int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255); - unsigned long l2prot = (cmd->arg >> 8) & 255; - unsigned long features = (dev->drv[cmd->driver]->interface->features - >> ISDN_FEATURE_L2_SHIFT) & - ISDN_FEATURE_L2_MASK; - unsigned long l2_feature = (1 << l2prot); - - switch (l2prot) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - /* If V.110 requested, but not supported by - * HL-driver, set emulator-flag and change - * Layer-2 to transparent - */ - if (!(features & l2_feature)) { - dev->v110emu[idx] = l2prot; - cmd->arg = (cmd->arg & 255) | - (ISDN_PROTO_L2_TRANS << 8); - } else - dev->v110emu[idx] = 0; - } - } - return dev->drv[cmd->driver]->interface->command(cmd); -} - -void -isdn_all_eaz(int di, int ch) -{ - isdn_ctrl cmd; - - if (di < 0) - return; - cmd.driver = di; - cmd.arg = ch; - cmd.command = ISDN_CMD_SETEAZ; - cmd.parm.num[0] = '\0'; - isdn_command(&cmd); -} - -/* - * Begin of a CAPI like LL<->HL interface, currently used only for - * supplementary service (CAPI 2.0 part III) - */ -#include - -static int -isdn_capi_rec_hl_msg(capi_msg *cm) -{ - switch (cm->Command) { - case CAPI_FACILITY: - /* in the moment only handled in tty */ - return (isdn_tty_capi_facility(cm)); - default: - return (-1); - } -} - -static int -isdn_status_callback(isdn_ctrl *c) -{ - int di; - u_long flags; - int i; - int r; - int retval = 0; - isdn_ctrl cmd; - isdn_net_dev *p; - - di = c->driver; - i = isdn_dc2minor(di, c->arg); - switch (c->command) { - case ISDN_STAT_BSENT: - if (i < 0) - return -1; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (isdn_net_stat_callback(i, c)) - return 0; - if (isdn_v110_stat_callback(i, c)) - return 0; - if (isdn_tty_stat_callback(i, c)) - return 0; - wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); - break; - case ISDN_STAT_STAVAIL: - dev->drv[di]->stavail += c->arg; - wake_up_interruptible(&dev->drv[di]->st_waitq); - break; - case ISDN_STAT_RUN: - dev->drv[di]->flags |= DRV_FLAG_RUNNING; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->drvmap[i] == di) - isdn_all_eaz(di, dev->chanmap[i]); - set_global_features(); - break; - case ISDN_STAT_STOP: - dev->drv[di]->flags &= ~DRV_FLAG_RUNNING; - break; - case ISDN_STAT_ICALL: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); - return 0; - } - /* Try to find a network-interface which will accept incoming call */ - r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup)); - switch (r) { - case 0: - /* No network-device replies. - * Try ttyI's. - * These return 0 on no match, 1 on match and - * 3 on eventually match, if CID is longer. - */ - if (c->command == ISDN_STAT_ICALL) - if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return (retval); -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - if ((retval = divert_if->stat_callback(c))) - return (retval); /* processed */ -#endif /* CONFIG_ISDN_DIVERSION */ - if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) { - /* No tty responding */ - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); - retval = 2; - } - break; - case 1: - /* Schedule connection-setup */ - isdn_net_dial(); - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTD; - for (p = dev->netdev; p; p = p->next) - if (p->local->isdn_channel == cmd.arg) - { - strcpy(cmd.parm.setup.eazmsn, p->local->msn); - isdn_command(&cmd); - retval = 1; - break; - } - break; - - case 2: /* For calling back, first reject incoming call ... */ - case 3: /* Interface found, but down, reject call actively */ - retval = 2; - printk(KERN_INFO "isdn: Rejecting Call\n"); - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); - if (r == 3) - break; - /* Fall through */ - case 4: - /* ... then start callback. */ - isdn_net_dial(); - break; - case 5: - /* Number would eventually match, if longer */ - retval = 3; - break; - } -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "ICALL: ret=%d\n", retval); -#endif - return retval; - break; - case ISDN_STAT_CINF: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (strcmp(c->parm.num, "0")) - isdn_net_stat_callback(i, c); - isdn_tty_stat_callback(i, c); - break; - case ISDN_STAT_CAUSE: -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num); -#endif - printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n", - dev->drvid[di], c->arg, c->parm.num); - isdn_tty_stat_callback(i, c); -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - divert_if->stat_callback(c); -#endif /* CONFIG_ISDN_DIVERSION */ - break; - case ISDN_STAT_DISPLAY: -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display); -#endif - isdn_tty_stat_callback(i, c); -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - divert_if->stat_callback(c); -#endif /* CONFIG_ISDN_DIVERSION */ - break; - case ISDN_STAT_DCONN: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DCONN: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - /* Find any net-device, waiting for D-channel setup */ - if (isdn_net_stat_callback(i, c)) - break; - isdn_v110_stat_callback(i, c); - /* Find any ttyI, waiting for D-channel setup */ - if (isdn_tty_stat_callback(i, c)) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTB; - isdn_command(&cmd); - break; - } - break; - case ISDN_STAT_DHUP: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DHUP: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->online &= ~(1 << (c->arg)); - isdn_info_update(); - /* Signal hangup to network-devices */ - if (isdn_net_stat_callback(i, c)) - break; - isdn_v110_stat_callback(i, c); - if (isdn_tty_stat_callback(i, c)) - break; -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - divert_if->stat_callback(c); -#endif /* CONFIG_ISDN_DIVERSION */ - break; - break; - case ISDN_STAT_BCONN: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "BCONN: %ld\n", c->arg); -#endif - /* Signal B-channel-connect to network-devices */ - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->online |= (1 << (c->arg)); - isdn_info_update(); - if (isdn_net_stat_callback(i, c)) - break; - isdn_v110_stat_callback(i, c); - if (isdn_tty_stat_callback(i, c)) - break; - break; - case ISDN_STAT_BHUP: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "BHUP: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->online &= ~(1 << (c->arg)); - isdn_info_update(); -#ifdef CONFIG_ISDN_X25 - /* Signal hangup to network-devices */ - if (isdn_net_stat_callback(i, c)) - break; -#endif - isdn_v110_stat_callback(i, c); - if (isdn_tty_stat_callback(i, c)) - break; - break; - case ISDN_STAT_NODCH: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "NODCH: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (isdn_net_stat_callback(i, c)) - break; - if (isdn_tty_stat_callback(i, c)) - break; - break; - case ISDN_STAT_ADDCH: - spin_lock_irqsave(&dev->lock, flags); - if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) { - spin_unlock_irqrestore(&dev->lock, flags); - return -1; - } - spin_unlock_irqrestore(&dev->lock, flags); - isdn_info_update(); - break; - case ISDN_STAT_DISCH: - spin_lock_irqsave(&dev->lock, flags); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if ((dev->drvmap[i] == di) && - (dev->chanmap[i] == c->arg)) { - if (c->parm.num[0]) - dev->usage[i] &= ~ISDN_USAGE_DISABLED; - else - if (USG_NONE(dev->usage[i])) { - dev->usage[i] |= ISDN_USAGE_DISABLED; - } - else - retval = -1; - break; - } - spin_unlock_irqrestore(&dev->lock, flags); - isdn_info_update(); - break; - case ISDN_STAT_UNLOAD: - while (dev->drv[di]->locks > 0) { - isdn_unlock_driver(dev->drv[di]); - } - spin_lock_irqsave(&dev->lock, flags); - isdn_tty_stat_callback(i, c); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->drvmap[i] == di) { - dev->drvmap[i] = -1; - dev->chanmap[i] = -1; - dev->usage[i] &= ~ISDN_USAGE_DISABLED; - } - dev->drivers--; - dev->channels -= dev->drv[di]->channels; - kfree(dev->drv[di]->rcverr); - kfree(dev->drv[di]->rcvcount); - for (i = 0; i < dev->drv[di]->channels; i++) - skb_queue_purge(&dev->drv[di]->rpqueue[i]); - kfree(dev->drv[di]->rpqueue); - kfree(dev->drv[di]->rcv_waitq); - kfree(dev->drv[di]); - dev->drv[di] = NULL; - dev->drvid[di][0] = '\0'; - isdn_info_update(); - set_global_features(); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - case ISDN_STAT_L1ERR: - break; - case CAPI_PUT_MESSAGE: - return (isdn_capi_rec_hl_msg(&c->parm.cmsg)); -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_STAT_FAXIND: - isdn_tty_stat_callback(i, c); - break; -#endif -#ifdef CONFIG_ISDN_AUDIO - case ISDN_STAT_AUDIO: - isdn_tty_stat_callback(i, c); - break; -#endif -#ifdef CONFIG_ISDN_DIVERSION - case ISDN_STAT_PROT: - case ISDN_STAT_REDIR: - if (divert_if) - return (divert_if->stat_callback(c)); -#endif /* CONFIG_ISDN_DIVERSION */ - /* fall through */ - default: - return -1; - } - return 0; -} - -/* - * Get integer from char-pointer, set pointer to end of number - */ -int -isdn_getnum(char **p) -{ - int v = -1; - - while (*p[0] >= '0' && *p[0] <= '9') - v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0'); - return v; -} - -#define DLE 0x10 - -/* - * isdn_readbchan() tries to get data from the read-queue. - * It MUST be called with interrupts off. - * - * Be aware that this is not an atomic operation when sleep != 0, even though - * interrupts are turned off! Well, like that we are currently only called - * on behalf of a read system call on raw device files (which are documented - * to be dangerous and for debugging purpose only). The inode semaphore - * takes care that this is not called for the same minor device number while - * we are sleeping, but access is not serialized against simultaneous read() - * from the corresponding ttyI device. Can other ugly events, like changes - * of the mapping (di,ch)<->minor, happen during the sleep? --he - */ -int -isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue_head_t *sleep) -{ - int count; - int count_pull; - int count_put; - int dflag; - struct sk_buff *skb; - u_char *cp; - - if (!dev->drv[di]) - return 0; - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) { - if (sleep) - wait_event_interruptible(*sleep, - !skb_queue_empty(&dev->drv[di]->rpqueue[channel])); - else - return 0; - } - if (len > dev->drv[di]->rcvcount[channel]) - len = dev->drv[di]->rcvcount[channel]; - cp = buf; - count = 0; - while (len) { - if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) - break; -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_LOCK(skb)) - break; - ISDN_AUDIO_SKB_LOCK(skb) = 1; - if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) { - char *p = skb->data; - unsigned long DLEmask = (1 << channel); - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (len > 0)) { - len--; - if (dev->drv[di]->DLEflag & DLEmask) { - *cp++ = DLE; - dev->drv[di]->DLEflag &= ~DLEmask; - } else { - *cp++ = *p; - if (*p == DLE) { - dev->drv[di]->DLEflag |= DLEmask; - (ISDN_AUDIO_SKB_DLECOUNT(skb))--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { -#endif - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((count_pull = skb->len) > len) { - count_pull = len; - dflag = 0; - } - count_put = count_pull; - skb_copy_from_linear_data(skb, cp, count_put); - cp += count_put; - len -= count_put; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - count += count_put; - if (fp) { - memset(fp, 0, count_put); - fp += count_put; - } - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ - if (fp) - *(fp - 1) = 0xff; -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); - dev_kfree_skb(skb); - } else { - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb, count_pull); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - dev->drv[di]->rcvcount[channel] -= count_put; - } - return count; -} - -/* - * isdn_readbchan_tty() tries to get data from the read-queue. - * It MUST be called with interrupts off. - * - * Be aware that this is not an atomic operation when sleep != 0, even though - * interrupts are turned off! Well, like that we are currently only called - * on behalf of a read system call on raw device files (which are documented - * to be dangerous and for debugging purpose only). The inode semaphore - * takes care that this is not called for the same minor device number while - * we are sleeping, but access is not serialized against simultaneous read() - * from the corresponding ttyI device. Can other ugly events, like changes - * of the mapping (di,ch)<->minor, happen during the sleep? --he - */ -int -isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack) -{ - int count; - int count_pull; - int count_put; - int dflag; - struct sk_buff *skb; - char last = 0; - int len; - - if (!dev->drv[di]) - return 0; - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) - return 0; - - len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]); - if (len == 0) - return len; - - count = 0; - while (len) { - if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) - break; -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_LOCK(skb)) - break; - ISDN_AUDIO_SKB_LOCK(skb) = 1; - if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) { - char *p = skb->data; - unsigned long DLEmask = (1 << channel); - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (len > 0)) { - /* push every character but the last to the tty buffer directly */ - if (count_put) - tty_insert_flip_char(port, last, TTY_NORMAL); - len--; - if (dev->drv[di]->DLEflag & DLEmask) { - last = DLE; - dev->drv[di]->DLEflag &= ~DLEmask; - } else { - last = *p; - if (last == DLE) { - dev->drv[di]->DLEflag |= DLEmask; - (ISDN_AUDIO_SKB_DLECOUNT(skb))--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { -#endif - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((count_pull = skb->len) > len) { - count_pull = len; - dflag = 0; - } - count_put = count_pull; - if (count_put > 1) - tty_insert_flip_string(port, skb->data, count_put - 1); - last = skb->data[count_put - 1]; - len -= count_put; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - count += count_put; - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ - if (cisco_hack) - tty_insert_flip_char(port, last, 0xFF); - else - tty_insert_flip_char(port, last, TTY_NORMAL); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); - dev_kfree_skb(skb); - } else { - tty_insert_flip_char(port, last, TTY_NORMAL); - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb, count_pull); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - dev->drv[di]->rcvcount[channel] -= count_put; - } - return count; -} - - -static inline int -isdn_minor2drv(int minor) -{ - return (dev->drvmap[minor]); -} - -static inline int -isdn_minor2chan(int minor) -{ - return (dev->chanmap[minor]); -} - -static char * -isdn_statstr(void) -{ - static char istatbuf[2048]; - char *p; - int i; - - sprintf(istatbuf, "idmap:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\nchmap:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%d ", dev->chanmap[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\ndrmap:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%d ", dev->drvmap[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\nusage:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%d ", dev->usage[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\nflags:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (dev->drv[i]) { - sprintf(p, "%ld ", dev->drv[i]->online); - p = istatbuf + strlen(istatbuf); - } else { - sprintf(p, "? "); - p = istatbuf + strlen(istatbuf); - } - } - sprintf(p, "\nphone:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%s ", dev->num[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\n"); - return istatbuf; -} - -/* Module interface-code */ - -void -isdn_info_update(void) -{ - infostruct *p = dev->infochain; - - while (p) { - *(p->private) = 1; - p = (infostruct *) p->next; - } - wake_up_interruptible(&(dev->info_waitq)); -} - -static ssize_t -isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - uint minor = iminor(file_inode(file)); - int len = 0; - int drvidx; - int chidx; - int retval; - char *p; - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - wait_event_interruptible(dev->info_waitq, - file->private_data); - } - p = isdn_statstr(); - file->private_data = NULL; - if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) { - retval = -EFAULT; - goto out; - } - *off += len; - retval = len; - goto out; - } - retval = 0; - goto out; - } - if (!dev->drivers) { - retval = -ENODEV; - goto out; - } - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { - retval = -ENODEV; - goto out; - } - chidx = isdn_minor2chan(minor); - if (!(p = kmalloc(count, GFP_KERNEL))) { - retval = -ENOMEM; - goto out; - } - len = isdn_readbchan(drvidx, chidx, p, NULL, count, - &dev->drv[drvidx]->rcv_waitq[chidx]); - *off += len; - if (copy_to_user(buf, p, len)) - len = -EFAULT; - kfree(p); - retval = len; - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!dev->drv[drvidx]->stavail) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - wait_event_interruptible(dev->drv[drvidx]->st_waitq, - dev->drv[drvidx]->stavail); - } - if (dev->drv[drvidx]->interface->readstat) { - if (count > dev->drv[drvidx]->stavail) - count = dev->drv[drvidx]->stavail; - len = dev->drv[drvidx]->interface->readstat(buf, count, - drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL)); - if (len < 0) { - retval = len; - goto out; - } - } else { - len = 0; - } - if (len) - dev->drv[drvidx]->stavail -= len; - else - dev->drv[drvidx]->stavail = 0; - *off += len; - retval = len; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count); - goto out; - } -#endif - retval = -ENODEV; -out: - mutex_unlock(&isdn_mutex); - return retval; -} - -static ssize_t -isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - uint minor = iminor(file_inode(file)); - int drvidx; - int chidx; - int retval; - - if (minor == ISDN_MINOR_STATUS) - return -EPERM; - if (!dev->drivers) - return -ENODEV; - - mutex_lock(&isdn_mutex); - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { - retval = -ENODEV; - goto out; - } - chidx = isdn_minor2chan(minor); - wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx], - (retval = isdn_writebuf_stub(drvidx, chidx, buf, count))); - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - /* - * We want to use the isdnctrl device to load the firmware - * - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; - */ - if (dev->drv[drvidx]->interface->writecmd) - retval = dev->drv[drvidx]->interface-> - writecmd(buf, count, drvidx, - isdn_minor2chan(minor - ISDN_MINOR_CTRL)); - else - retval = count; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count); - goto out; - } -#endif - retval = -ENODEV; -out: - mutex_unlock(&isdn_mutex); - return retval; -} - -static __poll_t -isdn_poll(struct file *file, poll_table *wait) -{ - __poll_t mask = 0; - unsigned int minor = iminor(file_inode(file)); - int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - poll_wait(file, &(dev->info_waitq), wait); - /* mask = EPOLLOUT | EPOLLWRNORM; */ - if (file->private_data) { - mask |= EPOLLIN | EPOLLRDNORM; - } - goto out; - } - if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { - if (drvidx < 0) { - /* driver deregistered while file open */ - mask = EPOLLHUP; - goto out; - } - poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); - mask = EPOLLOUT | EPOLLWRNORM; - if (dev->drv[drvidx]->stavail) { - mask |= EPOLLIN | EPOLLRDNORM; - } - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - mask = isdn_ppp_poll(file, wait); - goto out; - } -#endif - mask = EPOLLERR; -out: - mutex_unlock(&isdn_mutex); - return mask; -} - - -static int -isdn_ioctl(struct file *file, uint cmd, ulong arg) -{ - uint minor = iminor(file_inode(file)); - isdn_ctrl c; - int drvidx; - int ret; - int i; - char __user *p; - char *s; - union iocpar { - char name[10]; - char bname[22]; - isdn_ioctl_struct iocts; - isdn_net_ioctl_phone phone; - isdn_net_ioctl_cfg cfg; - } iocpar; - void __user *argp = (void __user *)arg; - -#define name iocpar.name -#define bname iocpar.bname -#define iocts iocpar.iocts -#define phone iocpar.phone -#define cfg iocpar.cfg - - if (minor == ISDN_MINOR_STATUS) { - switch (cmd) { - case IIOCGETDVR: - return (TTY_DV + - (NET_DV << 8) + - (INF_DV << 16)); - case IIOCGETCPS: - if (arg) { - ulong __user *p = argp; - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - put_user(dev->ibytes[i], p++); - put_user(dev->obytes[i], p++); - } - return 0; - } else - return -EINVAL; - break; - case IIOCNETGPN: - /* Get peer phone number of a connected - * isdn network interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - return isdn_net_getpeer(&phone, argp); - } else - return -EINVAL; - default: - return -EINVAL; - } - } - if (!dev->drivers) - return -ENODEV; - if (minor <= ISDN_MINOR_BMAX) { - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; - return 0; - } - if (minor <= ISDN_MINOR_CTRLMAX) { -/* - * isdn net devices manage lots of configuration variables as linked lists. - * Those lists must only be manipulated from user space. Some of the ioctl's - * service routines access user space and are not atomic. Therefore, ioctl's - * manipulating the lists and ioctl's sleeping while accessing the lists - * are serialized by means of a semaphore. - */ - switch (cmd) { - case IIOCNETDWRSET: - printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); - return (-EINVAL); - case IIOCNETLCR: - printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); - return -ENODEV; - case IIOCNETAIF: - /* Add a network-interface */ - if (arg) { - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - s = name; - } else { - s = NULL; - } - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - if ((s = isdn_net_new(s, NULL))) { - if (copy_to_user(argp, s, strlen(s) + 1)) { - ret = -EFAULT; - } else { - ret = 0; - } - } else - ret = -ENODEV; - mutex_unlock(&dev->mtx); - return ret; - case IIOCNETASL: - /* Add a slave to a network-interface */ - if (arg) { - if (copy_from_user(bname, argp, sizeof(bname) - 1)) - return -EFAULT; - bname[sizeof(bname)-1] = 0; - } else - return -EINVAL; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - if ((s = isdn_net_newslave(bname))) { - if (copy_to_user(argp, s, strlen(s) + 1)) { - ret = -EFAULT; - } else { - ret = 0; - } - } else - ret = -ENODEV; - mutex_unlock(&dev->mtx); - return ret; - case IIOCNETDIF: - /* Delete a network-interface */ - if (arg) { - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_rm(name); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETSCF: - /* Set configurable parameters of a network-interface */ - if (arg) { - if (copy_from_user(&cfg, argp, sizeof(cfg))) - return -EFAULT; - return isdn_net_setcfg(&cfg); - } else - return -EINVAL; - case IIOCNETGCF: - /* Get configurable parameters of a network-interface */ - if (arg) { - if (copy_from_user(&cfg, argp, sizeof(cfg))) - return -EFAULT; - if (!(ret = isdn_net_getcfg(&cfg))) { - if (copy_to_user(argp, &cfg, sizeof(cfg))) - return -EFAULT; - } - return ret; - } else - return -EINVAL; - case IIOCNETANM: - /* Add a phone-number to a network-interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_addphone(&phone); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETGNM: - /* Get list of phone-numbers of a network-interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_getphones(&phone, argp); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETDNM: - /* Delete a phone-number of a network-interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_delphone(&phone); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETDIL: - /* Force dialing of a network-interface */ - if (arg) { - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_net_force_dial(name); - } else - return -EINVAL; -#ifdef CONFIG_ISDN_PPP - case IIOCNETALN: - if (!arg) - return -EINVAL; - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_ppp_dial_slave(name); - case IIOCNETDLN: - if (!arg) - return -EINVAL; - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_ppp_hangup_slave(name); -#endif - case IIOCNETHUP: - /* Force hangup of a network-interface */ - if (!arg) - return -EINVAL; - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_net_force_hangup(name); - break; - case IIOCSETVER: - dev->net_verbose = arg; - printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); - return 0; - case IIOCSETGST: - if (arg) - dev->global_flags |= ISDN_GLOBAL_STOPPED; - else - dev->global_flags &= ~ISDN_GLOBAL_STOPPED; - printk(KERN_INFO "isdn: Global Mode %s\n", - (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); - return 0; - case IIOCSETBRJ: - drvidx = -1; - if (arg) { - int i; - char *p; - if (copy_from_user(&iocts, argp, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - iocts.drvid[sizeof(iocts.drvid) - 1] = 0; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } - } - if (drvidx == -1) - return -ENODEV; - if (iocts.arg) - dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; - else - dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; - return 0; - case IIOCSIGPRF: - dev->profd = current; - return 0; - break; - case IIOCGETPRF: - /* Get all Modem-Profiles */ - if (arg) { - char __user *p = argp; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - } - return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; - } else - return -EINVAL; - break; - case IIOCSETPRF: - /* Set all Modem-Profiles */ - if (arg) { - char __user *p = argp; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - } - return 0; - } else - return -EINVAL; - break; - case IIOCSETMAP: - case IIOCGETMAP: - /* Set/Get MSN->EAZ-Mapping for a driver */ - if (arg) { - - if (copy_from_user(&iocts, argp, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - iocts.drvid[sizeof(iocts.drvid) - 1] = 0; - if (strlen(iocts.drvid)) { - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - if (cmd == IIOCSETMAP) { - int loop = 1; - - p = (char __user *) iocts.arg; - i = 0; - while (loop) { - int j = 0; - - while (1) { - get_user(bname[j], p++); - switch (bname[j]) { - case '\0': - loop = 0; - /* Fall through */ - case ',': - bname[j] = '\0'; - strcpy(dev->drv[drvidx]->msn2eaz[i], bname); - j = ISDN_MSNLEN; - break; - default: - j++; - } - if (j >= ISDN_MSNLEN) - break; - } - if (++i > 9) - break; - } - } else { - p = (char __user *) iocts.arg; - for (i = 0; i < 10; i++) { - snprintf(bname, sizeof(bname), "%s%s", - strlen(dev->drv[drvidx]->msn2eaz[i]) ? - dev->drv[drvidx]->msn2eaz[i] : "_", - (i < 9) ? "," : "\0"); - if (copy_to_user(p, bname, strlen(bname) + 1)) - return -EFAULT; - p += strlen(bname); - } - } - return 0; - } else - return -EINVAL; - case IIOCDBGVAR: - return -EINVAL; - default: - if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) - cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; - else - return -EINVAL; - if (arg) { - int i; - char *p; - if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct))) - return -EFAULT; - iocts.drvid[sizeof(iocts.drvid) - 1] = 0; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - c.driver = drvidx; - c.command = ISDN_CMD_IOCTL; - c.arg = cmd; - memcpy(c.parm.num, &iocts.arg, sizeof(ulong)); - ret = isdn_command(&c); - memcpy(&iocts.arg, c.parm.num, sizeof(ulong)); - if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct))) - return -EFAULT; - return ret; - } else - return -EINVAL; - } - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg)); -#endif - return -ENODEV; - -#undef name -#undef bname -#undef iocts -#undef phone -#undef cfg -} - -static long -isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&isdn_mutex); - ret = isdn_ioctl(file, cmd, arg); - mutex_unlock(&isdn_mutex); - - return ret; -} - -/* - * Open the device code. - */ -static int -isdn_open(struct inode *ino, struct file *filep) -{ - uint minor = iminor(ino); - int drvidx; - int chidx; - int retval = -ENODEV; - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - infostruct *p; - - if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) { - p->next = (char *) dev->infochain; - p->private = (char *) &(filep->private_data); - dev->infochain = p; - /* At opening we allow a single update */ - filep->private_data = (char *) 1; - retval = 0; - goto out; - } else { - retval = -ENOMEM; - goto out; - } - } - if (!dev->channels) - goto out; - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - goto out; - chidx = isdn_minor2chan(minor); - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - goto out; - if (!(dev->drv[drvidx]->online & (1 << chidx))) - goto out; - isdn_lock_drivers(); - retval = 0; - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - goto out; - isdn_lock_drivers(); - retval = 0; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); - if (retval == 0) - isdn_lock_drivers(); - goto out; - } -#endif -out: - nonseekable_open(ino, filep); - mutex_unlock(&isdn_mutex); - return retval; -} - -static int -isdn_close(struct inode *ino, struct file *filep) -{ - uint minor = iminor(ino); - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - infostruct *p = dev->infochain; - infostruct *q = NULL; - - while (p) { - if (p->private == (char *) &(filep->private_data)) { - if (q) - q->next = p->next; - else - dev->infochain = (infostruct *) (p->next); - kfree(p); - goto out; - } - q = p; - p = (infostruct *) (p->next); - } - printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - goto out; - } - isdn_unlock_drivers(); - if (minor <= ISDN_MINOR_BMAX) - goto out; - if (minor <= ISDN_MINOR_CTRLMAX) { - if (dev->profd == current) - dev->profd = NULL; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); -#endif - -out: - mutex_unlock(&isdn_mutex); - return 0; -} - -static const struct file_operations isdn_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_read, - .write = isdn_write, - .poll = isdn_poll, - .unlocked_ioctl = isdn_unlocked_ioctl, - .open = isdn_open, - .release = isdn_close, -}; - -char * -isdn_map_eaz2msn(char *msn, int di) -{ - isdn_driver_t *this = dev->drv[di]; - int i; - - if (strlen(msn) == 1) { - i = msn[0] - '0'; - if ((i >= 0) && (i <= 9)) - if (strlen(this->msn2eaz[i])) - return (this->msn2eaz[i]); - } - return (msn); -} - -/* - * Find an unused ISDN-channel, whose feature-flags match the - * given L2- and L3-protocols. - */ -#define L2V (~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038)) - -/* - * This function must be called with holding the dev->lock. - */ -int -isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev - , int pre_chan, char *msn) -{ - int i; - ulong features; - ulong vfeatures; - - features = ((1 << l2_proto) | (0x10000 << l3_proto)); - vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) & - ~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038)); - /* If Layer-2 protocol is V.110, accept drivers with - * transparent feature even if these don't support V.110 - * because we can emulate this in linklevel. - */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (USG_NONE(dev->usage[i]) && - (dev->drvmap[i] != -1)) { - int d = dev->drvmap[i]; - if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && - ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) - continue; - if (!strcmp(isdn_map_eaz2msn(msn, d), "-")) - continue; - if (dev->usage[i] & ISDN_USAGE_DISABLED) - continue; /* usage not allowed */ - if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { - if (((dev->drv[d]->interface->features & features) == features) || - (((dev->drv[d]->interface->features & vfeatures) == vfeatures) && - (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) { - if ((pre_dev < 0) || (pre_chan < 0)) { - dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[i] |= usage; - isdn_info_update(); - return i; - } else { - if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) { - dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[i] |= usage; - isdn_info_update(); - return i; - } - } - } - } - } - return -1; -} - -/* - * Set state of ISDN-channel to 'unused' - */ -void -isdn_free_channel(int di, int ch, int usage) -{ - int i; - - if ((di < 0) || (ch < 0)) { - printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n", - __func__, di, ch); - return; - } - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) && - (dev->drvmap[i] == di) && - (dev->chanmap[i] == ch)) { - dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE); - strcpy(dev->num[i], "???"); - dev->ibytes[i] = 0; - dev->obytes[i] = 0; -// 20.10.99 JIM, try to reinitialize v110 ! - dev->v110emu[i] = 0; - atomic_set(&(dev->v110use[i]), 0); - isdn_v110_close(dev->v110[i]); - dev->v110[i] = NULL; -// 20.10.99 JIM, try to reinitialize v110 ! - isdn_info_update(); - if (dev->drv[di]) - skb_queue_purge(&dev->drv[di]->rpqueue[ch]); - } -} - -/* - * Cancel Exclusive-Flag for ISDN-channel - */ -void -isdn_unexclusive_channel(int di, int ch) -{ - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if ((dev->drvmap[i] == di) && - (dev->chanmap[i] == ch)) { - dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE; - isdn_info_update(); - return; - } -} - -/* - * writebuf replacement for SKB_ABLE drivers - */ -static int -isdn_writebuf_stub(int drvidx, int chan, const u_char __user *buf, int len) -{ - int ret; - int hl = dev->drv[drvidx]->interface->hl_hdrlen; - struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC); - - if (!skb) - return -ENOMEM; - skb_reserve(skb, hl); - if (copy_from_user(skb_put(skb, len), buf, len)) { - dev_kfree_skb(skb); - return -EFAULT; - } - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); - if (ret <= 0) - dev_kfree_skb(skb); - if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx, chan)] += ret; - return ret; -} - -/* - * Return: length of data on success, -ERRcode on failure. - */ -int -isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) -{ - int ret; - struct sk_buff *nskb = NULL; - int v110_ret = skb->len; - int idx = isdn_dc2minor(drvidx, chan); - - if (dev->v110[idx]) { - atomic_inc(&dev->v110use[idx]); - nskb = isdn_v110_encode(dev->v110[idx], skb); - atomic_dec(&dev->v110use[idx]); - if (!nskb) - return 0; - v110_ret = *((int *)nskb->data); - skb_pull(nskb, sizeof(int)); - if (!nskb->len) { - dev_kfree_skb(nskb); - return v110_ret; - } - /* V.110 must always be acknowledged */ - ack = 1; - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb); - } else { - int hl = dev->drv[drvidx]->interface->hl_hdrlen; - - if (skb_headroom(skb) < hl) { - /* - * This should only occur when new HL driver with - * increased hl_hdrlen was loaded after netdevice - * was created and connected to the new driver. - * - * The V.110 branch (re-allocates on its own) does - * not need this - */ - struct sk_buff *skb_tmp; - - skb_tmp = skb_realloc_headroom(skb, hl); - printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed"); - if (!skb_tmp) return -ENOMEM; /* 0 better? */ - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp); - if (ret > 0) { - dev_kfree_skb(skb); - } else { - dev_kfree_skb(skb_tmp); - } - } else { - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb); - } - } - if (ret > 0) { - dev->obytes[idx] += ret; - if (dev->v110[idx]) { - atomic_inc(&dev->v110use[idx]); - dev->v110[idx]->skbuser++; - atomic_dec(&dev->v110use[idx]); - /* For V.110 return unencoded data length */ - ret = v110_ret; - /* if the complete frame was send we free the skb; - if not upper function will requeue the skb */ - if (ret == skb->len) - dev_kfree_skb(skb); - } - } else - if (dev->v110[idx]) - dev_kfree_skb(nskb); - return ret; -} - -static int -isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) -{ - int j, k, m; - - init_waitqueue_head(&d->st_waitq); - if (d->flags & DRV_FLAG_RUNNING) - return -1; - if (n < 1) return 0; - - m = (adding) ? d->channels + n : n; - - if (dev->channels + n > ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", - ISDN_MAX_CHANNELS); - return -1; - } - - if ((adding) && (d->rcverr)) - kfree(d->rcverr); - if (!(d->rcverr = kcalloc(m, sizeof(int), GFP_ATOMIC))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); - return -1; - } - - if ((adding) && (d->rcvcount)) - kfree(d->rcvcount); - if (!(d->rcvcount = kcalloc(m, sizeof(int), GFP_ATOMIC))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - if (!adding) - kfree(d->rcverr); - return -1; - } - - if ((adding) && (d->rpqueue)) { - for (j = 0; j < d->channels; j++) - skb_queue_purge(&d->rpqueue[j]); - kfree(d->rpqueue); - } - d->rpqueue = kmalloc_array(m, sizeof(struct sk_buff_head), GFP_ATOMIC); - if (!d->rpqueue) { - printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - if (!adding) { - kfree(d->rcvcount); - kfree(d->rcverr); - } - return -1; - } - for (j = 0; j < m; j++) { - skb_queue_head_init(&d->rpqueue[j]); - } - - if ((adding) && (d->rcv_waitq)) - kfree(d->rcv_waitq); - d->rcv_waitq = kmalloc(array3_size(sizeof(wait_queue_head_t), 2, m), - GFP_ATOMIC); - if (!d->rcv_waitq) { - printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); - if (!adding) { - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - } - return -1; - } - d->snd_waitq = d->rcv_waitq + m; - for (j = 0; j < m; j++) { - init_waitqueue_head(&d->rcv_waitq[j]); - init_waitqueue_head(&d->snd_waitq[j]); - } - - dev->channels += n; - for (j = d->channels; j < m; j++) - for (k = 0; k < ISDN_MAX_CHANNELS; k++) - if (dev->chanmap[k] < 0) { - dev->chanmap[k] = j; - dev->drvmap[k] = drvidx; - break; - } - d->channels = m; - return 0; -} - -/* - * Low-level-driver registration - */ - -static void -set_global_features(void) -{ - int drvidx; - - dev->global_features = 0; - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { - if (!dev->drv[drvidx]) - continue; - if (dev->drv[drvidx]->interface) - dev->global_features |= dev->drv[drvidx]->interface->features; - } -} - -#ifdef CONFIG_ISDN_DIVERSION - -static char *map_drvname(int di) -{ - if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) - return (NULL); - return (dev->drvid[di]); /* driver name */ -} /* map_drvname */ - -static int map_namedrv(char *id) -{ int i; - - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - { if (!strcmp(dev->drvid[i], id)) - return (i); - } - return (-1); -} /* map_namedrv */ - -int DIVERT_REG_NAME(isdn_divert_if *i_div) -{ - if (i_div->if_magic != DIVERT_IF_MAGIC) - return (DIVERT_VER_ERR); - switch (i_div->cmd) - { - case DIVERT_CMD_REL: - if (divert_if != i_div) - return (DIVERT_REL_ERR); - divert_if = NULL; /* free interface */ - return (DIVERT_NO_ERR); - - case DIVERT_CMD_REG: - if (divert_if) - return (DIVERT_REG_ERR); - i_div->ll_cmd = isdn_command; /* set command function */ - i_div->drv_to_name = map_drvname; - i_div->name_to_drv = map_namedrv; - divert_if = i_div; /* remember interface */ - return (DIVERT_NO_ERR); - - default: - return (DIVERT_CMD_ERR); - } -} /* DIVERT_REG_NAME */ - -EXPORT_SYMBOL(DIVERT_REG_NAME); - -#endif /* CONFIG_ISDN_DIVERSION */ - - -EXPORT_SYMBOL(register_isdn); -#ifdef CONFIG_ISDN_PPP -EXPORT_SYMBOL(isdn_ppp_register_compressor); -EXPORT_SYMBOL(isdn_ppp_unregister_compressor); -#endif - -int -register_isdn(isdn_if *i) -{ - isdn_driver_t *d; - int j; - ulong flags; - int drvidx; - - if (dev->drivers >= ISDN_MAX_DRIVERS) { - printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", - ISDN_MAX_DRIVERS); - return 0; - } - if (!i->writebuf_skb) { - printk(KERN_WARNING "register_isdn: No write routine given.\n"); - return 0; - } - if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); - return 0; - } - - d->maxbufsize = i->maxbufsize; - d->pktcount = 0; - d->stavail = 0; - d->flags = DRV_FLAG_LOADED; - d->online = 0; - d->interface = i; - d->channels = 0; - spin_lock_irqsave(&dev->lock, flags); - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) - if (!dev->drv[drvidx]) - break; - if (isdn_add_channels(d, drvidx, i->channels, 0)) { - spin_unlock_irqrestore(&dev->lock, flags); - kfree(d); - return 0; - } - i->channels = drvidx; - i->rcvcallb_skb = isdn_receive_skb_callback; - i->statcallb = isdn_status_callback; - if (!strlen(i->id)) - sprintf(i->id, "line%d", drvidx); - for (j = 0; j < drvidx; j++) - if (!strcmp(i->id, dev->drvid[j])) - sprintf(i->id, "line%d", drvidx); - dev->drv[drvidx] = d; - strcpy(dev->drvid[drvidx], i->id); - isdn_info_update(); - dev->drivers++; - set_global_features(); - spin_unlock_irqrestore(&dev->lock, flags); - return 1; -} - -/* -***************************************************************************** -* And now the modules code. -***************************************************************************** -*/ - -static char * -isdn_getrev(const char *revision) -{ - char *rev; - char *p; - - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; -} - -/* - * Allocate and initialize all data, register modem-devices - */ -static int __init isdn_init(void) -{ - int i; - char tmprev[50]; - - dev = vzalloc(sizeof(isdn_dev)); - if (!dev) { - printk(KERN_WARNING "isdn: Could not allocate device-struct.\n"); - return -EIO; - } - timer_setup(&dev->timer, isdn_timer_funct, 0); - spin_lock_init(&dev->lock); - spin_lock_init(&dev->timerlock); -#ifdef MODULE - dev->owner = THIS_MODULE; -#endif - mutex_init(&dev->mtx); - init_waitqueue_head(&dev->info_waitq); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - dev->drvmap[i] = -1; - dev->chanmap[i] = -1; - dev->m_idx[i] = -1; - strcpy(dev->num[i], "???"); - } - if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { - printk(KERN_WARNING "isdn: Could not register control devices\n"); - vfree(dev); - return -EIO; - } - if ((isdn_tty_modem_init()) < 0) { - printk(KERN_WARNING "isdn: Could not register tty devices\n"); - vfree(dev); - unregister_chrdev(ISDN_MAJOR, "isdn"); - return -EIO; - } -#ifdef CONFIG_ISDN_PPP - if (isdn_ppp_init() < 0) { - printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n"); - isdn_tty_exit(); - unregister_chrdev(ISDN_MAJOR, "isdn"); - vfree(dev); - return -EIO; - } -#endif /* CONFIG_ISDN_PPP */ - - strcpy(tmprev, isdn_revision); - printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_net_revision); - printk("%s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_ppp_revision); - printk("%s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_audio_revision); - printk("%s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_v110_revision); - printk("%s", isdn_getrev(tmprev)); - -#ifdef MODULE - printk(" loaded\n"); -#else - printk("\n"); -#endif - isdn_info_update(); - return 0; -} - -/* - * Unload module - */ -static void __exit isdn_exit(void) -{ -#ifdef CONFIG_ISDN_PPP - isdn_ppp_cleanup(); -#endif - if (isdn_net_rmall() < 0) { - printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n"); - return; - } - isdn_tty_exit(); - unregister_chrdev(ISDN_MAJOR, "isdn"); - del_timer_sync(&dev->timer); - /* call vfree with interrupts enabled, else it will hang */ - vfree(dev); - printk(KERN_NOTICE "ISDN-subsystem unloaded\n"); -} - -module_init(isdn_init); -module_exit(isdn_exit); diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h deleted file mode 100644 index 2260ef07ab9c..000000000000 --- a/drivers/isdn/i4l/isdn_common.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem - * common used functions and debugging-switches (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#undef ISDN_DEBUG_MODEM_OPEN -#undef ISDN_DEBUG_MODEM_IOCTL -#undef ISDN_DEBUG_MODEM_WAITSENT -#undef ISDN_DEBUG_MODEM_HUP -#undef ISDN_DEBUG_MODEM_ICALL -#undef ISDN_DEBUG_MODEM_DUMP -#undef ISDN_DEBUG_MODEM_VOICE -#undef ISDN_DEBUG_AT -#undef ISDN_DEBUG_NET_DUMP -#undef ISDN_DEBUG_NET_DIAL -#undef ISDN_DEBUG_NET_ICALL - -/* Prototypes */ -extern void isdn_lock_drivers(void); -extern void isdn_unlock_drivers(void); -extern void isdn_free_channel(int di, int ch, int usage); -extern void isdn_all_eaz(int di, int ch); -extern int isdn_command(isdn_ctrl *); -extern int isdn_dc2minor(int di, int ch); -extern void isdn_info_update(void); -extern char *isdn_map_eaz2msn(char *msn, int di); -extern void isdn_timer_ctrl(int tf, int onoff); -extern void isdn_unexclusive_channel(int di, int ch); -extern int isdn_getnum(char **); -extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); -extern int isdn_readbchan_tty(int, int, struct tty_port *, int); -extern int isdn_get_free_channel(int, int, int, int, int, char *); -extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); -extern int register_isdn(isdn_if *i); -extern int isdn_msncmp(const char *, const char *); -#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -extern void isdn_dumppkt(char *, u_char *, int, int); -#endif diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c deleted file mode 100644 index 336523ec077c..000000000000 --- a/drivers/isdn/i4l/isdn_concap.c +++ /dev/null @@ -1,99 +0,0 @@ -/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, protocol encapsulation - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific - * stuff goes here. Stuff that depends only on the concap protocol goes to - * another -- protocol specific -- source file. - * - */ - - -#include -#include "isdn_x25iface.h" -#include "isdn_net.h" -#include -#include "isdn_concap.h" - - -/* The following set of device service operations are for encapsulation - protocols that require for reliable datalink semantics. That means: - - - before any data is to be submitted the connection must explicitly - be set up. - - after the successful set up of the connection is signalled the - connection is considered to be reliably up. - - Auto-dialing ist not compatible with this requirements. Thus, auto-dialing - is completely bypassed. - - It might be possible to implement a (non standardized) datalink protocol - that provides a reliable data link service while using some auto dialing - mechanism. Such a protocol would need an auxiliary channel (i.e. user-user- - signaling on the D-channel) while the B-channel is down. -*/ - - -static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) -{ - struct net_device *ndev = concap->net_dev; - isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; - isdn_net_local *lp = isdn_net_get_locked_lp(nd); - - IX25DEBUG("isdn_concap_dl_data_req: %s \n", concap->net_dev->name); - if (!lp) { - IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 1); - return 1; - } - lp->huptimer = 0; - isdn_net_writebuf_skb(lp, skb); - spin_unlock_bh(&lp->xmit_lock); - IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 0); - return 0; -} - - -static int isdn_concap_dl_connect_req(struct concap_proto *concap) -{ - struct net_device *ndev = concap->net_dev; - isdn_net_local *lp = netdev_priv(ndev); - int ret; - IX25DEBUG("isdn_concap_dl_connect_req: %s \n", ndev->name); - - /* dial ... */ - ret = isdn_net_dial_req(lp); - if (ret) IX25DEBUG("dialing failed\n"); - return ret; -} - -static int isdn_concap_dl_disconn_req(struct concap_proto *concap) -{ - IX25DEBUG("isdn_concap_dl_disconn_req: %s \n", concap->net_dev->name); - - isdn_net_hangup(concap->net_dev); - return 0; -} - -struct concap_device_ops isdn_concap_reliable_dl_dops = { - .data_req = &isdn_concap_dl_data_req, - .connect_req = &isdn_concap_dl_connect_req, - .disconn_req = &isdn_concap_dl_disconn_req -}; - -/* The following should better go into a dedicated source file such that - this sourcefile does not need to include any protocol specific header - files. For now: -*/ -struct concap_proto *isdn_concap_new(int encap) -{ - switch (encap) { - case ISDN_NET_ENCAP_X25IFACE: - return isdn_x25iface_proto_new(); - } - return NULL; -} diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h deleted file mode 100644 index cd7e3ba74e25..000000000000 --- a/drivers/isdn/i4l/isdn_concap.h +++ /dev/null @@ -1,11 +0,0 @@ -/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, protocol encapsulation - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -extern struct concap_device_ops isdn_concap_reliable_dl_dops; -extern struct concap_proto *isdn_concap_new(int); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c deleted file mode 100644 index c138f66f2659..000000000000 --- a/drivers/isdn/i4l/isdn_net.c +++ /dev/null @@ -1,3198 +0,0 @@ -/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, network interfaces and related functions (linklevel). - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 - * guy@traverse.com.au - * Outgoing calls - looks for a 'V' in first char of dialed number - * Incoming calls - checks first character of eaz as follows: - * Numeric - accept DATA only - original functionality - * 'V' - accept VOICE (DOV) only - * 'B' - accept BOTH DATA and DOV types - * - * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb - * for info on the protocol, see - * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt - */ - -#include -#include -#include -#include -#include -#include -#include "isdn_common.h" -#include "isdn_net.h" -#ifdef CONFIG_ISDN_PPP -#include "isdn_ppp.h" -#endif -#ifdef CONFIG_ISDN_X25 -#include -#include "isdn_concap.h" -#endif - - -/* - * Outline of new tbusy handling: - * - * Old method, roughly spoken, consisted of setting tbusy when entering - * isdn_net_start_xmit() and at several other locations and clearing - * it from isdn_net_start_xmit() thread when sending was successful. - * - * With 2.3.x multithreaded network core, to prevent problems, tbusy should - * only be set by the isdn_net_start_xmit() thread and only when a tx-busy - * condition is detected. Other threads (in particular isdn_net_stat_callb()) - * are only allowed to clear tbusy. - * - * -HE - */ - -/* - * About SOFTNET: - * Most of the changes were pretty obvious and basically done by HE already. - * - * One problem of the isdn net device code is that it uses struct net_device - * for masters and slaves. However, only master interface are registered to - * the network layer, and therefore, it only makes sense to call netif_* - * functions on them. - * - * --KG - */ - -/* - * Find out if the netdevice has been ifup-ed yet. - * For slaves, look at the corresponding master. - */ -static __inline__ int isdn_net_device_started(isdn_net_dev *n) -{ - isdn_net_local *lp = n->local; - struct net_device *dev; - - if (lp->master) - dev = lp->master; - else - dev = n->dev; - return netif_running(dev); -} - -/* - * wake up the network -> net_device queue. - * For slaves, wake the corresponding master interface. - */ -static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) -{ - if (lp->master) - netif_wake_queue(lp->master); - else - netif_wake_queue(lp->netdev->dev); -} - -/* - * stop the network -> net_device queue. - * For slaves, stop the corresponding master interface. - */ -static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) -{ - if (lp->master) - netif_stop_queue(lp->master); - else - netif_stop_queue(lp->netdev->dev); -} - -/* - * find out if the net_device which this lp belongs to (lp can be - * master or slave) is busy. It's busy iff all (master and slave) - * queues are busy - */ -static __inline__ int isdn_net_device_busy(isdn_net_local *lp) -{ - isdn_net_local *nlp; - isdn_net_dev *nd; - unsigned long flags; - - if (!isdn_net_lp_busy(lp)) - return 0; - - if (lp->master) - nd = ISDN_MASTER_PRIV(lp)->netdev; - else - nd = lp->netdev; - - spin_lock_irqsave(&nd->queue_lock, flags); - nlp = lp->next; - while (nlp != lp) { - if (!isdn_net_lp_busy(nlp)) { - spin_unlock_irqrestore(&nd->queue_lock, flags); - return 0; - } - nlp = nlp->next; - } - spin_unlock_irqrestore(&nd->queue_lock, flags); - return 1; -} - -static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp) -{ - atomic_inc(&lp->frame_cnt); - if (isdn_net_device_busy(lp)) - isdn_net_device_stop_queue(lp); -} - -static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp) -{ - atomic_dec(&lp->frame_cnt); - - if (!(isdn_net_device_busy(lp))) { - if (!skb_queue_empty(&lp->super_tx_queue)) { - schedule_work(&lp->tqueue); - } else { - isdn_net_device_wake_queue(lp); - } - } -} - -static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) -{ - atomic_set(&lp->frame_cnt, 0); -} - -/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just - * to be safe. - * For 2.3.x we push it up to 20 secs, because call establishment - * (in particular callback) may take such a long time, and we - * don't want confusing messages in the log. However, there is a slight - * possibility that this large timeout will break other things like MPPP, - * which might rely on the tx timeout. If so, we'll find out this way... - */ - -#define ISDN_NET_TX_TIMEOUT (20 * HZ) - -/* Prototypes */ - -static int isdn_net_force_dial_lp(isdn_net_local *); -static netdev_tx_t isdn_net_start_xmit(struct sk_buff *, - struct net_device *); - -static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); -static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); - -char *isdn_net_revision = "$Revision: 1.1.2.2 $"; - -/* - * Code for raw-networking over ISDN - */ - -static void -isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) -{ - if (skb) { - - u_short proto = ntohs(skb->protocol); - - printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", - dev->name, - (reason != NULL) ? reason : "unknown", - (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); - - dst_link_failure(skb); - } - else { /* dial not triggered by rawIP packet */ - printk(KERN_DEBUG "isdn_net: %s: %s\n", - dev->name, - (reason != NULL) ? reason : "reason unknown"); - } -} - -static void -isdn_net_reset(struct net_device *dev) -{ -#ifdef CONFIG_ISDN_X25 - struct concap_device_ops *dops = - ((isdn_net_local *)netdev_priv(dev))->dops; - struct concap_proto *cprot = - ((isdn_net_local *)netdev_priv(dev))->netdev->cprot; -#endif -#ifdef CONFIG_ISDN_X25 - if (cprot && cprot->pops && dops) - cprot->pops->restart(cprot, dev, dops); -#endif -} - -/* Open/initialize the board. */ -static int -isdn_net_open(struct net_device *dev) -{ - int i; - struct net_device *p; - struct in_device *in_dev; - - /* moved here from isdn_net_reset, because only the master has an - interface associated which is supposed to be started. BTW: - we need to call netif_start_queue, not netif_wake_queue here */ - netif_start_queue(dev); - - isdn_net_reset(dev); - /* Fill in the MAC-level header (not needed, but for compatibility... */ - for (i = 0; i < ETH_ALEN - sizeof(u32); i++) - dev->dev_addr[i] = 0xfc; - if ((in_dev = dev->ip_ptr) != NULL) { - /* - * Any address will do - we take the first - */ - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL) - memcpy(dev->dev_addr + 2, &ifa->ifa_local, 4); - } - - /* If this interface has slaves, start them also */ - p = MASTER_TO_SLAVE(dev); - if (p) { - while (p) { - isdn_net_reset(p); - p = MASTER_TO_SLAVE(p); - } - } - isdn_lock_drivers(); - return 0; -} - -/* - * Assign an ISDN-channel to a net-interface - */ -static void -isdn_net_bind_channel(isdn_net_local *lp, int idx) -{ - lp->flags |= ISDN_NET_CONNECTED; - lp->isdn_device = dev->drvmap[idx]; - lp->isdn_channel = dev->chanmap[idx]; - dev->rx_netdev[idx] = lp->netdev; - dev->st_netdev[idx] = lp->netdev; -} - -/* - * unbind a net-interface (resets interface after an error) - */ -static void -isdn_net_unbind_channel(isdn_net_local *lp) -{ - skb_queue_purge(&lp->super_tx_queue); - - if (!lp->master) { /* reset only master device */ - /* Moral equivalent of dev_purge_queues(): - BEWARE! This chunk of code cannot be called from hardware - interrupt handler. I hope it is true. --ANK - */ - qdisc_reset_all_tx(lp->netdev->dev); - } - lp->dialstate = 0; - dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; - dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; - if (lp->isdn_device != -1 && lp->isdn_channel != -1) - isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); - lp->flags &= ~ISDN_NET_CONNECTED; - lp->isdn_device = -1; - lp->isdn_channel = -1; -} - -/* - * Perform auto-hangup and cps-calculation for net-interfaces. - * - * auto-hangup: - * Increment idle-counter (this counter is reset on any incoming or - * outgoing packet), if counter exceeds configured limit either do a - * hangup immediately or - if configured - wait until just before the next - * charge-info. - * - * cps-calculation (needed for dynamic channel-bundling): - * Since this function is called every second, simply reset the - * byte-counter of the interface after copying it to the cps-variable. - */ -static unsigned long last_jiffies = -HZ; - -void -isdn_net_autohup(void) -{ - isdn_net_dev *p = dev->netdev; - int anymore; - - anymore = 0; - while (p) { - isdn_net_local *l = p->local; - if (jiffies == last_jiffies) - l->cps = l->transcount; - else - l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); - l->transcount = 0; - if (dev->net_verbose > 3) - printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps); - if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { - anymore = 1; - l->huptimer++; - /* - * if there is some dialmode where timeout-hangup - * should _not_ be done, check for that here - */ - if ((l->onhtime) && - (l->huptimer > l->onhtime)) - { - if (l->hupflags & ISDN_MANCHARGE && - l->hupflags & ISDN_CHARGEHUP) { - while (time_after(jiffies, l->chargetime + l->chargeint)) - l->chargetime += l->chargeint; - if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) - if (l->outgoing || l->hupflags & ISDN_INHUP) - isdn_net_hangup(p->dev); - } else if (l->outgoing) { - if (l->hupflags & ISDN_CHARGEHUP) { - if (l->hupflags & ISDN_WAITCHARGE) { - printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", - p->dev->name, l->hupflags); - isdn_net_hangup(p->dev); - } else if (time_after(jiffies, l->chargetime + l->chargeint)) { - printk(KERN_DEBUG - "isdn_net: %s: chtime = %lu, chint = %d\n", - p->dev->name, l->chargetime, l->chargeint); - isdn_net_hangup(p->dev); - } - } else - isdn_net_hangup(p->dev); - } else if (l->hupflags & ISDN_INHUP) - isdn_net_hangup(p->dev); - } - - if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { - isdn_net_hangup(p->dev); - break; - } - } - p = (isdn_net_dev *) p->next; - } - last_jiffies = jiffies; - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); -} - -static void isdn_net_lp_disconnected(isdn_net_local *lp) -{ - isdn_net_rm_from_bundle(lp); -} - -/* - * Handle status-messages from ISDN-interfacecard. - * This function is called from within the main-status-dispatcher - * isdn_status_callback, which itself is called from the low-level driver. - * Return: 1 = Event handled, 0 = not for us or unknown Event. - */ -int -isdn_net_stat_callback(int idx, isdn_ctrl *c) -{ - isdn_net_dev *p = dev->st_netdev[idx]; - int cmd = c->command; - - if (p) { - isdn_net_local *lp = p->local; -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; - struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; -#endif - switch (cmd) { - case ISDN_STAT_BSENT: - /* A packet has successfully been sent out */ - if ((lp->flags & ISDN_NET_CONNECTED) && - (!lp->dialstate)) { - isdn_net_dec_frame_cnt(lp); - lp->stats.tx_packets++; - lp->stats.tx_bytes += c->parm.length; - } - return 1; - case ISDN_STAT_DCONN: - /* D-Channel is up */ - switch (lp->dialstate) { - case 4: - case 7: - case 8: - lp->dialstate++; - return 1; - case 12: - lp->dialstate = 5; - return 1; - } - break; - case ISDN_STAT_DHUP: - /* Either D-Channel-hangup or error during dialout */ -#ifdef CONFIG_ISDN_X25 - /* If we are not connencted then dialing had - failed. If there are generic encap protocol - receiver routines signal the closure of - the link*/ - - if (!(lp->flags & ISDN_NET_CONNECTED) - && pops && pops->disconn_ind) - pops->disconn_ind(cprot); -#endif /* CONFIG_ISDN_X25 */ - if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { - if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) - isdn_net_ciscohdlck_disconnected(lp); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); - isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - printk(KERN_INFO "%s: remote hangup\n", p->dev->name); - printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name, - lp->charge); - isdn_net_unbind_channel(lp); - return 1; - } - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_STAT_BHUP: - /* B-Channel-hangup */ - /* try if there are generic encap protocol - receiver routines and signal the closure of - the link */ - if (pops && pops->disconn_ind) { - pops->disconn_ind(cprot); - return 1; - } - break; -#endif /* CONFIG_ISDN_X25 */ - case ISDN_STAT_BCONN: - /* B-Channel is up */ - isdn_net_zero_frame_cnt(lp); - switch (lp->dialstate) { - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 12: - if (lp->dialstate <= 6) { - dev->usage[idx] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - } else - dev->rx_netdev[idx] = p; - lp->dialstate = 0; - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); - if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) - isdn_net_ciscohdlck_connected(lp); - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { - if (lp->master) { /* is lp a slave? */ - isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev; - isdn_net_add_to_bundle(nd, lp); - } - } - printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name); - /* If first Chargeinfo comes before B-Channel connect, - * we correct the timestamp here. - */ - lp->chargetime = jiffies; - - /* reset dial-timeout */ - lp->dialstarted = 0; - lp->dialwait_timer = 0; - -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_wakeup_daemon(lp); -#endif -#ifdef CONFIG_ISDN_X25 - /* try if there are generic concap receiver routines */ - if (pops) - if (pops->connect_ind) - pops->connect_ind(cprot); -#endif /* CONFIG_ISDN_X25 */ - /* ppp needs to do negotiations first */ - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - isdn_net_device_wake_queue(lp); - return 1; - } - break; - case ISDN_STAT_NODCH: - /* No D-Channel avail. */ - if (lp->dialstate == 4) { - lp->dialstate--; - return 1; - } - break; - case ISDN_STAT_CINF: - /* Charge-info from TelCo. Calculate interval between - * charge-infos and set timestamp for last info for - * usage by isdn_net_autohup() - */ - lp->charge++; - if (lp->hupflags & ISDN_HAVECHARGE) { - lp->hupflags &= ~ISDN_WAITCHARGE; - lp->chargeint = jiffies - lp->chargetime - (2 * HZ); - } - if (lp->hupflags & ISDN_WAITCHARGE) - lp->hupflags |= ISDN_HAVECHARGE; - lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", - p->dev->name, lp->chargetime); - return 1; - } - } - return 0; -} - -/* - * Perform dialout for net-interfaces and timeout-handling for - * D-Channel-up and B-Channel-up Messages. - * This function is initially called from within isdn_net_start_xmit() or - * or isdn_net_find_icall() after initializing the dialstate for an - * interface. If further calls are needed, the function schedules itself - * for a timer-callback via isdn_timer_function(). - * The dialstate is also affected by incoming status-messages from - * the ISDN-Channel which are handled in isdn_net_stat_callback() above. - */ -void -isdn_net_dial(void) -{ - isdn_net_dev *p = dev->netdev; - int anymore = 0; - int i; - isdn_ctrl cmd; - u_char *phone_number; - - while (p) { - isdn_net_local *lp = p->local; - -#ifdef ISDN_DEBUG_NET_DIAL - if (lp->dialstate) - printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate); -#endif - switch (lp->dialstate) { - case 0: - /* Nothing to do for this interface */ - break; - case 1: - /* Initiate dialout. Set phone-number-pointer to first number - * of interface. - */ - lp->dial = lp->phone[1]; - if (!lp->dial) { - printk(KERN_WARNING "%s: phone number deleted?\n", - p->dev->name); - isdn_net_hangup(p->dev); - break; - } - anymore = 1; - - if (lp->dialtimeout > 0) - if (lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { - lp->dialstarted = jiffies; - lp->dialwait_timer = 0; - } - - lp->dialstate++; - /* Fall through */ - case 2: - /* Prepare dialing. Clear EAZ, then set EAZ. */ - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - lp->dialretry = 0; - anymore = 1; - lp->dialstate++; - /* Fall through */ - case 3: - /* Setup interface, dial current phone-number, switch to next number. - * If list of phone-numbers is exhausted, increment - * retry-counter. - */ - if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { - char *s; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - s = "dial suppressed: isdn system stopped"; - else - s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(p->dev, NULL, s); - isdn_net_hangup(p->dev); - break; - } - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); - isdn_command(&cmd); - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); - isdn_command(&cmd); - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - if (!lp->dial) { - printk(KERN_WARNING "%s: phone number deleted?\n", - p->dev->name); - isdn_net_hangup(p->dev); - break; - } - if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { - lp->dialstate = 4; - printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name); - } else { - if (lp->dialtimeout > 0) - if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { - lp->dialwait_timer = jiffies + lp->dialwait; - lp->dialstarted = 0; - isdn_net_unreachable(p->dev, NULL, "dial: timed out"); - isdn_net_hangup(p->dev); - break; - } - - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_DIAL; - cmd.parm.setup.si2 = 0; - - /* check for DOV */ - phone_number = lp->dial->num; - if ((*phone_number == 'v') || - (*phone_number == 'V')) { /* DOV call */ - cmd.parm.setup.si1 = 1; - } else { /* DATA call */ - cmd.parm.setup.si1 = 7; - } - - strcpy(cmd.parm.setup.phone, phone_number); - /* - * Switch to next number or back to start if at end of list. - */ - if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { - lp->dial = lp->phone[1]; - lp->dialretry++; - - if (lp->dialretry > lp->dialmax) { - if (lp->dialtimeout == 0) { - lp->dialwait_timer = jiffies + lp->dialwait; - lp->dialstarted = 0; - isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times"); - } - isdn_net_hangup(p->dev); - break; - } - } - sprintf(cmd.parm.setup.eazmsn, "%s", - isdn_map_eaz2msn(lp->msn, cmd.driver)); - i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel); - if (i >= 0) { - strcpy(dev->num[i], cmd.parm.setup.phone); - dev->usage[i] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - } - printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name, - lp->dialretry, cmd.parm.setup.phone, - (cmd.parm.setup.si1 == 1) ? "DOV" : ""); - lp->dtimer = 0; -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, - lp->isdn_channel); -#endif - isdn_command(&cmd); - } - lp->huptimer = 0; - lp->outgoing = 1; - if (lp->chargeint) { - lp->hupflags |= ISDN_HAVECHARGE; - lp->hupflags &= ~ISDN_WAITCHARGE; - } else { - lp->hupflags |= ISDN_WAITCHARGE; - lp->hupflags &= ~ISDN_HAVECHARGE; - } - anymore = 1; - lp->dialstate = - (lp->cbdelay && - (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4; - break; - case 4: - /* Wait for D-Channel-connect. - * If timeout, switch back to state 3. - * Dialmax-handling moved to state 3. - */ - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - lp->dialstate = 3; - anymore = 1; - break; - case 5: - /* Got D-Channel-Connect, send B-Channel-request */ - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTB; - anymore = 1; - lp->dtimer = 0; - lp->dialstate++; - isdn_command(&cmd); - break; - case 6: - /* Wait for B- or D-Channel-connect. If timeout, - * switch back to state 3. - */ -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer); -#endif - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - lp->dialstate = 3; - anymore = 1; - break; - case 7: - /* Got incoming Call, setup L2 and L3 protocols, - * then wait for D-Channel-connect - */ -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); -#endif - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); - isdn_command(&cmd); - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); - isdn_command(&cmd); - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15) - isdn_net_hangup(p->dev); - else { - anymore = 1; - lp->dialstate++; - } - break; - case 9: - /* Got incoming D-Channel-Connect, send B-Channel-request */ - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTB; - isdn_command(&cmd); - anymore = 1; - lp->dtimer = 0; - lp->dialstate++; - break; - case 8: - case 10: - /* Wait for B- or D-channel-connect */ -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); -#endif - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - isdn_net_hangup(p->dev); - else - anymore = 1; - break; - case 11: - /* Callback Delay */ - if (lp->dtimer++ > lp->cbdelay) - lp->dialstate = 1; - anymore = 1; - break; - case 12: - /* Remote does callback. Hangup after cbdelay, then wait for incoming - * call (in state 4). - */ - if (lp->dtimer++ > lp->cbdelay) - { - printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name); - lp->dtimer = 0; - lp->dialstate = 4; - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = lp->isdn_channel; - isdn_command(&cmd); - isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - } - anymore = 1; - break; - default: - printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", - lp->dialstate, p->dev->name); - } - p = (isdn_net_dev *) p->next; - } - isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore); -} - -/* - * Perform hangup for a net-interface. - */ -void -isdn_net_hangup(struct net_device *d) -{ - isdn_net_local *lp = netdev_priv(d); - isdn_ctrl cmd; -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; - struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; -#endif - - if (lp->flags & ISDN_NET_CONNECTED) { - if (lp->slave != NULL) { - isdn_net_local *slp = ISDN_SLAVE_PRIV(lp); - if (slp->flags & ISDN_NET_CONNECTED) { - printk(KERN_INFO - "isdn_net: hang up slave %s before %s\n", - lp->slave->name, d->name); - isdn_net_hangup(lp->slave); - } - } - printk(KERN_INFO "isdn_net: local hangup %s\n", d->name); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); -#ifdef CONFIG_ISDN_X25 - /* try if there are generic encap protocol - receiver routines and signal the closure of - the link */ - if (pops && pops->disconn_ind) - pops->disconn_ind(cprot); -#endif /* CONFIG_ISDN_X25 */ - - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = lp->isdn_channel; - isdn_command(&cmd); - printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge); - isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - } - isdn_net_unbind_channel(lp); -} - -typedef struct { - __be16 source; - __be16 dest; -} ip_ports; - -static void -isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp) -{ - /* hopefully, this was set correctly */ - const u_char *p = skb_network_header(skb); - unsigned short proto = ntohs(skb->protocol); - int data_ofs; - ip_ports *ipp; - char addinfo[100]; - - addinfo[0] = '\0'; - /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ - if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) { - /* fall back to old isdn_net_log_packet method() */ - char *buf = skb->data; - - printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name); - p = buf; - proto = ETH_P_IP; - switch (lp->p_encap) { - case ISDN_NET_ENCAP_IPTYP: - proto = ntohs(*(__be16 *)&buf[0]); - p = &buf[2]; - break; - case ISDN_NET_ENCAP_ETHER: - proto = ntohs(*(__be16 *)&buf[12]); - p = &buf[14]; - break; - case ISDN_NET_ENCAP_CISCOHDLC: - proto = ntohs(*(__be16 *)&buf[2]); - p = &buf[4]; - break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - proto = ntohs(skb->protocol); - p = &buf[IPPP_MAX_HEADER]; - break; -#endif - } - } - data_ofs = ((p[0] & 15) * 4); - switch (proto) { - case ETH_P_IP: - switch (p[9]) { - case 1: - strcpy(addinfo, " ICMP"); - break; - case 2: - strcpy(addinfo, " IGMP"); - break; - case 4: - strcpy(addinfo, " IPIP"); - break; - case 6: - ipp = (ip_ports *) (&p[data_ofs]); - sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source), - ntohs(ipp->dest)); - break; - case 8: - strcpy(addinfo, " EGP"); - break; - case 12: - strcpy(addinfo, " PUP"); - break; - case 17: - ipp = (ip_ports *) (&p[data_ofs]); - sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source), - ntohs(ipp->dest)); - break; - case 22: - strcpy(addinfo, " IDP"); - break; - } - printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n", - p + 12, p + 16, addinfo); - break; - case ETH_P_ARP: - printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n", - p + 14, p + 24); - break; - } -} - -/* - * this function is used to send supervisory data, i.e. data which was - * not received from the network layer, but e.g. frames from ipppd, CCP - * reset frames etc. - */ -void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) -{ - if (in_irq()) { - // we can't grab the lock from irq context, - // so we just queue the packet - skb_queue_tail(&lp->super_tx_queue, skb); - schedule_work(&lp->tqueue); - return; - } - - spin_lock_bh(&lp->xmit_lock); - if (!isdn_net_lp_busy(lp)) { - isdn_net_writebuf_skb(lp, skb); - } else { - skb_queue_tail(&lp->super_tx_queue, skb); - } - spin_unlock_bh(&lp->xmit_lock); -} - -/* - * called from tq_immediate - */ -static void isdn_net_softint(struct work_struct *work) -{ - isdn_net_local *lp = container_of(work, isdn_net_local, tqueue); - struct sk_buff *skb; - - spin_lock_bh(&lp->xmit_lock); - while (!isdn_net_lp_busy(lp)) { - skb = skb_dequeue(&lp->super_tx_queue); - if (!skb) - break; - isdn_net_writebuf_skb(lp, skb); - } - spin_unlock_bh(&lp->xmit_lock); -} - -/* - * all frames sent from the (net) LL to a HL driver should go via this function - * it's serialized by the caller holding the lp->xmit_lock spinlock - */ -void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb) -{ - int ret; - int len = skb->len; /* save len */ - - /* before obtaining the lock the caller should have checked that - the lp isn't busy */ - if (isdn_net_lp_busy(lp)) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - goto error; - } - - if (!(lp->flags & ISDN_NET_CONNECTED)) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - goto error; - } - ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); - if (ret != len) { - /* we should never get here */ - printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name); - goto error; - } - - lp->transcount += len; - isdn_net_inc_frame_cnt(lp); - return; - -error: - dev_kfree_skb(skb); - lp->stats.tx_errors++; - -} - - -/* - * Helper function for isdn_net_start_xmit. - * When called, the connection is already established. - * Based on cps-calculation, check if device is overloaded. - * If so, and if a slave exists, trigger dialing for it. - * If any slave is online, deliver packets using a simple round robin - * scheme. - * - * Return: 0 on success, !0 on failure. - */ - -static int -isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) -{ - isdn_net_dev *nd; - isdn_net_local *slp; - isdn_net_local *lp = netdev_priv(ndev); - int retv = NETDEV_TX_OK; - - if (((isdn_net_local *) netdev_priv(ndev))->master) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* For the other encaps the header has already been built */ -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - return isdn_ppp_xmit(skb, ndev); - } -#endif - nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; - lp = isdn_net_get_locked_lp(nd); - if (!lp) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - return NETDEV_TX_BUSY; - } - /* we have our lp locked from now on */ - - /* Reset hangup-timeout */ - lp->huptimer = 0; // FIXME? - isdn_net_writebuf_skb(lp, skb); - spin_unlock_bh(&lp->xmit_lock); - - /* the following stuff is here for backwards compatibility. - * in future, start-up and hangup of slaves (based on current load) - * should move to userspace and get based on an overall cps - * calculation - */ - if (lp->cps > lp->triggercps) { - if (lp->slave) { - if (!lp->sqfull) { - /* First time overload: set timestamp only */ - lp->sqfull = 1; - lp->sqfull_stamp = jiffies; - } else { - /* subsequent overload: if slavedelay exceeded, start dialing */ - if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { - slp = ISDN_SLAVE_PRIV(lp); - if (!(slp->flags & ISDN_NET_CONNECTED)) { - isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp)); - } - } - } - } - } else { - if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) { - lp->sqfull = 0; - } - /* this is a hack to allow auto-hangup for slaves on moderate loads */ - nd->queue = nd->local; - } - - return retv; - -} - -static void -isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) -{ - isdn_net_local *lp = netdev_priv(dev); - if (!skb) - return; - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { - const int pullsize = skb_network_offset(skb) - ETH_HLEN; - if (pullsize > 0) { - printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize); - skb_pull(skb, pullsize); - } - } -} - - -static void isdn_net_tx_timeout(struct net_device *ndev) -{ - isdn_net_local *lp = netdev_priv(ndev); - - printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate); - if (!lp->dialstate) { - lp->stats.tx_errors++; - /* - * There is a certain probability that this currently - * works at all because if we always wake up the interface, - * then upper layer will try to send the next packet - * immediately. And then, the old clean_up logic in the - * driver will hopefully continue to work as it used to do. - * - * This is rather primitive right know, we better should - * clean internal queues here, in particular for multilink and - * ppp, and reset HL driver's channel, too. --HE - * - * actually, this may not matter at all, because ISDN hardware - * should not see transmitter hangs at all IMO - * changed KERN_DEBUG to KERN_WARNING to find out if this is - * ever called --KG - */ - } - netif_trans_update(ndev); - netif_wake_queue(ndev); -} - -/* - * Try sending a packet. - * If this interface isn't connected to a ISDN-Channel, find a free channel, - * and start dialing. - */ -static netdev_tx_t -isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - isdn_net_local *lp = netdev_priv(ndev); -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; -/* At this point hard_start_xmit() passes control to the encapsulation - protocol (if present). - For X.25 auto-dialing is completly bypassed because: - - It does not conform with the semantics of a reliable datalink - service as needed by X.25 PLP. - - I don't want that the interface starts dialing when the network layer - sends a message which requests to disconnect the lapb link (or if it - sends any other message not resulting in data transmission). - Instead, dialing will be initiated by the encapsulation protocol entity - when a dl_establish request is received from the upper layer. -*/ - if (cprot && cprot->pops) { - int ret = cprot->pops->encap_and_xmit(cprot, skb); - - if (ret) - netif_stop_queue(ndev); - return ret; - } else -#endif - /* auto-dialing xmit function */ - { -#ifdef ISDN_DEBUG_NET_DUMP - u_char *buf; -#endif - isdn_net_adjust_hdr(skb, ndev); -#ifdef ISDN_DEBUG_NET_DUMP - buf = skb->data; - isdn_dumppkt("S:", buf, skb->len, 40); -#endif - - if (!(lp->flags & ISDN_NET_CONNECTED)) { - int chi; - /* only do autodial if allowed by config */ - if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { - isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - if (lp->phone[1]) { - ulong flags; - - if (lp->dialwait_timer <= 0) - if (lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) - lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; - - if (lp->dialwait_timer > 0) { - if (time_before(jiffies, lp->dialwait_timer)) { - isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - lp->dialwait_timer = 0; - } - /* Grab a free ISDN-Channel */ - spin_lock_irqsave(&dev->lock, flags); - if (((chi = - isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn) - ) < 0) && - ((chi = - isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel^1, - lp->msn) - ) < 0)) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_unreachable(ndev, skb, - "No channel"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - /* Log packet, which triggered dialing */ - if (dev->net_verbose) - isdn_net_log_skb(skb, lp); - lp->dialstate = 1; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - /* no 'first_skb' handling for syncPPP */ - if (isdn_ppp_bind(lp) < 0) { - dev_kfree_skb(skb); - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */ - } -#ifdef CONFIG_IPPP_FILTER - if (isdn_ppp_autodial_filter(skb, lp)) { - isdn_ppp_free(lp); - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } -#endif - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_dial(); /* Initiate dialing */ - netif_stop_queue(ndev); - return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */ - } -#endif - /* Initiate dialing */ - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_dial(); - isdn_net_device_stop_queue(lp); - return NETDEV_TX_BUSY; - } else { - isdn_net_unreachable(ndev, skb, - "No phone number"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - } else { - /* Device is connected to an ISDN channel */ - netif_trans_update(ndev); - if (!lp->dialstate) { - /* ISDN connection is established, try sending */ - int ret; - ret = (isdn_net_xmit(ndev, skb)); - if (ret) netif_stop_queue(ndev); - return ret; - } else - netif_stop_queue(ndev); - } - } - return NETDEV_TX_BUSY; -} - -/* - * Shutdown a net-interface. - */ -static int -isdn_net_close(struct net_device *dev) -{ - struct net_device *p; -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = - ((isdn_net_local *)netdev_priv(dev))->netdev->cprot; - /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name); */ -#endif - -#ifdef CONFIG_ISDN_X25 - if (cprot && cprot->pops) cprot->pops->close(cprot); -#endif - netif_stop_queue(dev); - p = MASTER_TO_SLAVE(dev); - if (p) { - /* If this interface has slaves, stop them also */ - while (p) { -#ifdef CONFIG_ISDN_X25 - cprot = ((isdn_net_local *)netdev_priv(p)) - ->netdev->cprot; - if (cprot && cprot->pops) - cprot->pops->close(cprot); -#endif - isdn_net_hangup(p); - p = MASTER_TO_SLAVE(p); - } - } - isdn_net_hangup(dev); - isdn_unlock_drivers(); - return 0; -} - -/* - * Get statistics - */ -static struct net_device_stats * -isdn_net_get_stats(struct net_device *dev) -{ - isdn_net_local *lp = netdev_priv(dev); - return &lp->stats; -} - -/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN - * instead of dev->hard_header_len off. This is done because the - * lowlevel-driver has already pulled off its stuff when we get - * here and this routine only gets called with p_encap == ETHER. - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - */ - -static __be16 -isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct ethhdr *eth; - unsigned char *rawp; - - skb_reset_mac_header(skb); - skb_pull(skb, ETH_HLEN); - eth = eth_hdr(skb); - - if (*eth->h_dest & 1) { - if (ether_addr_equal(eth->h_dest, dev->broadcast)) - skb->pkt_type = PACKET_BROADCAST; - else - skb->pkt_type = PACKET_MULTICAST; - } - /* - * This ALLMULTI check should be redundant by 1.4 - * so don't forget to remove it. - */ - - else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) { - if (!ether_addr_equal(eth->h_dest, dev->dev_addr)) - skb->pkt_type = PACKET_OTHERHOST; - } - if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) - return eth->h_proto; - - rawp = skb->data; - - /* - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - if (*(unsigned short *) rawp == 0xFFFF) - return htons(ETH_P_802_3); - /* - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); -} - - -/* - * CISCO HDLC keepalive specific stuff - */ -static struct sk_buff* -isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) -{ - unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - struct sk_buff *skb; - - skb = alloc_skb(hl + len, GFP_ATOMIC); - if (skb) - skb_reserve(skb, hl); - else - printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); - return skb; -} - -/* cisco hdlck device private ioctls */ -static int -isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - isdn_net_local *lp = netdev_priv(dev); - unsigned long len = 0; - unsigned long expires = 0; - int tmp = 0; - int period = lp->cisco_keepalive_period; - s8 debserint = lp->cisco_debserint; - int rc = 0; - - if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK) - return -EINVAL; - - switch (cmd) { - /* get/set keepalive period */ - case SIOCGKEEPPERIOD: - len = (unsigned long)sizeof(lp->cisco_keepalive_period); - if (copy_to_user(ifr->ifr_data, - &lp->cisco_keepalive_period, len)) - rc = -EFAULT; - break; - case SIOCSKEEPPERIOD: - tmp = lp->cisco_keepalive_period; - len = (unsigned long)sizeof(lp->cisco_keepalive_period); - if (copy_from_user(&period, ifr->ifr_data, len)) - rc = -EFAULT; - if ((period > 0) && (period <= 32767)) - lp->cisco_keepalive_period = period; - else - rc = -EINVAL; - if (!rc && (tmp != lp->cisco_keepalive_period)) { - expires = (unsigned long)(jiffies + - lp->cisco_keepalive_period * HZ); - mod_timer(&lp->cisco_timer, expires); - printk(KERN_INFO "%s: Keepalive period set " - "to %d seconds.\n", - dev->name, lp->cisco_keepalive_period); - } - break; - - /* get/set debugging */ - case SIOCGDEBSERINT: - len = (unsigned long)sizeof(lp->cisco_debserint); - if (copy_to_user(ifr->ifr_data, - &lp->cisco_debserint, len)) - rc = -EFAULT; - break; - case SIOCSDEBSERINT: - len = (unsigned long)sizeof(lp->cisco_debserint); - if (copy_from_user(&debserint, - ifr->ifr_data, len)) - rc = -EFAULT; - if ((debserint >= 0) && (debserint <= 64)) - lp->cisco_debserint = debserint; - else - rc = -EINVAL; - break; - - default: - rc = -EINVAL; - break; - } - return (rc); -} - - -static int isdn_net_ioctl(struct net_device *dev, - struct ifreq *ifr, int cmd) -{ - isdn_net_local *lp = netdev_priv(dev); - - switch (lp->p_encap) { -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - return isdn_ppp_dev_ioctl(dev, ifr, cmd); -#endif - case ISDN_NET_ENCAP_CISCOHDLCK: - return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd); - default: - return -EINVAL; - } -} - -/* called via cisco_timer.function */ -static void -isdn_net_ciscohdlck_slarp_send_keepalive(struct timer_list *t) -{ - isdn_net_local *lp = from_timer(lp, t, cisco_timer); - struct sk_buff *skb; - unsigned char *p; - unsigned long last_cisco_myseq = lp->cisco_myseq; - int myseq_diff = 0; - - if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - return; - } - lp->cisco_myseq++; - - myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen); - if ((lp->cisco_line_state) && ((myseq_diff >= 3) || (myseq_diff <= -3))) { - /* line up -> down */ - lp->cisco_line_state = 0; - printk(KERN_WARNING - "UPDOWN: Line protocol on Interface %s," - " changed state to down\n", lp->netdev->dev->name); - /* should stop routing higher-level data across */ - } else if ((!lp->cisco_line_state) && - (myseq_diff >= 0) && (myseq_diff <= 2)) { - /* line down -> up */ - lp->cisco_line_state = 1; - printk(KERN_WARNING - "UPDOWN: Line protocol on Interface %s," - " changed state to up\n", lp->netdev->dev->name); - /* restart routing higher-level data across */ - } - - if (lp->cisco_debserint) - printk(KERN_DEBUG "%s: HDLC " - "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n", - lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen, - ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040), - lp->cisco_yourseq, - ((lp->cisco_line_state) ? "line up" : "line down")); - - skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); - - /* slarp keepalive */ - *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE); - *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq); - *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq); - *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff - p += 18; - - isdn_net_write_super(lp, skb); - - lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; - - add_timer(&lp->cisco_timer); -} - -static void -isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp) -{ - struct sk_buff *skb; - unsigned char *p; - - skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); - - /* slarp request */ - *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST); - *(__be32 *)(p + 8) = cpu_to_be32(0); // address - *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask - *(__be16 *)(p + 16) = cpu_to_be16(0); // unused - p += 18; - - isdn_net_write_super(lp, skb); -} - -static void -isdn_net_ciscohdlck_connected(isdn_net_local *lp) -{ - lp->cisco_myseq = 0; - lp->cisco_mineseen = 0; - lp->cisco_yourseq = 0; - lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT; - lp->cisco_last_slarp_in = 0; - lp->cisco_line_state = 0; - lp->cisco_debserint = 0; - - /* send slarp request because interface/seq.no.s reset */ - isdn_net_ciscohdlck_slarp_send_request(lp); - - timer_setup(&lp->cisco_timer, - isdn_net_ciscohdlck_slarp_send_keepalive, 0); - lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; - add_timer(&lp->cisco_timer); -} - -static void -isdn_net_ciscohdlck_disconnected(isdn_net_local *lp) -{ - del_timer(&lp->cisco_timer); -} - -static void -isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) -{ - struct sk_buff *skb; - unsigned char *p; - struct in_device *in_dev = NULL; - __be32 addr = 0; /* local ipv4 address */ - __be32 mask = 0; /* local netmask */ - - if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) { - /* take primary(first) address of interface */ - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL) { - addr = ifa->ifa_local; - mask = ifa->ifa_mask; - } - } - - skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); - - /* slarp reply, send own ip/netmask; if values are nonsense remote - * should think we are unable to provide it with an address via SLARP */ - *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY); - *(__be32 *)(p + 8) = addr; // address - *(__be32 *)(p + 12) = mask; // netmask - *(__be16 *)(p + 16) = cpu_to_be16(0); // unused - p += 18; - - isdn_net_write_super(lp, skb); -} - -static void -isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) -{ - unsigned char *p; - int period; - u32 code; - u32 my_seq; - u32 your_seq; - __be32 local; - __be32 *addr, *mask; - - if (skb->len < 14) - return; - - p = skb->data; - code = be32_to_cpup((__be32 *)p); - p += 4; - - switch (code) { - case CISCO_SLARP_REQUEST: - lp->cisco_yourseq = 0; - isdn_net_ciscohdlck_slarp_send_reply(lp); - break; - case CISCO_SLARP_REPLY: - addr = (__be32 *)p; - mask = (__be32 *)(p + 4); - if (*mask != cpu_to_be32(0xfffffffc)) - goto slarp_reply_out; - if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) || - (*addr & cpu_to_be32(3)) == cpu_to_be32(3)) - goto slarp_reply_out; - local = *addr ^ cpu_to_be32(3); - printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n", - lp->netdev->dev->name, addr, &local, mask); - break; - slarp_reply_out: - printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n", - lp->netdev->dev->name, addr, mask); - break; - case CISCO_SLARP_KEEPALIVE: - period = (int)((jiffies - lp->cisco_last_slarp_in - + HZ / 2 - 1) / HZ); - if (lp->cisco_debserint && - (period != lp->cisco_keepalive_period) && - lp->cisco_last_slarp_in) { - printk(KERN_DEBUG "%s: Keepalive period mismatch - " - "is %d but should be %d.\n", - lp->netdev->dev->name, period, - lp->cisco_keepalive_period); - } - lp->cisco_last_slarp_in = jiffies; - my_seq = be32_to_cpup((__be32 *)(p + 0)); - your_seq = be32_to_cpup((__be32 *)(p + 4)); - p += 10; - lp->cisco_yourseq = my_seq; - lp->cisco_mineseen = your_seq; - break; - } -} - -static void -isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) -{ - unsigned char *p; - u8 addr; - u8 ctrl; - u16 type; - - if (skb->len < 4) - goto out_free; - - p = skb->data; - addr = *(u8 *)(p + 0); - ctrl = *(u8 *)(p + 1); - type = be16_to_cpup((__be16 *)(p + 2)); - p += 4; - skb_pull(skb, 4); - - if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { - printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", - lp->netdev->dev->name, addr); - goto out_free; - } - if (ctrl != CISCO_CTRL) { - printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", - lp->netdev->dev->name, ctrl); - goto out_free; - } - - switch (type) { - case CISCO_TYPE_SLARP: - isdn_net_ciscohdlck_slarp_in(lp, skb); - goto out_free; - case CISCO_TYPE_CDP: - if (lp->cisco_debserint) - printk(KERN_DEBUG "%s: Received CDP packet. use " - "\"no cdp enable\" on cisco.\n", - lp->netdev->dev->name); - goto out_free; - default: - /* no special cisco protocol */ - skb->protocol = htons(type); - netif_rx(skb); - return; - } - -out_free: - kfree_skb(skb); -} - -/* - * Got a packet from ISDN-Channel. - */ -static void -isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) -{ - isdn_net_local *lp = netdev_priv(ndev); - isdn_net_local *olp = lp; /* original 'lp' */ -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; -#endif - lp->transcount += skb->len; - - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; - if (lp->master) { - /* Bundling: If device is a slave-device, deliver to master, also - * handle master's statistics and hangup-timeout - */ - ndev = lp->master; - lp = netdev_priv(ndev); - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; - } - skb->dev = ndev; - skb->pkt_type = PACKET_HOST; - skb_reset_mac_header(skb); -#ifdef ISDN_DEBUG_NET_DUMP - isdn_dumppkt("R:", skb->data, skb->len, 40); -#endif - switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - /* Ethernet over ISDN */ - olp->huptimer = 0; - lp->huptimer = 0; - skb->protocol = isdn_net_type_trans(skb, ndev); - break; - case ISDN_NET_ENCAP_UIHDLC: - /* HDLC with UI-frame (for ispa with -h1 option) */ - olp->huptimer = 0; - lp->huptimer = 0; - skb_pull(skb, 2); - /* Fall through */ - case ISDN_NET_ENCAP_RAWIP: - /* RAW-IP without MAC-Header */ - olp->huptimer = 0; - lp->huptimer = 0; - skb->protocol = htons(ETH_P_IP); - break; - case ISDN_NET_ENCAP_CISCOHDLCK: - isdn_net_ciscohdlck_receive(lp, skb); - return; - case ISDN_NET_ENCAP_CISCOHDLC: - /* CISCO-HDLC IP with type field and fake I-frame-header */ - skb_pull(skb, 2); - /* Fall through */ - case ISDN_NET_ENCAP_IPTYP: - /* IP with type field */ - olp->huptimer = 0; - lp->huptimer = 0; - skb->protocol = *(__be16 *)&(skb->data[0]); - skb_pull(skb, 2); - if (*(unsigned short *) skb->data == 0xFFFF) - skb->protocol = htons(ETH_P_802_3); - break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - /* huptimer is done in isdn_ppp_push_higher */ - isdn_ppp_receive(lp->netdev, olp, skb); - return; -#endif - - default: -#ifdef CONFIG_ISDN_X25 - /* try if there are generic sync_device receiver routines */ - if (cprot) if (cprot->pops) - if (cprot->pops->data_ind) { - cprot->pops->data_ind(cprot, skb); - return; - }; -#endif /* CONFIG_ISDN_X25 */ - printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", - lp->netdev->dev->name); - kfree_skb(skb); - return; - } - - netif_rx(skb); - return; -} - -/* - * A packet arrived via ISDN. Search interface-chain for a corresponding - * interface. If found, deliver packet to receiver-function and return 1, - * else return 0. - */ -int -isdn_net_rcv_skb(int idx, struct sk_buff *skb) -{ - isdn_net_dev *p = dev->rx_netdev[idx]; - - if (p) { - isdn_net_local *lp = p->local; - if ((lp->flags & ISDN_NET_CONNECTED) && - (!lp->dialstate)) { - isdn_net_receive(p->dev, skb); - return 1; - } - } - return 0; -} - -/* - * build an header - * depends on encaps that is being used. - */ - -static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned plen) -{ - isdn_net_local *lp = netdev_priv(dev); - unsigned char *p; - int len = 0; - - switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - len = eth_header(skb, dev, type, daddr, saddr, plen); - break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - /* stick on a fake header to keep fragmentation code happy. */ - len = IPPP_MAX_HEADER; - skb_push(skb, len); - break; -#endif - case ISDN_NET_ENCAP_RAWIP: - printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n"); - len = 0; - break; - case ISDN_NET_ENCAP_IPTYP: - /* ethernet type field */ - *((__be16 *)skb_push(skb, 2)) = htons(type); - len = 2; - break; - case ISDN_NET_ENCAP_UIHDLC: - /* HDLC with UI-Frames (for ispa with -h1 option) */ - *((__be16 *)skb_push(skb, 2)) = htons(0x0103); - len = 2; - break; - case ISDN_NET_ENCAP_CISCOHDLC: - case ISDN_NET_ENCAP_CISCOHDLCK: - p = skb_push(skb, 4); - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(type); - p += 4; - len = 4; - break; -#ifdef CONFIG_ISDN_X25 - default: - /* try if there are generic concap protocol routines */ - if (lp->netdev->cprot) { - printk(KERN_WARNING "isdn_net_header called with concap_proto!\n"); - len = 0; - break; - } - break; -#endif /* CONFIG_ISDN_X25 */ - } - return len; -} - -static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh, - __be16 type) -{ - const struct net_device *dev = neigh->dev; - isdn_net_local *lp = netdev_priv(dev); - - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) - return eth_header_cache(neigh, hh, type); - return -1; -} - -static void isdn_header_cache_update(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char *haddr) -{ - isdn_net_local *lp = netdev_priv(dev); - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) - eth_header_cache_update(hh, dev, haddr); -} - -static const struct header_ops isdn_header_ops = { - .create = isdn_net_header, - .cache = isdn_header_cache, - .cache_update = isdn_header_cache_update, -}; - -/* - * Interface-setup. (just after registering a new interface) - */ -static int -isdn_net_init(struct net_device *ndev) -{ - ushort max_hlhdr_len = 0; - int drvidx; - - /* - * up till binding we ask the protocol layer to reserve as much - * as we might need for HL layer - */ - - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) - if (dev->drv[drvidx]) - if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen) - max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; - - ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; - return 0; -} - -static void -isdn_net_swapbind(int drvidx) -{ - isdn_net_dev *p; - -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx); -#endif - p = dev->netdev; - while (p) { - if (p->local->pre_device == drvidx) - switch (p->local->pre_channel) { - case 0: - p->local->pre_channel = 1; - break; - case 1: - p->local->pre_channel = 0; - break; - } - p = (isdn_net_dev *) p->next; - } -} - -static void -isdn_net_swap_usage(int i1, int i2) -{ - int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE; - int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE; - -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2); -#endif - dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE; - dev->usage[i1] |= u2; - dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE; - dev->usage[i2] |= u1; - isdn_info_update(); -} - -/* - * An incoming call-request has arrived. - * Search the interface-chain for an appropriate interface. - * If found, connect the interface to the ISDN-channel and initiate - * D- and B-Channel-setup. If secure-flag is set, accept only - * configured phone-numbers. If callback-flag is set, initiate - * callback-dialing. - * - * Return-Value: 0 = No appropriate interface for this call. - * 1 = Call accepted - * 2 = Reject call, wait cbdelay, then call back - * 3 = Reject call - * 4 = Wait cbdelay, then call back - * 5 = No appropriate interface for this call, - * would eventually match if CID was longer. - */ - -int -isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) -{ - char *eaz; - int si1; - int si2; - int ematch; - int wret; - int swapped; - int sidx = 0; - u_long flags; - isdn_net_dev *p; - isdn_net_phone *n; - char nr[ISDN_MSNLEN]; - char *my_eaz; - - /* Search name in netdev-chain */ - if (!setup->phone[0]) { - nr[0] = '0'; - nr[1] = '\0'; - printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); - } else - strlcpy(nr, setup->phone, ISDN_MSNLEN); - si1 = (int) setup->si1; - si2 = (int) setup->si2; - if (!setup->eazmsn[0]) { - printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); - eaz = "0"; - } else - eaz = setup->eazmsn; - if (dev->net_verbose > 1) - printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); - /* Accept DATA and VOICE calls at this stage - * local eaz is checked later for allowed call types - */ - if ((si1 != 7) && (si1 != 1)) { - if (dev->net_verbose > 1) - printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n"); - return 0; - } - n = (isdn_net_phone *) 0; - p = dev->netdev; - ematch = wret = swapped = 0; -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, - dev->usage[idx]); -#endif - while (p) { - int matchret; - isdn_net_local *lp = p->local; - - /* If last check has triggered as binding-swap, revert it */ - switch (swapped) { - case 2: - isdn_net_swap_usage(idx, sidx); - /* fall through */ - case 1: - isdn_net_swapbind(di); - break; - } - swapped = 0; - /* check acceptable call types for DOV */ - my_eaz = isdn_map_eaz2msn(lp->msn, di); - if (si1 == 1) { /* it's a DOV call, check if we allow it */ - if (*my_eaz == 'v' || *my_eaz == 'V' || - *my_eaz == 'b' || *my_eaz == 'B') - my_eaz++; /* skip to allow a match */ - else - my_eaz = NULL; /* force non match */ - } else { /* it's a DATA call, check if we allow it */ - if (*my_eaz == 'b' || *my_eaz == 'B') - my_eaz++; /* skip to allow a match */ - } - if (my_eaz) - matchret = isdn_msncmp(eaz, my_eaz); - else - matchret = 1; - if (!matchret) - ematch = 1; - - /* Remember if more numbers eventually can match */ - if (matchret > wret) - wret = matchret; -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", - p->dev->name, lp->msn, lp->flags, lp->dialstate); -#endif - if ((!matchret) && /* EAZ is matching */ - (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ - (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ - ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ - (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ - ))) - { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", - lp->pre_device, lp->pre_channel); -#endif - if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) { - if ((lp->pre_channel != ch) || - (lp->pre_device != di)) { - /* Here we got a problem: - * If using an ICN-Card, an incoming call is always signaled on - * on the first channel of the card, if both channels are - * down. However this channel may be bound exclusive. If the - * second channel is free, this call should be accepted. - * The solution is horribly but it runs, so what: - * We exchange the exclusive bindings of the two channels, the - * corresponding variables in the interface-structs. - */ - if (ch == 0) { - sidx = isdn_dc2minor(di, 1); -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: ch is 0\n"); -#endif - if (USG_NONE(dev->usage[sidx])) { - /* Second Channel is free, now see if it is bound - * exclusive too. */ - if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n"); -#endif - /* Yes, swap bindings only, if the original - * binding is bound to channel 1 of this driver */ - if ((lp->pre_device == di) && - (lp->pre_channel == 1)) { - isdn_net_swapbind(di); - swapped = 1; - } else { - /* ... else iterate next device */ - p = (isdn_net_dev *) p->next; - continue; - } - } else { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n"); -#endif - /* No, swap always and swap excl-usage also */ - isdn_net_swap_usage(idx, sidx); - isdn_net_swapbind(di); - swapped = 2; - } - /* Now check for exclusive binding again */ -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: final check\n"); -#endif - if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) && - ((lp->pre_channel != ch) || - (lp->pre_device != di))) { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: final check failed\n"); -#endif - p = (isdn_net_dev *) p->next; - continue; - } - } - } else { - /* We are already on the second channel, so nothing to do */ -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: already on 2nd channel\n"); -#endif - } - } - } -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: match2\n"); -#endif - n = lp->phone[0]; - if (lp->flags & ISDN_NET_SECURE) { - while (n) { - if (!isdn_msncmp(nr, n->num)) - break; - n = (isdn_net_phone *) n->next; - } - } - if (n || (!(lp->flags & ISDN_NET_SECURE))) { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: match3\n"); -#endif - /* matching interface found */ - - /* - * Is the state STOPPED? - * If so, no dialin is allowed, - * so reject actively. - * */ - if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { - printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", - p->dev->name); - return 3; - } - /* - * Is the interface up? - * If not, reject the call actively. - */ - if (!isdn_net_device_started(p)) { - printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", - p->dev->name); - return 3; - } - /* Interface is up, now see if it's a slave. If so, see if - * it's master and parent slave is online. If not, reject the call. - */ - if (lp->master) { - isdn_net_local *mlp = ISDN_MASTER_PRIV(lp); - printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name); - printk(KERN_DEBUG "master=%s\n", lp->master->name); - if (mlp->flags & ISDN_NET_CONNECTED) { - printk(KERN_DEBUG "master online\n"); - /* Master is online, find parent-slave (master if first slave) */ - while (mlp->slave) { - if (ISDN_SLAVE_PRIV(mlp) == lp) - break; - mlp = ISDN_SLAVE_PRIV(mlp); - } - } else - printk(KERN_DEBUG "master offline\n"); - /* Found parent, if it's offline iterate next device */ - printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED); - if (!(mlp->flags & ISDN_NET_CONNECTED)) { - p = (isdn_net_dev *) p->next; - continue; - } - } - if (lp->flags & ISDN_NET_CALLBACK) { - int chi; - /* - * Is the state MANUAL? - * If so, no callback can be made, - * so reject actively. - * */ - if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { - printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", - p->dev->name); - return 3; - } - printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", - p->dev->name, nr, eaz); - if (lp->phone[1]) { - /* Grab a free ISDN-Channel */ - spin_lock_irqsave(&dev->lock, flags); - if ((chi = - isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn) - ) < 0) { - - printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", - p->dev->name); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - /* Setup dialstate. */ - lp->dtimer = 0; - lp->dialstate = 11; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_unbind_channel(lp); - return 0; - } -#endif - spin_unlock_irqrestore(&dev->lock, flags); - /* Initiate dialing by returning 2 or 4 */ - return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; - } else - printk(KERN_WARNING "isdn_net: %s: No phone number\n", - p->dev->name); - return 0; - } else { - printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", - p->dev->name, nr, eaz); - /* if this interface is dialing, it does it probably on a different - device, so free this device */ - if ((lp->dialstate == 4) || (lp->dialstate == 12)) { -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); - isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); - } - spin_lock_irqsave(&dev->lock, flags); - dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= ISDN_USAGE_NET; - strcpy(dev->num[idx], nr); - isdn_info_update(); - dev->st_netdev[idx] = lp->netdev; - lp->isdn_device = di; - lp->isdn_channel = ch; - lp->ppp_slot = -1; - lp->flags |= ISDN_NET_CONNECTED; - lp->dialstate = 7; - lp->dtimer = 0; - lp->outgoing = 0; - lp->huptimer = 0; - lp->hupflags |= ISDN_WAITCHARGE; - lp->hupflags &= ~ISDN_HAVECHARGE; -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - } -#endif - spin_unlock_irqrestore(&dev->lock, flags); - return 1; - } - } - } - p = (isdn_net_dev *) p->next; - } - /* If none of configured EAZ/MSN matched and not verbose, be silent */ - if (!ematch || dev->net_verbose) - printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz); - return (wret == 2) ? 5 : 0; -} - -/* - * Search list of net-interfaces for an interface with given name. - */ -isdn_net_dev * -isdn_net_findif(char *name) -{ - isdn_net_dev *p = dev->netdev; - - while (p) { - if (!strcmp(p->dev->name, name)) - return p; - p = (isdn_net_dev *) p->next; - } - return (isdn_net_dev *) NULL; -} - -/* - * Force a net-interface to dial out. - * This is called from the userlevel-routine below or - * from isdn_net_start_xmit(). - */ -static int -isdn_net_force_dial_lp(isdn_net_local *lp) -{ - if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) { - int chi; - if (lp->phone[1]) { - ulong flags; - - /* Grab a free ISDN-Channel */ - spin_lock_irqsave(&dev->lock, flags); - if ((chi = isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn)) < 0) { - printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", - lp->netdev->dev->name); - spin_unlock_irqrestore(&dev->lock, flags); - return -EAGAIN; - } - lp->dialstate = 1; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - return -EAGAIN; - } -#endif - /* Initiate dialing */ - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_dial(); - return 0; - } else - return -EINVAL; - } else - return -EBUSY; -} - -/* - * This is called from certain upper protocol layers (multilink ppp - * and x25iface encapsulation module) that want to initiate dialing - * themselves. - */ -int -isdn_net_dial_req(isdn_net_local *lp) -{ - /* is there a better error code? */ - if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY; - - return isdn_net_force_dial_lp(lp); -} - -/* - * Force a net-interface to dial out. - * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). - */ -int -isdn_net_force_dial(char *name) -{ - isdn_net_dev *p = isdn_net_findif(name); - - if (!p) - return -ENODEV; - return (isdn_net_force_dial_lp(p->local)); -} - -/* The ISDN-specific entries in the device structure. */ -static const struct net_device_ops isdn_netdev_ops = { - .ndo_init = isdn_net_init, - .ndo_open = isdn_net_open, - .ndo_stop = isdn_net_close, - .ndo_do_ioctl = isdn_net_ioctl, - - .ndo_start_xmit = isdn_net_start_xmit, - .ndo_get_stats = isdn_net_get_stats, - .ndo_tx_timeout = isdn_net_tx_timeout, -}; - -/* - * Helper for alloc_netdev() - */ -static void _isdn_setup(struct net_device *dev) -{ - isdn_net_local *lp = netdev_priv(dev); - - ether_setup(dev); - - /* Setup the generic properties */ - dev->flags = IFF_NOARP | IFF_POINTOPOINT; - - /* isdn prepends a header in the tx path, can't share skbs */ - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->header_ops = NULL; - dev->netdev_ops = &isdn_netdev_ops; - - /* for clients with MPPP maybe higher values better */ - dev->tx_queue_len = 30; - - lp->p_encap = ISDN_NET_ENCAP_RAWIP; - lp->magic = ISDN_NET_MAGIC; - lp->last = lp; - lp->next = lp; - lp->isdn_device = -1; - lp->isdn_channel = -1; - lp->pre_device = -1; - lp->pre_channel = -1; - lp->exclusive = -1; - lp->ppp_slot = -1; - lp->pppbind = -1; - skb_queue_head_init(&lp->super_tx_queue); - lp->l2_proto = ISDN_PROTO_L2_X75I; - lp->l3_proto = ISDN_PROTO_L3_TRANS; - lp->triggercps = 6000; - lp->slavedelay = 10 * HZ; - lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ - lp->onhtime = 10; /* Default hangup-time for saving costs */ - lp->dialmax = 1; - /* Hangup before Callback, manual dial */ - lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; - lp->cbdelay = 25; /* Wait 5 secs before Callback */ - lp->dialtimeout = -1; /* Infinite Dial-Timeout */ - lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ - lp->dialstarted = 0; /* Jiffies of last dial-start */ - lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ -} - -/* - * Allocate a new network-interface and initialize its data structures. - */ -char * -isdn_net_new(char *name, struct net_device *master) -{ - isdn_net_dev *netdev; - - /* Avoid creating an existing interface */ - if (isdn_net_findif(name)) { - printk(KERN_WARNING "isdn_net: interface %s already exists\n", name); - return NULL; - } - if (name == NULL) - return NULL; - if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); - return NULL; - } - netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, - NET_NAME_UNKNOWN, _isdn_setup); - if (!netdev->dev) { - printk(KERN_WARNING "isdn_net: Could not allocate network device\n"); - kfree(netdev); - return NULL; - } - netdev->local = netdev_priv(netdev->dev); - - if (master) { - /* Device shall be a slave */ - struct net_device *p = MASTER_TO_SLAVE(master); - struct net_device *q = master; - - netdev->local->master = master; - /* Put device at end of slave-chain */ - while (p) { - q = p; - p = MASTER_TO_SLAVE(p); - } - MASTER_TO_SLAVE(q) = netdev->dev; - } else { - /* Device shall be a master */ - /* - * Watchdog timer (currently) for master only. - */ - netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT; - if (register_netdev(netdev->dev) != 0) { - printk(KERN_WARNING "isdn_net: Could not register net-device\n"); - free_netdev(netdev->dev); - kfree(netdev); - return NULL; - } - } - netdev->queue = netdev->local; - spin_lock_init(&netdev->queue_lock); - - netdev->local->netdev = netdev; - - INIT_WORK(&netdev->local->tqueue, isdn_net_softint); - spin_lock_init(&netdev->local->xmit_lock); - - /* Put into to netdev-chain */ - netdev->next = (void *) dev->netdev; - dev->netdev = netdev; - return netdev->dev->name; -} - -char * -isdn_net_newslave(char *parm) -{ - char *p = strchr(parm, ','); - isdn_net_dev *n; - char newname[10]; - - if (p) { - /* Slave-Name MUST not be empty or overflow 'newname' */ - if (strscpy(newname, p + 1, sizeof(newname)) <= 0) - return NULL; - *p = 0; - /* Master must already exist */ - if (!(n = isdn_net_findif(parm))) - return NULL; - /* Master must be a real interface, not a slave */ - if (n->local->master) - return NULL; - /* Master must not be started yet */ - if (isdn_net_device_started(n)) - return NULL; - return (isdn_net_new(newname, n->dev)); - } - return NULL; -} - -/* - * Set interface-parameters. - * Always set all parameters, so the user-level application is responsible - * for not overwriting existing setups. It has to get the current - * setup first, if only selected parameters are to be changed. - */ -int -isdn_net_setcfg(isdn_net_ioctl_cfg *cfg) -{ - isdn_net_dev *p = isdn_net_findif(cfg->name); - ulong features; - int i; - int drvidx; - int chidx; - char drvid[25]; - - if (p) { - isdn_net_local *lp = p->local; - - /* See if any registered driver supports the features we want */ - features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) | - ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT); - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (dev->drv[i]) - if ((dev->drv[i]->interface->features & features) == features) - break; - if (i == ISDN_MAX_DRIVERS) { - printk(KERN_WARNING "isdn_net: No driver with selected features\n"); - return -ENODEV; - } - if (lp->p_encap != cfg->p_encap) { -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = p->cprot; -#endif - if (isdn_net_device_started(p)) { - printk(KERN_WARNING "%s: cannot change encap when if is up\n", - p->dev->name); - return -EBUSY; - } -#ifdef CONFIG_ISDN_X25 - if (cprot && cprot->pops) - cprot->pops->proto_del(cprot); - p->cprot = NULL; - lp->dops = NULL; - /* ... , prepare for configuration of new one ... */ - switch (cfg->p_encap) { - case ISDN_NET_ENCAP_X25IFACE: - lp->dops = &isdn_concap_reliable_dl_dops; - } - /* ... and allocate new one ... */ - p->cprot = isdn_concap_new(cfg->p_encap); - /* p -> cprot == NULL now if p_encap is not supported - by means of the concap_proto mechanism */ - /* the protocol is not configured yet; this will - happen later when isdn_net_reset() is called */ -#endif - } - switch (cfg->p_encap) { - case ISDN_NET_ENCAP_SYNCPPP: -#ifndef CONFIG_ISDN_PPP - printk(KERN_WARNING "%s: SyncPPP support not configured\n", - p->dev->name); - return -EINVAL; -#else - p->dev->type = ARPHRD_PPP; /* change ARP type */ - p->dev->addr_len = 0; -#endif - break; - case ISDN_NET_ENCAP_X25IFACE: -#ifndef CONFIG_ISDN_X25 - printk(KERN_WARNING "%s: isdn-x25 support not configured\n", - p->dev->name); - return -EINVAL; -#else - p->dev->type = ARPHRD_X25; /* change ARP type */ - p->dev->addr_len = 0; -#endif - break; - case ISDN_NET_ENCAP_CISCOHDLCK: - break; - default: - if (cfg->p_encap >= 0 && - cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP) - break; - printk(KERN_WARNING - "%s: encapsulation protocol %d not supported\n", - p->dev->name, cfg->p_encap); - return -EINVAL; - } - if (strlen(cfg->drvid)) { - /* A bind has been requested ... */ - char *c, - *e; - - if (strnlen(cfg->drvid, sizeof(cfg->drvid)) == - sizeof(cfg->drvid)) - return -EINVAL; - drvidx = -1; - chidx = -1; - strcpy(drvid, cfg->drvid); - if ((c = strchr(drvid, ','))) { - /* The channel-number is appended to the driver-Id with a comma */ - chidx = (int) simple_strtoul(c + 1, &e, 10); - if (e == c) - chidx = -1; - *c = '\0'; - } - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - /* Lookup driver-Id in array */ - if (!(strcmp(dev->drvid[i], drvid))) { - drvidx = i; - break; - } - if ((drvidx == -1) || (chidx == -1)) - /* Either driver-Id or channel-number invalid */ - return -ENODEV; - } else { - /* Parameters are valid, so get them */ - drvidx = lp->pre_device; - chidx = lp->pre_channel; - } - if (cfg->exclusive > 0) { - unsigned long flags; - - /* If binding is exclusive, try to grab the channel */ - spin_lock_irqsave(&dev->lock, flags); - if ((i = isdn_get_free_channel(ISDN_USAGE_NET, - lp->l2_proto, lp->l3_proto, drvidx, - chidx, lp->msn)) < 0) { - /* Grab failed, because desired channel is in use */ - lp->exclusive = -1; - spin_unlock_irqrestore(&dev->lock, flags); - return -EBUSY; - } - /* All went ok, so update isdninfo */ - dev->usage[i] = ISDN_USAGE_EXCLUSIVE; - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - lp->exclusive = i; - } else { - /* Non-exclusive binding or unbind. */ - lp->exclusive = -1; - if ((lp->pre_device != -1) && (cfg->exclusive == -1)) { - isdn_unexclusive_channel(lp->pre_device, lp->pre_channel); - isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET); - drvidx = -1; - chidx = -1; - } - } - strlcpy(lp->msn, cfg->eaz, sizeof(lp->msn)); - lp->pre_device = drvidx; - lp->pre_channel = chidx; - lp->onhtime = cfg->onhtime; - lp->charge = cfg->charge; - lp->l2_proto = cfg->l2_proto; - lp->l3_proto = cfg->l3_proto; - lp->cbdelay = cfg->cbdelay; - lp->dialmax = cfg->dialmax; - lp->triggercps = cfg->triggercps; - lp->slavedelay = cfg->slavedelay * HZ; - lp->pppbind = cfg->pppbind; - lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; - lp->dialwait = cfg->dialwait * HZ; - if (cfg->secure) - lp->flags |= ISDN_NET_SECURE; - else - lp->flags &= ~ISDN_NET_SECURE; - if (cfg->cbhup) - lp->flags |= ISDN_NET_CBHUP; - else - lp->flags &= ~ISDN_NET_CBHUP; - switch (cfg->callback) { - case 0: - lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT); - break; - case 1: - lp->flags |= ISDN_NET_CALLBACK; - lp->flags &= ~ISDN_NET_CBOUT; - break; - case 2: - lp->flags |= ISDN_NET_CBOUT; - lp->flags &= ~ISDN_NET_CALLBACK; - break; - } - lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */ - if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) { - /* old isdnctrl version, where only 0 or 1 is given */ - printk(KERN_WARNING - "Old isdnctrl version detected! Please update.\n"); - lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */ - } - else { - lp->flags |= cfg->dialmode; /* turn on selected bits */ - } - if (cfg->chargehup) - lp->hupflags |= ISDN_CHARGEHUP; - else - lp->hupflags &= ~ISDN_CHARGEHUP; - if (cfg->ihup) - lp->hupflags |= ISDN_INHUP; - else - lp->hupflags &= ~ISDN_INHUP; - if (cfg->chargeint > 10) { - lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE; - lp->chargeint = cfg->chargeint * HZ; - } - if (cfg->p_encap != lp->p_encap) { - if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev->header_ops = NULL; - p->dev->flags = IFF_NOARP | IFF_POINTOPOINT; - } else { - p->dev->header_ops = &isdn_header_ops; - if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) - p->dev->flags = IFF_BROADCAST | IFF_MULTICAST; - else - p->dev->flags = IFF_NOARP | IFF_POINTOPOINT; - } - } - lp->p_encap = cfg->p_encap; - return 0; - } - return -ENODEV; -} - -/* - * Perform get-interface-parameters.ioctl - */ -int -isdn_net_getcfg(isdn_net_ioctl_cfg *cfg) -{ - isdn_net_dev *p = isdn_net_findif(cfg->name); - - if (p) { - isdn_net_local *lp = p->local; - - strcpy(cfg->eaz, lp->msn); - cfg->exclusive = lp->exclusive; - if (lp->pre_device >= 0) { - sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device], - lp->pre_channel); - } else - cfg->drvid[0] = '\0'; - cfg->onhtime = lp->onhtime; - cfg->charge = lp->charge; - cfg->l2_proto = lp->l2_proto; - cfg->l3_proto = lp->l3_proto; - cfg->p_encap = lp->p_encap; - cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0; - cfg->callback = 0; - if (lp->flags & ISDN_NET_CALLBACK) - cfg->callback = 1; - if (lp->flags & ISDN_NET_CBOUT) - cfg->callback = 2; - cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0; - cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK; - cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0; - cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0; - cfg->cbdelay = lp->cbdelay; - cfg->dialmax = lp->dialmax; - cfg->triggercps = lp->triggercps; - cfg->slavedelay = lp->slavedelay / HZ; - cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ? - (lp->chargeint / HZ) : 0; - cfg->pppbind = lp->pppbind; - cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1; - cfg->dialwait = lp->dialwait / HZ; - if (lp->slave) { - if (strlen(lp->slave->name) >= 10) - strcpy(cfg->slave, "too-long"); - else - strcpy(cfg->slave, lp->slave->name); - } else - cfg->slave[0] = '\0'; - if (lp->master) { - if (strlen(lp->master->name) >= 10) - strcpy(cfg->master, "too-long"); - else - strcpy(cfg->master, lp->master->name); - } else - cfg->master[0] = '\0'; - return 0; - } - return -ENODEV; -} - -/* - * Add a phone-number to an interface. - */ -int -isdn_net_addphone(isdn_net_ioctl_phone *phone) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - isdn_net_phone *n; - - if (p) { - if (!(n = kmalloc(sizeof(isdn_net_phone), GFP_KERNEL))) - return -ENOMEM; - strlcpy(n->num, phone->phone, sizeof(n->num)); - n->next = p->local->phone[phone->outgoing & 1]; - p->local->phone[phone->outgoing & 1] = n; - return 0; - } - return -ENODEV; -} - -/* - * Copy a string of all phone-numbers of an interface to user space. - * This might sleep and must be called with the isdn semaphore down. - */ -int -isdn_net_getphones(isdn_net_ioctl_phone *phone, char __user *phones) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - int inout = phone->outgoing & 1; - int more = 0; - int count = 0; - isdn_net_phone *n; - - if (!p) - return -ENODEV; - inout &= 1; - for (n = p->local->phone[inout]; n; n = n->next) { - if (more) { - put_user(' ', phones++); - count++; - } - if (copy_to_user(phones, n->num, strlen(n->num) + 1)) { - return -EFAULT; - } - phones += strlen(n->num); - count += strlen(n->num); - more = 1; - } - put_user(0, phones); - count++; - return count; -} - -/* - * Copy a string containing the peer's phone number of a connected interface - * to user space. - */ -int -isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - int ch, dv, idx; - - if (!p) - return -ENODEV; - /* - * Theoretical race: while this executes, the remote number might - * become invalid (hang up) or change (new connection), resulting - * in (partially) wrong number copied to user. This race - * currently ignored. - */ - ch = p->local->isdn_channel; - dv = p->local->isdn_device; - if (ch < 0 && dv < 0) - return -ENOTCONN; - idx = isdn_dc2minor(dv, ch); - if (idx < 0) - return -ENODEV; - /* for pre-bound channels, we need this extra check */ - if (strncmp(dev->num[idx], "???", 3) == 0) - return -ENOTCONN; - strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN); - phone->outgoing = USG_OUTGOING(dev->usage[idx]); - if (copy_to_user(peer, phone, sizeof(*peer))) - return -EFAULT; - return 0; -} -/* - * Delete a phone-number from an interface. - */ -int -isdn_net_delphone(isdn_net_ioctl_phone *phone) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - int inout = phone->outgoing & 1; - isdn_net_phone *n; - isdn_net_phone *m; - - if (p) { - n = p->local->phone[inout]; - m = NULL; - while (n) { - if (!strcmp(n->num, phone->phone)) { - if (p->local->dial == n) - p->local->dial = n->next; - if (m) - m->next = n->next; - else - p->local->phone[inout] = n->next; - kfree(n); - return 0; - } - m = n; - n = (isdn_net_phone *) n->next; - } - return -EINVAL; - } - return -ENODEV; -} - -/* - * Delete all phone-numbers of an interface. - */ -static int -isdn_net_rmallphone(isdn_net_dev *p) -{ - isdn_net_phone *n; - isdn_net_phone *m; - int i; - - for (i = 0; i < 2; i++) { - n = p->local->phone[i]; - while (n) { - m = n->next; - kfree(n); - n = m; - } - p->local->phone[i] = NULL; - } - p->local->dial = NULL; - return 0; -} - -/* - * Force a hangup of a network-interface. - */ -int -isdn_net_force_hangup(char *name) -{ - isdn_net_dev *p = isdn_net_findif(name); - struct net_device *q; - - if (p) { - if (p->local->isdn_device < 0) - return 1; - q = p->local->slave; - /* If this interface has slaves, do a hangup for them also. */ - while (q) { - isdn_net_hangup(q); - q = MASTER_TO_SLAVE(q); - } - isdn_net_hangup(p->dev); - return 0; - } - return -ENODEV; -} - -/* - * Helper-function for isdn_net_rm: Do the real work. - */ -static int -isdn_net_realrm(isdn_net_dev *p, isdn_net_dev *q) -{ - u_long flags; - - if (isdn_net_device_started(p)) { - return -EBUSY; - } -#ifdef CONFIG_ISDN_X25 - if (p->cprot && p->cprot->pops) - p->cprot->pops->proto_del(p->cprot); -#endif - /* Free all phone-entries */ - isdn_net_rmallphone(p); - /* If interface is bound exclusive, free channel-usage */ - if (p->local->exclusive != -1) - isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); - if (p->local->master) { - /* It's a slave-device, so update master's slave-pointer if necessary */ - if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave == - p->dev) - ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave = - p->local->slave; - } else { - /* Unregister only if it's a master-device */ - unregister_netdev(p->dev); - } - /* Unlink device from chain */ - spin_lock_irqsave(&dev->lock, flags); - if (q) - q->next = p->next; - else - dev->netdev = p->next; - if (p->local->slave) { - /* If this interface has a slave, remove it also */ - char *slavename = p->local->slave->name; - isdn_net_dev *n = dev->netdev; - q = NULL; - while (n) { - if (!strcmp(n->dev->name, slavename)) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_realrm(n, q); - spin_lock_irqsave(&dev->lock, flags); - break; - } - q = n; - n = (isdn_net_dev *)n->next; - } - } - spin_unlock_irqrestore(&dev->lock, flags); - /* If no more net-devices remain, disable auto-hangup timer */ - if (dev->netdev == NULL) - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); - free_netdev(p->dev); - kfree(p); - - return 0; -} - -/* - * Remove a single network-interface. - */ -int -isdn_net_rm(char *name) -{ - u_long flags; - isdn_net_dev *p; - isdn_net_dev *q; - - /* Search name in netdev-chain */ - spin_lock_irqsave(&dev->lock, flags); - p = dev->netdev; - q = NULL; - while (p) { - if (!strcmp(p->dev->name, name)) { - spin_unlock_irqrestore(&dev->lock, flags); - return (isdn_net_realrm(p, q)); - } - q = p; - p = (isdn_net_dev *) p->next; - } - spin_unlock_irqrestore(&dev->lock, flags); - /* If no more net-devices remain, disable auto-hangup timer */ - if (dev->netdev == NULL) - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); - return -ENODEV; -} - -/* - * Remove all network-interfaces - */ -int -isdn_net_rmall(void) -{ - u_long flags; - int ret; - - /* Walk through netdev-chain */ - spin_lock_irqsave(&dev->lock, flags); - while (dev->netdev) { - if (!dev->netdev->local->master) { - /* Remove master-devices only, slaves get removed with their master */ - spin_unlock_irqrestore(&dev->lock, flags); - if ((ret = isdn_net_realrm(dev->netdev, NULL))) { - return ret; - } - spin_lock_irqsave(&dev->lock, flags); - } - } - dev->netdev = NULL; - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h deleted file mode 100644 index cca6d68da171..000000000000 --- a/drivers/isdn/i4l/isdn_net.h +++ /dev/null @@ -1,151 +0,0 @@ -/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, network related functions (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* Definitions for hupflags: */ -#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */ -#define ISDN_HAVECHARGE 2 /* We know a charge info */ -#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ -#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ -#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ - -/* - * Definitions for Cisco-HDLC header. - */ - -#define CISCO_ADDR_UNICAST 0x0f -#define CISCO_ADDR_BROADCAST 0x8f -#define CISCO_CTRL 0x00 -#define CISCO_TYPE_CDP 0x2000 -#define CISCO_TYPE_SLARP 0x8035 -#define CISCO_SLARP_REQUEST 0 -#define CISCO_SLARP_REPLY 1 -#define CISCO_SLARP_KEEPALIVE 2 - -extern char *isdn_net_new(char *, struct net_device *); -extern char *isdn_net_newslave(char *); -extern int isdn_net_rm(char *); -extern int isdn_net_rmall(void); -extern int isdn_net_stat_callback(int, isdn_ctrl *); -extern int isdn_net_setcfg(isdn_net_ioctl_cfg *); -extern int isdn_net_getcfg(isdn_net_ioctl_cfg *); -extern int isdn_net_addphone(isdn_net_ioctl_phone *); -extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *); -extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *); -extern int isdn_net_delphone(isdn_net_ioctl_phone *); -extern int isdn_net_find_icall(int, int, int, setup_parm *); -extern void isdn_net_hangup(struct net_device *); -extern void isdn_net_dial(void); -extern void isdn_net_autohup(void); -extern int isdn_net_force_hangup(char *); -extern int isdn_net_force_dial(char *); -extern isdn_net_dev *isdn_net_findif(char *); -extern int isdn_net_rcv_skb(int, struct sk_buff *); -extern int isdn_net_dial_req(isdn_net_local *); -extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); -extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); - -#define ISDN_NET_MAX_QUEUE_LENGTH 2 - -#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master)) -#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave)) -#define MASTER_TO_SLAVE(master) \ - (((isdn_net_local *) netdev_priv(master))->slave) - -/* - * is this particular channel busy? - */ -static __inline__ int isdn_net_lp_busy(isdn_net_local *lp) -{ - if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH) - return 0; - else - return 1; -} - -/* - * For the given net device, this will get a non-busy channel out of the - * corresponding bundle. The returned channel is locked. - */ -static __inline__ isdn_net_local *isdn_net_get_locked_lp(isdn_net_dev *nd) -{ - unsigned long flags; - isdn_net_local *lp; - - spin_lock_irqsave(&nd->queue_lock, flags); - lp = nd->queue; /* get lp on top of queue */ - while (isdn_net_lp_busy(nd->queue)) { - nd->queue = nd->queue->next; - if (nd->queue == lp) { /* not found -- should never happen */ - lp = NULL; - goto errout; - } - } - lp = nd->queue; - nd->queue = nd->queue->next; - spin_unlock_irqrestore(&nd->queue_lock, flags); - spin_lock(&lp->xmit_lock); - local_bh_disable(); - return lp; -errout: - spin_unlock_irqrestore(&nd->queue_lock, flags); - return lp; -} - -/* - * add a channel to a bundle - */ -static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp) -{ - isdn_net_local *lp; - unsigned long flags; - - spin_lock_irqsave(&nd->queue_lock, flags); - - lp = nd->queue; -// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n", -// __func__, lp->name, lp, nlp->name, nlp, lp->last); - nlp->last = lp->last; - lp->last->next = nlp; - lp->last = nlp; - nlp->next = lp; - nd->queue = nlp; - - spin_unlock_irqrestore(&nd->queue_lock, flags); -} -/* - * remove a channel from the bundle it belongs to - */ -static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) -{ - isdn_net_local *master_lp = lp; - unsigned long flags; - - if (lp->master) - master_lp = ISDN_MASTER_PRIV(lp); - -// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", -// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); - spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); - lp->last->next = lp->next; - lp->next->last = lp->last; - if (master_lp->netdev->queue == lp) { - master_lp->netdev->queue = lp->next; - if (lp->next == lp) { /* last in queue */ - master_lp->netdev->queue = master_lp->netdev->local; - } - } - lp->next = lp->last = lp; /* (re)set own pointers */ -// printk(KERN_DEBUG "%s: mndq(%p)\n", -// __func__, master_lp->netdev->queue); - spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); -} diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c deleted file mode 100644 index 7e0f419c14f8..000000000000 --- a/drivers/isdn/i4l/isdn_ppp.c +++ /dev/null @@ -1,3046 +0,0 @@ -/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ - * - * Linux ISDN subsystem, functions for synchronous PPP (linklevel). - * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#ifdef CONFIG_IPPP_FILTER -#include -#endif - -#include "isdn_common.h" -#include "isdn_ppp.h" -#include "isdn_net.h" - -#ifndef PPP_IPX -#define PPP_IPX 0x002b -#endif - -/* Prototypes */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); -static int isdn_ppp_closewait(int slot); -static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb, int proto); -static int isdn_ppp_if_get_unit(char *namebuf); -static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *); -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ippp_struct *, struct ippp_struct *, int *proto); -static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb, int proto); -static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto, - struct ippp_struct *is, struct ippp_struct *master, int type); -static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb); - -/* New CCP stuff */ -static void isdn_ppp_ccp_kickup(struct ippp_struct *is); -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len); -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, - unsigned char id); -static void isdn_ppp_ccp_timer_callback(struct timer_list *t); -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, - unsigned char id); -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, - struct isdn_ppp_resetparams *rp); -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, - unsigned char id); - - - -#ifdef CONFIG_ISDN_MPP -static ippp_bundle *isdn_ppp_bundle_arr = NULL; - -static int isdn_ppp_mp_bundle_array_init(void); -static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to); -static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb); -static void isdn_ppp_mp_cleanup(isdn_net_local *lp); - -static int isdn_ppp_bundle(struct ippp_struct *, int unit); -#endif /* CONFIG_ISDN_MPP */ - -char *isdn_ppp_revision = "$Revision: 1.1.2.3 $"; - -static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; - -static struct isdn_ppp_compressor *ipc_head = NULL; - -/* - * frame log (debug) - */ -static void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot) -{ - int cnt, - j, - i; - char buf[80]; - - if (len < maxlen) - maxlen = len; - - for (i = 0, cnt = 0; cnt < maxlen; i++) { - for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) - sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]); - printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf); - } -} - -/* - * unbind isdn_net_local <=> ippp-device - * note: it can happen, that we hangup/free the master before the slaves - * in this case we bind another lp to the master device - */ -int -isdn_ppp_free(isdn_net_local *lp) -{ - struct ippp_struct *is; - - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return 0; - } - -#ifdef CONFIG_ISDN_MPP - spin_lock(&lp->netdev->pb->lock); -#endif - isdn_net_rm_from_bundle(lp); -#ifdef CONFIG_ISDN_MPP - if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ - isdn_ppp_mp_cleanup(lp); - - lp->netdev->pb->ref_ct--; - spin_unlock(&lp->netdev->pb->lock); -#endif /* CONFIG_ISDN_MPP */ - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", - __func__, lp->ppp_slot); - return 0; - } - is = ippp_table[lp->ppp_slot]; - if ((is->state & IPPP_CONNECT)) - isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ - else if (is->state & IPPP_ASSIGNED) - is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ - - if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp); - - is->lp = NULL; /* link is down .. set lp to NULL */ - lp->ppp_slot = -1; /* is this OK ?? */ - - return 0; -} - -/* - * bind isdn_net_local <=> ippp-device - * - * This function is allways called with holding dev->lock so - * no additional lock is needed - */ -int -isdn_ppp_bind(isdn_net_local *lp) -{ - int i; - int unit = 0; - struct ippp_struct *is; - int retval; - - if (lp->pppbind < 0) { /* device bounded to ippp device ? */ - isdn_net_dev *net_dev = dev->netdev; - char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ - memset(exclusive, 0, ISDN_MAX_CHANNELS); - while (net_dev) { /* step through net devices to find exclusive minors */ - isdn_net_local *lp = net_dev->local; - if (lp->pppbind >= 0) - exclusive[lp->pppbind] = 1; - net_dev = net_dev->next; - } - /* - * search a free device / slot - */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ - break; - } - } - } else { - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->minor == lp->pppbind && - (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) - break; - } - } - - if (i >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); - retval = -1; - goto out; - } - /* get unit number from interface name .. ugly! */ - unit = isdn_ppp_if_get_unit(lp->netdev->dev->name); - if (unit < 0) { - printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", - lp->netdev->dev->name); - retval = -1; - goto out; - } - - lp->ppp_slot = i; - is = ippp_table[i]; - is->lp = lp; - is->unit = unit; - is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ -#ifdef CONFIG_ISDN_MPP - retval = isdn_ppp_mp_init(lp, NULL); - if (retval < 0) - goto out; -#endif /* CONFIG_ISDN_MPP */ - - retval = lp->ppp_slot; - -out: - return retval; -} - -/* - * kick the ipppd on the device - * (wakes up daemon after B-channel connect) - */ - -void -isdn_ppp_wakeup_daemon(isdn_net_local *lp) -{ - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return; - } - ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; - wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); -} - -/* - * there was a hangup on the netdevice - * force wakeup of the ippp device - * go into 'device waits for release' state - */ -static int -isdn_ppp_closewait(int slot) -{ - struct ippp_struct *is; - - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __func__, slot); - return 0; - } - is = ippp_table[slot]; - if (is->state) - wake_up_interruptible(&is->wq); - is->state = IPPP_CLOSEWAIT; - return 1; -} - -/* - * isdn_ppp_find_slot / isdn_ppp_free_slot - */ - -static int -isdn_ppp_get_slot(void) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!ippp_table[i]->state) - return i; - } - return -1; -} - -/* - * isdn_ppp_open - */ - -int -isdn_ppp_open(int min, struct file *file) -{ - int slot; - struct ippp_struct *is; - - if (min < 0 || min >= ISDN_MAX_CHANNELS) - return -ENODEV; - - slot = isdn_ppp_get_slot(); - if (slot < 0) { - return -EBUSY; - } - is = file->private_data = ippp_table[slot]; - - printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", - slot, min, is->state); - - /* compression stuff */ - is->link_compressor = is->compressor = NULL; - is->link_decompressor = is->decompressor = NULL; - is->link_comp_stat = is->comp_stat = NULL; - is->link_decomp_stat = is->decomp_stat = NULL; - is->compflags = 0; - - is->reset = isdn_ppp_ccp_reset_alloc(is); - if (!is->reset) - return -ENOMEM; - - is->lp = NULL; - is->mp_seqno = 0; /* MP sequence number */ - is->pppcfg = 0; /* ppp configuration */ - is->mpppcfg = 0; /* mppp configuration */ - is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ - is->unit = -1; /* set, when we have our interface */ - is->mru = 1524; /* MRU, default 1524 */ - is->maxcid = 16; /* VJ: maxcid */ - is->tk = current; - init_waitqueue_head(&is->wq); - is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - is->last = is->rq; - is->minor = min; -#ifdef CONFIG_ISDN_PPP_VJ - /* - * VJ header compression init - */ - is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ - if (IS_ERR(is->slcomp)) { - isdn_ppp_ccp_reset_free(is); - return PTR_ERR(is->slcomp); - } -#endif -#ifdef CONFIG_IPPP_FILTER - is->pass_filter = NULL; - is->active_filter = NULL; -#endif - is->state = IPPP_OPEN; - - return 0; -} - -/* - * release ippp device - */ -void -isdn_ppp_release(int min, struct file *file) -{ - int i; - struct ippp_struct *is; - - if (min < 0 || min >= ISDN_MAX_CHANNELS) - return; - is = file->private_data; - - if (!is) { - printk(KERN_ERR "%s: no file->private_data\n", __func__); - return; - } - if (is->debug & 0x1) - printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp); - - if (is->lp) { /* a lp address says: this link is still up */ - isdn_net_dev *p = is->lp->netdev; - - if (!p) { - printk(KERN_ERR "%s: no lp->netdev\n", __func__); - return; - } - is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */ - /* - * isdn_net_hangup() calls isdn_ppp_free() - * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 - * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() - */ - isdn_net_hangup(p->dev); - } - for (i = 0; i < NUM_RCV_BUFFS; i++) { - kfree(is->rq[i].buf); - is->rq[i].buf = NULL; - } - is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - is->last = is->rq; - -#ifdef CONFIG_ISDN_PPP_VJ -/* TODO: if this was the previous master: link the slcomp to the new master */ - slhc_free(is->slcomp); - is->slcomp = NULL; -#endif -#ifdef CONFIG_IPPP_FILTER - if (is->pass_filter) { - bpf_prog_destroy(is->pass_filter); - is->pass_filter = NULL; - } - - if (is->active_filter) { - bpf_prog_destroy(is->active_filter); - is->active_filter = NULL; - } -#endif - -/* TODO: if this was the previous master: link the stuff to the new master */ - if (is->comp_stat) - is->compressor->free(is->comp_stat); - if (is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - if (is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - if (is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->compressor = is->link_compressor = NULL; - is->decompressor = is->link_decompressor = NULL; - is->comp_stat = is->link_comp_stat = NULL; - is->decomp_stat = is->link_decomp_stat = NULL; - - /* Clean up if necessary */ - if (is->reset) - isdn_ppp_ccp_reset_free(is); - - /* this slot is ready for new connections */ - is->state = 0; -} - -/* - * get_arg .. ioctl helper - */ -static int -get_arg(void __user *b, void *val, int len) -{ - if (len <= 0) - len = sizeof(void *); - if (copy_from_user(val, b, len)) - return -EFAULT; - return 0; -} - -/* - * set arg .. ioctl helper - */ -static int -set_arg(void __user *b, void *val, int len) -{ - if (len <= 0) - len = sizeof(void *); - if (copy_to_user(b, val, len)) - return -EFAULT; - return 0; -} - -#ifdef CONFIG_IPPP_FILTER -static int get_filter(void __user *arg, struct sock_filter **p) -{ - struct sock_fprog uprog; - struct sock_filter *code = NULL; - int len; - - if (copy_from_user(&uprog, arg, sizeof(uprog))) - return -EFAULT; - - if (!uprog.len) { - *p = NULL; - return 0; - } - - /* uprog.len is unsigned short, so no overflow here */ - len = uprog.len * sizeof(struct sock_filter); - code = memdup_user(uprog.filter, len); - if (IS_ERR(code)) - return PTR_ERR(code); - - *p = code; - return uprog.len; -} -#endif /* CONFIG_IPPP_FILTER */ - -/* - * ippp device ioctl - */ -int -isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) -{ - unsigned long val; - int r, i, j; - struct ippp_struct *is; - isdn_net_local *lp; - struct isdn_ppp_comp_data data; - void __user *argp = (void __user *)arg; - - is = file->private_data; - lp = is->lp; - - if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state); - - if (!(is->state & IPPP_OPEN)) - return -EINVAL; - - switch (cmd) { - case PPPIOCBUNDLE: -#ifdef CONFIG_ISDN_MPP - if (!(is->state & IPPP_CONNECT)) - return -EINVAL; - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) min, (int) is->unit, (int) val); - return isdn_ppp_bundle(is, val); -#else - return -1; -#endif - break; - case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg(argp, &is->unit, sizeof(is->unit)))) - return r; - break; - case PPPIOCGIFNAME: - if (!lp) - return -EINVAL; - if ((r = set_arg(argp, lp->netdev->dev->name, - strlen(lp->netdev->dev->name)))) - return r; - break; - case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg)))) - return r; - break; - case PPPIOCSMPFLAGS: /* set configuration flags */ - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - is->mpppcfg = val; - break; - case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg)))) - return r; - break; - case PPPIOCSFLAGS: /* set configuration flags */ - if ((r = get_arg(argp, &val, sizeof(val)))) { - return r; - } - if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { - if (lp) { - /* OK .. we are ready to send buffers */ - is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */ - netif_wake_queue(lp->netdev->dev); - break; - } - } - is->pppcfg = val; - break; - case PPPIOCGIDLE: /* get idle time information */ - if (lp) { - struct ppp_idle pidle; - pidle.xmit_idle = pidle.recv_idle = lp->huptimer; - if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle)))) - return r; - } - break; - case PPPIOCSMRU: /* set receive unit size for PPP */ - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - is->mru = val; - break; - case PPPIOCSMPMRU: - break; - case PPPIOCSMPMTU: - break; - case PPPIOCSMAXCID: /* set the maximum compression slot id */ - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - val++; - if (is->maxcid != val) { -#ifdef CONFIG_ISDN_PPP_VJ - struct slcompress *sltmp; -#endif - if (is->debug & 0x1) - printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); - is->maxcid = val; -#ifdef CONFIG_ISDN_PPP_VJ - sltmp = slhc_init(16, val); - if (IS_ERR(sltmp)) - return PTR_ERR(sltmp); - if (is->slcomp) - slhc_free(is->slcomp); - is->slcomp = sltmp; -#endif - } - break; - case PPPIOCGDEBUG: - if ((r = set_arg(argp, &is->debug, sizeof(is->debug)))) - return r; - break; - case PPPIOCSDEBUG: - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - is->debug = val; - break; - case PPPIOCGCOMPRESSORS: - { - unsigned long protos[8] = {0,}; - struct isdn_ppp_compressor *ipc = ipc_head; - while (ipc) { - j = ipc->num / (sizeof(long) * 8); - i = ipc->num % (sizeof(long) * 8); - if (j < 8) - protos[j] |= (1UL << i); - ipc = ipc->next; - } - if ((r = set_arg(argp, protos, 8 * sizeof(long)))) - return r; - } - break; - case PPPIOCSCOMPRESSOR: - if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data)))) - return r; - return isdn_ppp_set_compressor(is, &data); - case PPPIOCGCALLINFO: - { - struct pppcallinfo pci; - memset((char *)&pci, 0, sizeof(struct pppcallinfo)); - if (lp) - { - strncpy(pci.local_num, lp->msn, 63); - if (lp->dial) { - strncpy(pci.remote_num, lp->dial->num, 63); - } - pci.charge_units = lp->charge; - if (lp->outgoing) - pci.calltype = CALLTYPE_OUTGOING; - else - pci.calltype = CALLTYPE_INCOMING; - if (lp->flags & ISDN_NET_CALLBACK) - pci.calltype |= CALLTYPE_CALLBACK; - } - return set_arg(argp, &pci, sizeof(struct pppcallinfo)); - } -#ifdef CONFIG_IPPP_FILTER - case PPPIOCSPASS: - { - struct sock_fprog_kern fprog; - struct sock_filter *code; - int err, len = get_filter(argp, &code); - - if (len < 0) - return len; - - fprog.len = len; - fprog.filter = code; - - if (is->pass_filter) { - bpf_prog_destroy(is->pass_filter); - is->pass_filter = NULL; - } - if (fprog.filter != NULL) - err = bpf_prog_create(&is->pass_filter, &fprog); - else - err = 0; - kfree(code); - - return err; - } - case PPPIOCSACTIVE: - { - struct sock_fprog_kern fprog; - struct sock_filter *code; - int err, len = get_filter(argp, &code); - - if (len < 0) - return len; - - fprog.len = len; - fprog.filter = code; - - if (is->active_filter) { - bpf_prog_destroy(is->active_filter); - is->active_filter = NULL; - } - if (fprog.filter != NULL) - err = bpf_prog_create(&is->active_filter, &fprog); - else - err = 0; - kfree(code); - - return err; - } -#endif /* CONFIG_IPPP_FILTER */ - default: - break; - } - return 0; -} - -__poll_t -isdn_ppp_poll(struct file *file, poll_table *wait) -{ - __poll_t mask; - struct ippp_buf_queue *bf, *bl; - u_long flags; - struct ippp_struct *is; - - is = file->private_data; - - if (is->debug & 0x2) - printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", - iminor(file_inode(file))); - - /* just registers wait_queue hook. This doesn't really wait. */ - poll_wait(file, &is->wq, wait); - - if (!(is->state & IPPP_OPEN)) { - if (is->state == IPPP_CLOSEWAIT) - return EPOLLHUP; - printk(KERN_DEBUG "isdn_ppp: device not open\n"); - return EPOLLERR; - } - /* we're always ready to send .. */ - mask = EPOLLOUT | EPOLLWRNORM; - - spin_lock_irqsave(&is->buflock, flags); - bl = is->last; - bf = is->first; - /* - * if IPPP_NOBLOCK is set we return even if we have nothing to read - */ - if (bf->next != bl || (is->state & IPPP_NOBLOCK)) { - is->state &= ~IPPP_NOBLOCK; - mask |= EPOLLIN | EPOLLRDNORM; - } - spin_unlock_irqrestore(&is->buflock, flags); - return mask; -} - -/* - * fill up isdn_ppp_read() queue .. - */ - -static int -isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) -{ - struct ippp_buf_queue *bf, *bl; - u_long flags; - u_char *nbuf; - struct ippp_struct *is; - - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); - return 0; - } - is = ippp_table[slot]; - - if (!(is->state & IPPP_CONNECT)) { - printk(KERN_DEBUG "ippp: device not activated.\n"); - return 0; - } - nbuf = kmalloc(len + 4, GFP_ATOMIC); - if (!nbuf) { - printk(KERN_WARNING "ippp: Can't alloc buf\n"); - return 0; - } - nbuf[0] = PPP_ALLSTATIONS; - nbuf[1] = PPP_UI; - nbuf[2] = proto >> 8; - nbuf[3] = proto & 0xff; - memcpy(nbuf + 4, buf, len); - - spin_lock_irqsave(&is->buflock, flags); - bf = is->first; - bl = is->last; - - if (bf == bl) { - printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n"); - bf = bf->next; - kfree(bf->buf); - is->first = bf; - } - bl->buf = (char *) nbuf; - bl->len = len + 4; - - is->last = bl->next; - spin_unlock_irqrestore(&is->buflock, flags); - wake_up_interruptible(&is->wq); - return len; -} - -/* - * read() .. non-blocking: ipppd calls it only after select() - * reports, that there is data - */ - -int -isdn_ppp_read(int min, struct file *file, char __user *buf, int count) -{ - struct ippp_struct *is; - struct ippp_buf_queue *b; - u_long flags; - u_char *save_buf; - - is = file->private_data; - - if (!(is->state & IPPP_OPEN)) - return 0; - - spin_lock_irqsave(&is->buflock, flags); - b = is->first->next; - save_buf = b->buf; - if (!save_buf) { - spin_unlock_irqrestore(&is->buflock, flags); - return -EAGAIN; - } - if (b->len < count) - count = b->len; - b->buf = NULL; - is->first = b; - - spin_unlock_irqrestore(&is->buflock, flags); - if (copy_to_user(buf, save_buf, count)) - count = -EFAULT; - kfree(save_buf); - - return count; -} - -/* - * ipppd wanna write a packet to the card .. non-blocking - */ - -int -isdn_ppp_write(int min, struct file *file, const char __user *buf, int count) -{ - isdn_net_local *lp; - struct ippp_struct *is; - int proto; - - is = file->private_data; - - if (!(is->state & IPPP_CONNECT)) - return 0; - - lp = is->lp; - - /* -> push it directly to the lowlevel interface */ - - if (!lp) - printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); - else { - if (lp->isdn_device < 0 || lp->isdn_channel < 0) { - unsigned char protobuf[4]; - /* - * Don't reset huptimer for - * LCP packets. (Echo requests). - */ - if (copy_from_user(protobuf, buf, 4)) - return -EFAULT; - - proto = PPP_PROTOCOL(protobuf); - if (proto != PPP_LCP) - lp->huptimer = 0; - - return 0; - } - - if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && - lp->dialstate == 0 && - (lp->flags & ISDN_NET_CONNECTED)) { - unsigned short hl; - struct sk_buff *skb; - unsigned char *cpy_buf; - /* - * we need to reserve enough space in front of - * sk_buff. old call to dev_alloc_skb only reserved - * 16 bytes, now we are looking what the driver want - */ - hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - skb = alloc_skb(hl + count, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); - return count; - } - skb_reserve(skb, hl); - cpy_buf = skb_put(skb, count); - if (copy_from_user(cpy_buf, buf, count)) - { - kfree_skb(skb); - return -EFAULT; - } - - /* - * Don't reset huptimer for - * LCP packets. (Echo requests). - */ - proto = PPP_PROTOCOL(cpy_buf); - if (proto != PPP_LCP) - lp->huptimer = 0; - - if (is->debug & 0x40) { - printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - } - - isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */ - - isdn_net_write_super(lp, skb); - } - } - return count; -} - -/* - * init memory, structures etc. - */ - -int -isdn_ppp_init(void) -{ - int i, - j; - -#ifdef CONFIG_ISDN_MPP - if (isdn_ppp_mp_bundle_array_init() < 0) - return -ENOMEM; -#endif /* CONFIG_ISDN_MPP */ - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); - for (j = 0; j < i; j++) - kfree(ippp_table[j]); - return -1; - } - spin_lock_init(&ippp_table[i]->buflock); - ippp_table[i]->state = 0; - ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; - ippp_table[i]->last = ippp_table[i]->rq; - - for (j = 0; j < NUM_RCV_BUFFS; j++) { - ippp_table[i]->rq[j].buf = NULL; - ippp_table[i]->rq[j].last = ippp_table[i]->rq + - (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS; - ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS; - } - } - return 0; -} - -void -isdn_ppp_cleanup(void) -{ - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(ippp_table[i]); - -#ifdef CONFIG_ISDN_MPP - kfree(isdn_ppp_bundle_arr); -#endif /* CONFIG_ISDN_MPP */ - -} - -/* - * check for address/control field and skip if allowed - * retval != 0 -> discard packet silently - */ -static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) -{ - if (skb->len < 1) - return -1; - - if (skb->data[0] == 0xff) { - if (skb->len < 2) - return -1; - - if (skb->data[1] != 0x03) - return -1; - - // skip address/control (AC) field - skb_pull(skb, 2); - } else { - if (is->pppcfg & SC_REJ_COMP_AC) - // if AC compression was not negotiated, but used, discard packet - return -1; - } - return 0; -} - -/* - * get the PPP protocol header and pull skb - * retval < 0 -> discard packet silently - */ -static int isdn_ppp_strip_proto(struct sk_buff *skb) -{ - int proto; - - if (skb->len < 1) - return -1; - - if (skb->data[0] & 0x1) { - // protocol field is compressed - proto = skb->data[0]; - skb_pull(skb, 1); - } else { - if (skb->len < 2) - return -1; - proto = ((int) skb->data[0] << 8) + skb->data[1]; - skb_pull(skb, 2); - } - return proto; -} - - -/* - * handler for incoming packets on a syncPPP interface - */ -void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) -{ - struct ippp_struct *is; - int slot; - int proto; - - BUG_ON(net_dev->local->master); // we're called with the master device always - - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", - lp->ppp_slot); - kfree_skb(skb); - return; - } - is = ippp_table[slot]; - - if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n", - (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - } - - if (isdn_ppp_skip_ac(is, skb) < 0) { - kfree_skb(skb); - return; - } - proto = isdn_ppp_strip_proto(skb); - if (proto < 0) { - kfree_skb(skb); - return; - } - -#ifdef CONFIG_ISDN_MPP - if (is->compflags & SC_LINK_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, NULL, &proto); - if (!skb) // decompression error - return; - } - - if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP - if (proto == PPP_MP) { - isdn_ppp_mp_receive(net_dev, lp, skb); - return; - } - } -#endif - isdn_ppp_push_higher(net_dev, lp, skb, proto); -} - -/* - * we receive a reassembled frame, MPPP has been taken care of before. - * address/control and protocol have been stripped from the skb - * note: net_dev has to be master net_dev - */ -static void -isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto) -{ - struct net_device *dev = net_dev->dev; - struct ippp_struct *is, *mis; - isdn_net_local *mlp = NULL; - int slot; - - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n", - lp->ppp_slot); - goto drop_packet; - } - is = ippp_table[slot]; - - if (lp->master) { // FIXME? - mlp = ISDN_MASTER_PRIV(lp); - slot = mlp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n", - lp->ppp_slot); - goto drop_packet; - } - } - mis = ippp_table[slot]; - - if (is->debug & 0x10) { - printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - } - if (mis->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, mis, &proto); - if (!skb) // decompression error - return; - } - switch (proto) { - case PPP_IPX: /* untested */ - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: IPX\n"); - skb->protocol = htons(ETH_P_IPX); - break; - case PPP_IP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: IP\n"); - skb->protocol = htons(ETH_P_IP); - break; - case PPP_COMP: - case PPP_COMPFRAG: - printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); - goto drop_packet; -#ifdef CONFIG_ISDN_PPP_VJ - case PPP_VJC_UNCOMP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if (net_dev->local->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __func__, net_dev->local->ppp_slot); - goto drop_packet; - } - if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { - printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - goto drop_packet; - } - skb->protocol = htons(ETH_P_IP); - break; - case PPP_VJC_COMP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); - { - struct sk_buff *skb_old = skb; - int pkt_len; - skb = dev_alloc_skb(skb_old->len + 128); - - if (!skb) { - printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - skb = skb_old; - goto drop_packet; - } - skb_put(skb, skb_old->len + 128); - skb_copy_from_linear_data(skb_old, skb->data, - skb_old->len); - if (net_dev->local->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __func__, net_dev->local->ppp_slot); - goto drop_packet; - } - pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, - skb->data, skb_old->len); - kfree_skb(skb_old); - if (pkt_len < 0) - goto drop_packet; - - skb_trim(skb, pkt_len); - skb->protocol = htons(ETH_P_IP); - } - break; -#endif - case PPP_CCP: - case PPP_CCPFRAG: - isdn_ppp_receive_ccp(net_dev, lp, skb, proto); - /* Dont pop up ResetReq/Ack stuff to the daemon any - longer - the job is done already */ - if (skb->data[0] == CCP_RESETREQ || - skb->data[0] == CCP_RESETACK) - break; - /* fall through */ - default: - isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ - kfree_skb(skb); - return; - } - -#ifdef CONFIG_IPPP_FILTER - /* check if the packet passes the pass and active filters - * the filter instructions are constructed assuming - * a four-byte PPP header on each packet (which is still present) */ - skb_push(skb, 4); - - { - u_int16_t *p = (u_int16_t *) skb->data; - - *p = 0; /* indicate inbound */ - } - - if (is->pass_filter - && BPF_PROG_RUN(is->pass_filter, skb) == 0) { - if (is->debug & 0x2) - printk(KERN_DEBUG "IPPP: inbound frame filtered.\n"); - kfree_skb(skb); - return; - } - if (!(is->active_filter - && BPF_PROG_RUN(is->active_filter, skb) == 0)) { - if (is->debug & 0x2) - printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n"); - lp->huptimer = 0; - if (mlp) - mlp->huptimer = 0; - } - skb_pull(skb, 4); -#else /* CONFIG_IPPP_FILTER */ - lp->huptimer = 0; - if (mlp) - mlp->huptimer = 0; -#endif /* CONFIG_IPPP_FILTER */ - skb->dev = dev; - skb_reset_mac_header(skb); - netif_rx(skb); - /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ - return; - -drop_packet: - net_dev->local->stats.rx_dropped++; - kfree_skb(skb); -} - -/* - * isdn_ppp_skb_push .. - * checks whether we have enough space at the beginning of the skb - * and allocs a new SKB if necessary - */ -static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len) -{ - struct sk_buff *skb = *skb_p; - - if (skb_headroom(skb) < len) { - struct sk_buff *nskb = skb_realloc_headroom(skb, len); - - if (!nskb) { - printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n"); - dev_kfree_skb(skb); - return NULL; - } - printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len); - dev_kfree_skb(skb); - *skb_p = nskb; - return skb_push(nskb, len); - } - return skb_push(skb, len); -} - -/* - * send ppp frame .. we expect a PIDCOMPressable proto -- - * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) - * - * VJ compression may change skb pointer!!! .. requeue with old - * skb isn't allowed!! - */ - -int -isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - isdn_net_local *lp, *mlp; - isdn_net_dev *nd; - unsigned int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt, *ipts; - int slot, retval = NETDEV_TX_OK; - - mlp = netdev_priv(netdev); - nd = mlp->netdev; /* get master lp */ - - slot = mlp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - mlp->ppp_slot); - kfree_skb(skb); - goto out; - } - ipts = ippp_table[slot]; - - if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - if (ipts->debug & 0x1) - printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); - retval = NETDEV_TX_BUSY; - goto out; - } - - switch (ntohs(skb->protocol)) { - case ETH_P_IP: - proto = PPP_IP; - break; - case ETH_P_IPX: - proto = PPP_IPX; /* untested */ - break; - default: - printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", - skb->protocol); - dev_kfree_skb(skb); - goto out; - } - - lp = isdn_net_get_locked_lp(nd); - if (!lp) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); - retval = NETDEV_TX_BUSY; - goto out; - } - /* we have our lp locked from now on */ - - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - lp->ppp_slot); - kfree_skb(skb); - goto unlock; - } - ipt = ippp_table[slot]; - - /* - * after this line .. requeueing in the device queue is no longer allowed!!! - */ - - /* Pull off the fake header we stuck on earlier to keep - * the fragmentation code happy. - */ - skb_pull(skb, IPPP_MAX_HEADER); - -#ifdef CONFIG_IPPP_FILTER - /* check if we should pass this packet - * the filter instructions are constructed assuming - * a four-byte PPP header on each packet */ - *(u8 *)skb_push(skb, 4) = 1; /* indicate outbound */ - - { - __be16 *p = (__be16 *)skb->data; - - p++; - *p = htons(proto); - } - - if (ipt->pass_filter - && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) { - if (ipt->debug & 0x4) - printk(KERN_DEBUG "IPPP: outbound frame filtered.\n"); - kfree_skb(skb); - goto unlock; - } - if (!(ipt->active_filter - && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) { - if (ipt->debug & 0x4) - printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n"); - lp->huptimer = 0; - } - skb_pull(skb, 4); -#else /* CONFIG_IPPP_FILTER */ - lp->huptimer = 0; -#endif /* CONFIG_IPPP_FILTER */ - - if (ipt->debug & 0x4) - printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); - if (ipts->debug & 0x40) - isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot); - -#ifdef CONFIG_ISDN_PPP_VJ - if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ - struct sk_buff *new_skb; - unsigned short hl; - /* - * we need to reserve enough space in front of - * sk_buff. old call to dev_alloc_skb only reserved - * 16 bytes, now we are looking what the driver want. - */ - hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER; - /* - * Note: hl might still be insufficient because the method - * above does not account for a possibible MPPP slave channel - * which had larger HL header space requirements than the - * master. - */ - new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC); - if (new_skb) { - u_char *buf; - int pktlen; - - skb_reserve(new_skb, hl); - new_skb->dev = skb->dev; - skb_put(new_skb, skb->len); - buf = skb->data; - - pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, - &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); - - if (buf != skb->data) { - if (new_skb->data != buf) - printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n"); - dev_kfree_skb(skb); - skb = new_skb; - } else { - dev_kfree_skb(new_skb); - } - - skb_trim(skb, pktlen); - if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */ - proto = PPP_VJC_COMP; - skb->data[0] ^= SL_TYPE_COMPRESSED_TCP; - } else { - if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP) - proto = PPP_VJC_UNCOMP; - skb->data[0] = (skb->data[0] & 0x0f) | 0x40; - } - } - } -#endif - - /* - * normal (single link) or bundle compression - */ - if (ipts->compflags & SC_COMP_ON) { - /* We send compressed only if both down- und upstream - compression is negotiated, that means, CCP is up */ - if (ipts->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0); - } else { - printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); - } - } - - if (ipt->debug & 0x24) - printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); - -#ifdef CONFIG_ISDN_MPP - if (ipt->mpppcfg & SC_MP_PROT) { - /* we get mp_seqno from static isdn_net_local */ - long mp_seqno = ipts->mp_seqno; - ipts->mp_seqno++; - if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { - unsigned char *data = isdn_ppp_skb_push(&skb, 3); - if (!data) - goto unlock; - mp_seqno &= 0xfff; - data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */ - data[1] = mp_seqno & 0xff; - data[2] = proto; /* PID compression */ - } else { - unsigned char *data = isdn_ppp_skb_push(&skb, 5); - if (!data) - goto unlock; - data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ - data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ - data[2] = (mp_seqno >> 8) & 0xff; - data[3] = (mp_seqno >> 0) & 0xff; - data[4] = proto; /* PID compression */ - } - proto = PPP_MP; /* MP Protocol, 0x003d */ - } -#endif - - /* - * 'link in bundle' compression ... - */ - if (ipt->compflags & SC_LINK_COMP_ON) - skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1); - - if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) { - unsigned char *data = isdn_ppp_skb_push(&skb, 1); - if (!data) - goto unlock; - data[0] = proto & 0xff; - } - else { - unsigned char *data = isdn_ppp_skb_push(&skb, 2); - if (!data) - goto unlock; - data[0] = (proto >> 8) & 0xff; - data[1] = proto & 0xff; - } - if (!(ipt->pppcfg & SC_COMP_AC)) { - unsigned char *data = isdn_ppp_skb_push(&skb, 2); - if (!data) - goto unlock; - data[0] = 0xff; /* All Stations */ - data[1] = 0x03; /* Unnumbered information */ - } - - /* tx-stats are now updated via BSENT-callback */ - - if (ipts->debug & 0x40) { - printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot); - } - - isdn_net_writebuf_skb(lp, skb); - -unlock: - spin_unlock_bh(&lp->xmit_lock); -out: - return retval; -} - -#ifdef CONFIG_IPPP_FILTER -/* - * check if this packet may trigger auto-dial. - */ - -int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) -{ - struct ippp_struct *is = ippp_table[lp->ppp_slot]; - u_int16_t proto; - int drop = 0; - - switch (ntohs(skb->protocol)) { - case ETH_P_IP: - proto = PPP_IP; - break; - case ETH_P_IPX: - proto = PPP_IPX; - break; - default: - printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n", - skb->protocol); - return 1; - } - - /* the filter instructions are constructed assuming - * a four-byte PPP header on each packet. we have to - * temporarily remove part of the fake header stuck on - * earlier. - */ - *(u8 *)skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */ - - { - __be16 *p = (__be16 *)skb->data; - - p++; - *p = htons(proto); - } - - drop |= is->pass_filter - && BPF_PROG_RUN(is->pass_filter, skb) == 0; - drop |= is->active_filter - && BPF_PROG_RUN(is->active_filter, skb) == 0; - - skb_push(skb, IPPP_MAX_HEADER - 4); - return drop; -} -#endif -#ifdef CONFIG_ISDN_MPP - -/* this is _not_ rfc1990 header, but something we convert both short and long - * headers to for convinience's sake: - * byte 0 is flags as in rfc1990 - * bytes 1...4 is 24-bit seqence number converted to host byte order - */ -#define MP_HEADER_LEN 5 - -#define MP_LONGSEQ_MASK 0x00ffffff -#define MP_SHORTSEQ_MASK 0x00000fff -#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK -#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK -#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1) -#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1) - -/* sequence-wrap safe comparisons (for long sequence)*/ -#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT) -#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT) -#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT) -#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT) - -#define MP_SEQ(f) ((*(u32 *)(f->data + 1))) -#define MP_FLAGS(f) (f->data[0]) - -static int isdn_ppp_mp_bundle_array_init(void) -{ - int i; - int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle); - if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL) - return -ENOMEM; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - spin_lock_init(&isdn_ppp_bundle_arr[i].lock); - return 0; -} - -static ippp_bundle *isdn_ppp_mp_bundle_alloc(void) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (isdn_ppp_bundle_arr[i].ref_ct <= 0) - return (isdn_ppp_bundle_arr + i); - return NULL; -} - -static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to) -{ - struct ippp_struct *is; - - if (lp->ppp_slot < 0) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return (-EINVAL); - } - - is = ippp_table[lp->ppp_slot]; - if (add_to) { - if (lp->netdev->pb) - lp->netdev->pb->ref_ct--; - lp->netdev->pb = add_to; - } else { /* first link in a bundle */ - is->mp_seqno = 0; - if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) - return -ENOMEM; - lp->next = lp->last = lp; /* nobody else in a queue */ - lp->netdev->pb->frags = NULL; - lp->netdev->pb->frames = 0; - lp->netdev->pb->seq = UINT_MAX; - } - lp->netdev->pb->ref_ct++; - - is->last_link_seqno = 0; - return 0; -} - -static u32 isdn_ppp_mp_get_seq(int short_seq, - struct sk_buff *skb, u32 last_seq); -static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp, - struct sk_buff *from, struct sk_buff *to); -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *from, struct sk_buff *to); -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb); -static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb); - -static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb) -{ - struct ippp_struct *is; - isdn_net_local *lpq; - ippp_bundle *mp; - isdn_mppp_stats *stats; - struct sk_buff *newfrag, *frag, *start, *nextf; - u32 newseq, minseq, thisseq; - unsigned long flags; - int slot; - - spin_lock_irqsave(&net_dev->pb->lock, flags); - mp = net_dev->pb; - stats = &mp->stats; - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", - __func__, lp->ppp_slot); - stats->frame_drops++; - dev_kfree_skb(skb); - spin_unlock_irqrestore(&mp->lock, flags); - return; - } - is = ippp_table[slot]; - if (++mp->frames > stats->max_queue_len) - stats->max_queue_len = mp->frames; - - if (is->debug & 0x8) - isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb); - - newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, - skb, is->last_link_seqno); - - - /* if this packet seq # is less than last already processed one, - * toss it right away, but check for sequence start case first - */ - if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) { - mp->seq = newseq; /* the first packet: required for - * rfc1990 non-compliant clients -- - * prevents constant packet toss */ - } else if (MP_LT(newseq, mp->seq)) { - stats->frame_drops++; - isdn_ppp_mp_free_skb(mp, skb); - spin_unlock_irqrestore(&mp->lock, flags); - return; - } - - /* find the minimum received sequence number over all links */ - is->last_link_seqno = minseq = newseq; - for (lpq = net_dev->queue;;) { - slot = lpq->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", - __func__, lpq->ppp_slot); - } else { - u32 lls = ippp_table[slot]->last_link_seqno; - if (MP_LT(lls, minseq)) - minseq = lls; - } - if ((lpq = lpq->next) == net_dev->queue) - break; - } - if (MP_LT(minseq, mp->seq)) - minseq = mp->seq; /* can't go beyond already processed - * packets */ - newfrag = skb; - - /* if this new fragment is before the first one, then enqueue it now. */ - if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { - newfrag->next = frag; - mp->frags = frag = newfrag; - newfrag = NULL; - } - - start = MP_FLAGS(frag) & MP_BEGIN_FRAG && - MP_SEQ(frag) == mp->seq ? frag : NULL; - - /* - * main fragment traversing loop - * - * try to accomplish several tasks: - * - insert new fragment into the proper sequence slot (once that's done - * newfrag will be set to NULL) - * - reassemble any complete fragment sequence (non-null 'start' - * indicates there is a contiguous sequence present) - * - discard any incomplete sequences that are below minseq -- due - * to the fact that sender always increment sequence number, if there - * is an incomplete sequence below minseq, no new fragments would - * come to complete such sequence and it should be discarded - * - * loop completes when we accomplished the following tasks: - * - new fragment is inserted in the proper sequence ('newfrag' is - * set to NULL) - * - we hit a gap in the sequence, so no reassembly/processing is - * possible ('start' would be set to NULL) - * - * algorithm for this code is derived from code in the book - * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) - */ - while (start != NULL || newfrag != NULL) { - - thisseq = MP_SEQ(frag); - nextf = frag->next; - - /* drop any duplicate fragments */ - if (newfrag != NULL && thisseq == newseq) { - isdn_ppp_mp_free_skb(mp, newfrag); - newfrag = NULL; - } - - /* insert new fragment before next element if possible. */ - if (newfrag != NULL && (nextf == NULL || - MP_LT(newseq, MP_SEQ(nextf)))) { - newfrag->next = nextf; - frag->next = nextf = newfrag; - newfrag = NULL; - } - - if (start != NULL) { - /* check for misplaced start */ - if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { - printk(KERN_WARNING"isdn_mppp(seq %d): new " - "BEGIN flag with no prior END", thisseq); - stats->seqerrs++; - stats->frame_drops++; - start = isdn_ppp_mp_discard(mp, start, frag); - nextf = frag->next; - } - } else if (MP_LE(thisseq, minseq)) { - if (MP_FLAGS(frag) & MP_BEGIN_FRAG) - start = frag; - else { - if (MP_FLAGS(frag) & MP_END_FRAG) - stats->frame_drops++; - if (mp->frags == frag) - mp->frags = nextf; - isdn_ppp_mp_free_skb(mp, frag); - frag = nextf; - continue; - } - } - - /* if start is non-null and we have end fragment, then - * we have full reassembly sequence -- reassemble - * and process packet now - */ - if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { - minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK; - /* Reassemble the packet then dispatch it */ - isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); - - start = NULL; - frag = NULL; - - mp->frags = nextf; - } - - /* check if need to update start pointer: if we just - * reassembled the packet and sequence is contiguous - * then next fragment should be the start of new reassembly - * if sequence is contiguous, but we haven't reassembled yet, - * keep going. - * if sequence is not contiguous, either clear everything - * below low watermark and set start to the next frag or - * clear start ptr. - */ - if (nextf != NULL && - ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { - /* if we just reassembled and the next one is here, - * then start another reassembly. */ - - if (frag == NULL) { - if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) - start = nextf; - else - { - printk(KERN_WARNING"isdn_mppp(seq %d):" - " END flag with no following " - "BEGIN", thisseq); - stats->seqerrs++; - } - } - - } else { - if (nextf != NULL && frag != NULL && - MP_LT(thisseq, minseq)) { - /* we've got a break in the sequence - * and we not at the end yet - * and we did not just reassembled - *(if we did, there wouldn't be anything before) - * and we below the low watermark - * discard all the frames below low watermark - * and start over */ - stats->frame_drops++; - mp->frags = isdn_ppp_mp_discard(mp, start, nextf); - } - /* break in the sequence, no reassembly */ - start = NULL; - } - - frag = nextf; - } /* while -- main loop */ - - if (mp->frags == NULL) - mp->frags = frag; - - /* rather straighforward way to deal with (not very) possible - * queue overflow */ - if (mp->frames > MP_MAX_QUEUE_LEN) { - stats->overflows++; - while (mp->frames > MP_MAX_QUEUE_LEN) { - frag = mp->frags->next; - isdn_ppp_mp_free_skb(mp, mp->frags); - mp->frags = frag; - } - } - spin_unlock_irqrestore(&mp->lock, flags); -} - -static void isdn_ppp_mp_cleanup(isdn_net_local *lp) -{ - struct sk_buff *frag = lp->netdev->pb->frags; - struct sk_buff *nextfrag; - while (frag) { - nextfrag = frag->next; - isdn_ppp_mp_free_skb(lp->netdev->pb, frag); - frag = nextfrag; - } - lp->netdev->pb->frags = NULL; -} - -static u32 isdn_ppp_mp_get_seq(int short_seq, - struct sk_buff *skb, u32 last_seq) -{ - u32 seq; - int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG); - - if (!short_seq) - { - seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK; - skb_push(skb, 1); - } - else - { - /* convert 12-bit short seq number to 24-bit long one - */ - seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK; - - /* check for seqence wrap */ - if (!(seq & MP_SHORTSEQ_MAXBIT) && - (last_seq & MP_SHORTSEQ_MAXBIT) && - (unsigned long)last_seq <= MP_LONGSEQ_MAX) - seq |= (last_seq + MP_SHORTSEQ_MAX + 1) & - (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); - else - seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); - - skb_push(skb, 3); /* put converted seqence back in skb */ - } - *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte - * order */ - skb->data[0] = flags; /* restore flags */ - return seq; -} - -static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp, - struct sk_buff *from, - struct sk_buff *to) -{ - if (from) - while (from != to) { - struct sk_buff *next = from->next; - isdn_ppp_mp_free_skb(mp, from); - from = next; - } - return from; -} - -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *from, struct sk_buff *to) -{ - ippp_bundle *mp = net_dev->pb; - int proto; - struct sk_buff *skb; - unsigned int tot_len; - - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return; - } - if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) { - if (ippp_table[lp->ppp_slot]->debug & 0x40) - printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " - "len %d\n", MP_SEQ(from), from->len); - skb = from; - skb_pull(skb, MP_HEADER_LEN); - mp->frames--; - } else { - struct sk_buff *frag; - int n; - - for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++) - tot_len += frag->len - MP_HEADER_LEN; - - if (ippp_table[lp->ppp_slot]->debug & 0x40) - printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " - "to %d, len %d\n", MP_SEQ(from), - (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len); - if ((skb = dev_alloc_skb(tot_len)) == NULL) { - printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " - "of size %d\n", tot_len); - isdn_ppp_mp_discard(mp, from, to); - return; - } - - while (from != to) { - unsigned int len = from->len - MP_HEADER_LEN; - - skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, - skb_put(skb, len), - len); - frag = from->next; - isdn_ppp_mp_free_skb(mp, from); - from = frag; - } - } - proto = isdn_ppp_strip_proto(skb); - isdn_ppp_push_higher(net_dev, lp, skb, proto); -} - -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb) -{ - dev_kfree_skb(skb); - mp->frames--; -} - -static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb) -{ - printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n", - slot, (int) skb->len, - (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], - (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); -} - -static int -isdn_ppp_bundle(struct ippp_struct *is, int unit) -{ - char ifn[IFNAMSIZ + 1]; - isdn_net_dev *p; - isdn_net_local *lp, *nlp; - int rc; - unsigned long flags; - - sprintf(ifn, "ippp%d", unit); - p = isdn_net_findif(ifn); - if (!p) { - printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn); - return -EINVAL; - } - - spin_lock_irqsave(&p->pb->lock, flags); - - nlp = is->lp; - lp = p->queue; - if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS || - lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n", - nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? - nlp->ppp_slot : lp->ppp_slot); - rc = -EINVAL; - goto out; - } - - isdn_net_add_to_bundle(p, nlp); - - ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; - - /* maybe also SC_CCP stuff */ - ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & - (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); - ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & - (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); - rc = isdn_ppp_mp_init(nlp, p->pb); -out: - spin_unlock_irqrestore(&p->pb->lock, flags); - return rc; -} - -#endif /* CONFIG_ISDN_MPP */ - -/* - * network device ioctl handlers - */ - -static int -isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) -{ - struct ppp_stats __user *res = ifr->ifr_data; - struct ppp_stats t; - isdn_net_local *lp = netdev_priv(dev); - - /* build a temporary stat struct and copy it to user space */ - - memset(&t, 0, sizeof(struct ppp_stats)); - if (dev->flags & IFF_UP) { - t.p.ppp_ipackets = lp->stats.rx_packets; - t.p.ppp_ibytes = lp->stats.rx_bytes; - t.p.ppp_ierrors = lp->stats.rx_errors; - t.p.ppp_opackets = lp->stats.tx_packets; - t.p.ppp_obytes = lp->stats.tx_bytes; - t.p.ppp_oerrors = lp->stats.tx_errors; -#ifdef CONFIG_ISDN_PPP_VJ - if (slot >= 0 && ippp_table[slot]->slcomp) { - struct slcompress *slcomp = ippp_table[slot]->slcomp; - t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; - t.vj.vjs_compressed = slcomp->sls_o_compressed; - t.vj.vjs_searches = slcomp->sls_o_searches; - t.vj.vjs_misses = slcomp->sls_o_misses; - t.vj.vjs_errorin = slcomp->sls_i_error; - t.vj.vjs_tossed = slcomp->sls_i_tossed; - t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed; - t.vj.vjs_compressedin = slcomp->sls_i_compressed; - } -#endif - } - if (copy_to_user(res, &t, sizeof(struct ppp_stats))) - return -EFAULT; - return 0; -} - -int -isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - int error = 0; - int len; - isdn_net_local *lp = netdev_priv(dev); - - - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - return -EINVAL; - - switch (cmd) { -#define PPP_VERSION "2.3.7" - case SIOCGPPPVER: - len = strlen(PPP_VERSION) + 1; - if (copy_to_user(ifr->ifr_data, PPP_VERSION, len)) - error = -EFAULT; - break; - - case SIOCGPPPSTATS: - error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev); - break; - default: - error = -EINVAL; - break; - } - return error; -} - -static int -isdn_ppp_if_get_unit(char *name) -{ - int len, - i, - unit = 0, - deci; - - len = strlen(name); - - if (strncmp("ippp", name, 4) || len > 8) - return -1; - - for (i = 0, deci = 1; i < len; i++, deci *= 10) { - char a = name[len - i - 1]; - if (a >= '0' && a <= '9') - unit += (a - '0') * deci; - else - break; - } - if (!i || len - i != 4) - unit = -1; - - return unit; -} - - -int -isdn_ppp_dial_slave(char *name) -{ -#ifdef CONFIG_ISDN_MPP - isdn_net_dev *ndev; - isdn_net_local *lp; - struct net_device *sdev; - - if (!(ndev = isdn_net_findif(name))) - return 1; - lp = ndev->local; - if (!(lp->flags & ISDN_NET_CONNECTED)) - return 5; - - sdev = lp->slave; - while (sdev) { - isdn_net_local *mlp = netdev_priv(sdev); - if (!(mlp->flags & ISDN_NET_CONNECTED)) - break; - sdev = mlp->slave; - } - if (!sdev) - return 2; - - isdn_net_dial_req(netdev_priv(sdev)); - return 0; -#else - return -1; -#endif -} - -int -isdn_ppp_hangup_slave(char *name) -{ -#ifdef CONFIG_ISDN_MPP - isdn_net_dev *ndev; - isdn_net_local *lp; - struct net_device *sdev; - - if (!(ndev = isdn_net_findif(name))) - return 1; - lp = ndev->local; - if (!(lp->flags & ISDN_NET_CONNECTED)) - return 5; - - sdev = lp->slave; - while (sdev) { - isdn_net_local *mlp = netdev_priv(sdev); - - if (mlp->slave) { /* find last connected link in chain */ - isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp); - - if (!(nlp->flags & ISDN_NET_CONNECTED)) - break; - } else if (mlp->flags & ISDN_NET_CONNECTED) - break; - - sdev = mlp->slave; - } - if (!sdev) - return 2; - - isdn_net_hangup(sdev); - return 0; -#else - return -1; -#endif -} - -/* - * PPP compression stuff - */ - - -/* Push an empty CCP Data Frame up to the daemon to wake it up and let it - generate a CCP Reset-Request or tear down CCP altogether */ - -static void isdn_ppp_ccp_kickup(struct ippp_struct *is) -{ - isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot); -} - -/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, - but absolutely nontrivial. The most abstruse problem we are facing is - that the generation, reception and all the handling of timeouts and - resends including proper request id management should be entirely left - to the (de)compressor, but indeed is not covered by the current API to - the (de)compressor. The API is a prototype version from PPP where only - some (de)compressors have yet been implemented and all of them are - rather simple in their reset handling. Especially, their is only one - outstanding ResetAck at a time with all of them and ResetReq/-Acks do - not have parameters. For this very special case it was sufficient to - just return an error code from the decompressor and have a single - reset() entry to communicate all the necessary information between - the framework and the (de)compressor. Bad enough, LZS is different - (and any other compressor may be different, too). It has multiple - histories (eventually) and needs to Reset each of them independently - and thus uses multiple outstanding Acks and history numbers as an - additional parameter to Reqs/Acks. - All that makes it harder to port the reset state engine into the - kernel because it is not just the same simple one as in (i)pppd but - it must be able to pass additional parameters and have multiple out- - standing Acks. We are trying to achieve the impossible by handling - reset transactions independent by their id. The id MUST change when - the data portion changes, thus any (de)compressor who uses more than - one resettable state must provide and recognize individual ids for - each individual reset transaction. The framework itself does _only_ - differentiate them by id, because it has no other semantics like the - (de)compressor might. - This looks like a major redesign of the interface would be nice, - but I don't have an idea how to do it better. */ - -/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is - getting that lengthy because there is no simple "send-this-frame-out" - function above but every wrapper does a bit different. Hope I guess - correct in this hack... */ - -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len) -{ - struct sk_buff *skb; - unsigned char *p; - int hl; - int cnt = 0; - isdn_net_local *lp = is->lp; - - /* Alloc large enough skb */ - hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - skb = alloc_skb(len + hl + 16, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING - "ippp: CCP cannot send reset - out of memory\n"); - return; - } - skb_reserve(skb, hl); - - /* We may need to stuff an address and control field first */ - if (!(is->pppcfg & SC_COMP_AC)) { - p = skb_put(skb, 2); - *p++ = 0xff; - *p++ = 0x03; - } - - /* Stuff proto, code, id and length */ - p = skb_put(skb, 6); - *p++ = (proto >> 8); - *p++ = (proto & 0xff); - *p++ = code; - *p++ = id; - cnt = 4 + len; - *p++ = (cnt >> 8); - *p++ = (cnt & 0xff); - - /* Now stuff remaining bytes */ - if (len) { - skb_put_data(skb, data, len); - } - - /* skb is now ready for xmit */ - printk(KERN_DEBUG "Sending CCP Frame:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - - isdn_net_write_super(lp, skb); -} - -/* Allocate the reset state vector */ -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) -{ - struct ippp_ccp_reset *r; - r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); - if (!r) { - printk(KERN_ERR "ippp_ccp: failed to allocate reset data" - " structure - no mem\n"); - return NULL; - } - printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r); - is->reset = r; - return r; -} - -/* Destroy the reset state vector. Kill all pending timers first. */ -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is) -{ - unsigned int id; - - printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", - is->reset); - for (id = 0; id < 256; id++) { - if (is->reset->rs[id]) { - isdn_ppp_ccp_reset_free_state(is, (unsigned char)id); - } - } - kfree(is->reset); - is->reset = NULL; -} - -/* Free a given state and clear everything up for later reallocation */ -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - - if (is->reset->rs[id]) { - printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); - rs = is->reset->rs[id]; - /* Make sure the kernel will not call back later */ - if (rs->ta) - del_timer(&rs->timer); - is->reset->rs[id] = NULL; - kfree(rs); - } else { - printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); - } -} - -/* The timer callback function which is called when a ResetReq has timed out, - aka has never been answered by a ResetAck */ -static void isdn_ppp_ccp_timer_callback(struct timer_list *t) -{ - struct ippp_ccp_reset_state *rs = - from_timer(rs, t, timer); - - if (!rs) { - printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); - return; - } - if (rs->ta && rs->state == CCPResetSentReq) { - /* We are correct here */ - if (!rs->expra) { - /* Hmm, there is no Ack really expected. We can clean - up the state now, it will be reallocated if the - decompressor insists on another reset */ - rs->ta = 0; - isdn_ppp_ccp_reset_free_state(rs->is, rs->id); - return; - } - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); - /* Push it again */ - isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Restart timer */ - rs->timer.expires = jiffies + HZ * 5; - add_timer(&rs->timer); - } else { - printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", - rs->state); - } -} - -/* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - if (is->reset->rs[id]) { - printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", - id); - return NULL; - } else { - rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC); - if (!rs) - return NULL; - rs->state = CCPResetIdle; - rs->is = is; - rs->id = id; - timer_setup(&rs->timer, isdn_ppp_ccp_timer_callback, 0); - is->reset->rs[id] = rs; - } - return rs; -} - - -/* A decompressor wants a reset with a set of parameters - do what is - necessary to fulfill it */ -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, - struct isdn_ppp_resetparams *rp) -{ - struct ippp_ccp_reset_state *rs; - - if (rp->valid) { - /* The decompressor defines parameters by itself */ - if (rp->rsend) { - /* And he wants us to send a request */ - if (!(rp->idval)) { - printk(KERN_ERR "ippp_ccp: decompressor must" - " specify reset id\n"); - return; - } - if (is->reset->rs[rp->id]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = is->reset->rs[rp->id]; - if (rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - /* Ok, this is a new transaction */ - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", rp->id); - rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); - if (!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - rs->expra = rp->expra; - if (rp->dtval) { - rs->dlen = rp->dlen; - memcpy(rs->data, rp->data, rp->dlen); - } - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, - CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Start the timer */ - rs->timer.expires = jiffies + 5 * HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } else { - printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); - } - } else { - /* The reset params are invalid. The decompressor does not - care about them, so we just send the minimal requests - and increase ids only when an Ack is received for a - given id */ - if (is->reset->rs[is->reset->lastid]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = is->reset->rs[is->reset->lastid]; - if (rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", is->reset->lastid); - rs = isdn_ppp_ccp_reset_alloc_state(is, - is->reset->lastid); - if (!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - /* We always expect an Ack if the decompressor doesn't - know better */ - rs->expra = 1; - rs->dlen = 0; - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, - rs->id, NULL, 0); - /* Start the timer */ - rs->timer.expires = jiffies + 5 * HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } -} - -/* An Ack was received for this id. This means we stop the timer and clean - up the state prior to calling the decompressors reset routine. */ -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs = is->reset->rs[id]; - - if (rs) { - if (rs->ta && rs->state == CCPResetSentReq) { - /* Great, we are correct */ - if (!rs->expra) - printk(KERN_DEBUG "ippp_ccp: ResetAck received" - " for id %d but not expected\n", id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received out of" - "sync for id %d\n", id); - } - if (rs->ta) { - rs->ta = 0; - del_timer(&rs->timer); - } - isdn_ppp_ccp_reset_free_state(is, id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" - " %d\n", id); - } - /* Make sure the simple reset stuff uses a new id next time */ - is->reset->lastid++; -} - -/* - * decompress packet - * - * if master = 0, we're trying to uncompress an per-link compressed packet, - * as opposed to an compressed reconstructed-from-MPPP packet. - * proto is updated to protocol field of uncompressed packet. - * - * retval: decompressed packet, - * same packet if uncompressed, - * NULL if decompression error - */ - -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master, - int *proto) -{ - void *stat = NULL; - struct isdn_ppp_compressor *ipc = NULL; - struct sk_buff *skb_out; - int len; - struct ippp_struct *ri; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - if (!master) { - // per-link decompression - stat = is->link_decomp_stat; - ipc = is->link_decompressor; - ri = is; - } else { - stat = master->decomp_stat; - ipc = master->decompressor; - ri = master; - } - - if (!ipc) { - // no decompressor -> we can't decompress. - printk(KERN_DEBUG "ippp: no decompressor defined!\n"); - return skb; - } - BUG_ON(!stat); // if we have a compressor, stat has been set as well - - if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) { - // compressed packets are compressed by their protocol type - - // Set up reset params for the decompressor - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - - skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN); - if (!skb_out) { - kfree_skb(skb); - printk(KERN_ERR "ippp: decomp memory allocation failure\n"); - return NULL; - } - len = ipc->decompress(stat, skb, skb_out, &rsparm); - kfree_skb(skb); - if (len <= 0) { - switch (len) { - case DECOMP_ERROR: - printk(KERN_INFO "ippp: decomp wants reset %s params\n", - rsparm.valid ? "with" : "without"); - - isdn_ppp_ccp_reset_trans(ri, &rsparm); - break; - case DECOMP_FATALERROR: - ri->pppcfg |= SC_DC_FERROR; - /* Kick ipppd to recognize the error */ - isdn_ppp_ccp_kickup(ri); - break; - } - kfree_skb(skb_out); - return NULL; - } - *proto = isdn_ppp_strip_proto(skb_out); - if (*proto < 0) { - kfree_skb(skb_out); - return NULL; - } - return skb_out; - } else { - // uncompressed packets are fed through the decompressor to - // update the decompressor state - ipc->incomp(stat, skb, *proto); - return skb; - } -} - -/* - * compress a frame - * type=0: normal/bundle compression - * =1: link compression - * returns original skb if we haven't compressed the frame - * and a new skb pointer if we've done it - */ -static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto, - struct ippp_struct *is, struct ippp_struct *master, int type) -{ - int ret; - int new_proto; - struct isdn_ppp_compressor *compressor; - void *stat; - struct sk_buff *skb_out; - - /* we do not compress control protocols */ - if (*proto < 0 || *proto > 0x3fff) { - return skb_in; - } - - if (type) { /* type=1 => Link compression */ - return skb_in; - } - else { - if (!master) { - compressor = is->compressor; - stat = is->comp_stat; - } - else { - compressor = master->compressor; - stat = master->comp_stat; - } - new_proto = PPP_COMP; - } - - if (!compressor) { - printk(KERN_ERR "isdn_ppp: No compressor set!\n"); - return skb_in; - } - if (!stat) { - printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); - return skb_in; - } - - /* Allow for at least 150 % expansion (for now) */ - skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 + - skb_headroom(skb_in), GFP_ATOMIC); - if (!skb_out) - return skb_in; - skb_reserve(skb_out, skb_headroom(skb_in)); - - ret = (compressor->compress)(stat, skb_in, skb_out, *proto); - if (!ret) { - dev_kfree_skb(skb_out); - return skb_in; - } - - dev_kfree_skb(skb_in); - *proto = new_proto; - return skb_out; -} - -/* - * we received a CCP frame .. - * not a clean solution, but we MUST handle a few cases in the kernel - */ -static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb, int proto) -{ - struct ippp_struct *is; - struct ippp_struct *mis; - int len; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", - lp->ppp_slot); - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return; - } - is = ippp_table[lp->ppp_slot]; - isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - - if (lp->master) { - int slot = ISDN_MASTER_PRIV(lp)->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __func__, slot); - return; - } - mis = ippp_table[slot]; - } else - mis = is; - - switch (skb->data[0]) { - case CCP_CONFREQ: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable compression here!\n"); - if (proto == PPP_CCP) - mis->compflags &= ~SC_COMP_ON; - else - is->compflags &= ~SC_LINK_COMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if (proto == PPP_CCP) - mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON); - else - is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we RECEIVE an ackowledge we enable the decompressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Enable decompression here!\n"); - if (proto == PPP_CCP) { - if (!mis->decompressor) - break; - mis->compflags |= SC_DECOMP_ON; - } else { - if (!is->decompressor) - break; - is->compflags |= SC_LINK_DECOMP_ON; - } - break; - - case CCP_RESETACK: - printk(KERN_DEBUG "Received ResetAck from peer\n"); - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - - if (proto == PPP_CCP) { - /* If a reset Ack was outstanding for this id, then - clean up the state engine */ - isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); - if (mis->decompressor && mis->decomp_stat) - mis->decompressor-> - reset(mis->decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: This is not easy to decide here */ - mis->compflags &= ~SC_DECOMP_DISCARD; - } - else { - isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); - if (is->link_decompressor && is->link_decomp_stat) - is->link_decompressor-> - reset(is->link_decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: neither here */ - is->compflags &= ~SC_LINK_DECOMP_DISCARD; - } - break; - - case CCP_RESETREQ: - printk(KERN_DEBUG "Received ResetReq from peer\n"); - /* Receiving a ResetReq means we must reset our compressor */ - /* Set up reset params for the reset entry */ - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - /* Isolate data length */ - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - if (proto == PPP_CCP) { - if (mis->compressor && mis->comp_stat) - mis->compressor-> - reset(mis->comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - else { - if (is->link_compressor && is->link_comp_stat) - is->link_compressor-> - reset(is->link_comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - /* Ack the Req as specified by rsparm */ - if (rsparm.valid) { - /* Compressor reset handler decided how to answer */ - if (rsparm.rsend) { - /* We should send a Frame */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - rsparm.idval ? rsparm.id - : skb->data[1], - rsparm.dtval ? - rsparm.data : NULL, - rsparm.dtval ? - rsparm.dlen : 0); - } else { - printk(KERN_DEBUG "ResetAck suppressed\n"); - } - } else { - /* We answer with a straight reflected Ack */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - skb->data[1], - len ? &skb->data[4] : NULL, - len); - } - break; - } -} - - -/* - * Daemon sends a CCP frame ... - */ - -/* TODO: Clean this up with new Reset semantics */ - -/* I believe the CCP handling as-is is done wrong. Compressed frames - * should only be sent/received after CCP reaches UP state, which means - * both sides have sent CONF_ACK. Currently, we handle both directions - * independently, which means we may accept compressed frames too early - * (supposedly not a problem), but may also mean we send compressed frames - * too early, which may turn out to be a problem. - * This part of state machine should actually be handled by (i)pppd, but - * that's too big of a change now. --kai - */ - -/* Actually, we might turn this into an advantage: deal with the RFC in - * the old tradition of beeing generous on what we accept, but beeing - * strict on what we send. Thus we should just - * - accept compressed frames as soon as decompression is negotiated - * - send compressed frames only when decomp *and* comp are negotiated - * - drop rx compressed frames if we cannot decomp (instead of pushing them - * up to ipppd) - * and I tried to modify this file according to that. --abp - */ - -static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) -{ - struct ippp_struct *mis, *is; - int proto, slot = lp->ppp_slot; - unsigned char *data; - - if (!skb || skb->len < 3) - return; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, slot); - return; - } - is = ippp_table[slot]; - /* Daemon may send with or without address and control field comp */ - data = skb->data; - if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { - data += 2; - if (skb->len < 5) - return; - } - - proto = ((int)data[0]<<8) + data[1]; - if (proto != PPP_CCP && proto != PPP_CCPFRAG) - return; - - printk(KERN_DEBUG "Received CCP frame from daemon:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - - if (lp->master) { - slot = ISDN_MASTER_PRIV(lp)->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __func__, slot); - return; - } - mis = ippp_table[slot]; - } else - mis = is; - if (mis != is) - printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); - - switch (data[2]) { - case CCP_CONFREQ: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable decompression here!\n"); - if (proto == PPP_CCP) - is->compflags &= ~SC_DECOMP_ON; - else - is->compflags &= ~SC_LINK_DECOMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if (proto == PPP_CCP) - is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON); - else - is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we SEND an ackowledge we can/must enable the compressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Enable compression here!\n"); - if (proto == PPP_CCP) { - if (!is->compressor) - break; - is->compflags |= SC_COMP_ON; - } else { - if (!is->compressor) - break; - is->compflags |= SC_LINK_COMP_ON; - } - break; - case CCP_RESETACK: - /* If we send a ACK we should reset our compressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Reset decompression state here!\n"); - printk(KERN_DEBUG "ResetAck from daemon passed by\n"); - if (proto == PPP_CCP) { - /* link to master? */ - if (is->compressor && is->comp_stat) - is->compressor->reset(is->comp_stat, 0, 0, - NULL, 0, NULL); - is->compflags &= ~SC_COMP_DISCARD; - } - else { - if (is->link_compressor && is->link_comp_stat) - is->link_compressor->reset(is->link_comp_stat, - 0, 0, NULL, 0, NULL); - is->compflags &= ~SC_LINK_COMP_DISCARD; - } - break; - case CCP_RESETREQ: - /* Just let it pass by */ - printk(KERN_DEBUG "ResetReq from daemon passed by\n"); - break; - } -} - -int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) -{ - ipc->next = ipc_head; - ipc->prev = NULL; - if (ipc_head) { - ipc_head->prev = ipc; - } - ipc_head = ipc; - return 0; -} - -int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) -{ - if (ipc->prev) - ipc->prev->next = ipc->next; - else - ipc_head = ipc->next; - if (ipc->next) - ipc->next->prev = ipc->prev; - ipc->prev = ipc->next = NULL; - return 0; -} - -static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) -{ - struct isdn_ppp_compressor *ipc = ipc_head; - int ret; - void *stat; - int num = data->num; - - if (is->debug & 0x10) - printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit, - (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num); - - /* If is has no valid reset state vector, we cannot allocate a - decompressor. The decompressor would cause reset transactions - sooner or later, and they need that vector. */ - - if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) { - printk(KERN_ERR "ippp_ccp: no reset data structure - can't" - " allow decompression.\n"); - return -ENOMEM; - } - - while (ipc) { - if (ipc->num == num) { - stat = ipc->alloc(data); - if (stat) { - ret = ipc->init(stat, data, is->unit, 0); - if (!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - stat = NULL; - break; - } - } - else { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - break; - } - - if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (data->flags & IPPP_COMP_FLAG_LINK) { - if (is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - is->link_comp_stat = stat; - is->link_compressor = ipc; - } - else { - if (is->comp_stat) - is->compressor->free(is->comp_stat); - is->comp_stat = stat; - is->compressor = ipc; - } - } - else { - if (data->flags & IPPP_COMP_FLAG_LINK) { - if (is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - is->link_decomp_stat = stat; - is->link_decompressor = ipc; - } - else { - if (is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->decomp_stat = stat; - is->decompressor = ipc; - } - } - return 0; - } - ipc = ipc->next; - } - return -EINVAL; -} diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h deleted file mode 100644 index 34b8a2ce84f3..000000000000 --- a/drivers/isdn/i4l/isdn_ppp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). - * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include /* for PPP_PROTOCOL */ -#include /* for isdn_ppp info */ - -extern int isdn_ppp_read(int, struct file *, char __user *, int); -extern int isdn_ppp_write(int, struct file *, const char __user *, int); -extern int isdn_ppp_open(int, struct file *); -extern int isdn_ppp_init(void); -extern void isdn_ppp_cleanup(void); -extern int isdn_ppp_free(isdn_net_local *); -extern int isdn_ppp_bind(isdn_net_local *); -extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *); -extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *); -extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *); -extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int); -extern __poll_t isdn_ppp_poll(struct file *, struct poll_table_struct *); -extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); -extern void isdn_ppp_release(int, struct file *); -extern int isdn_ppp_dial_slave(char *); -extern void isdn_ppp_wakeup_daemon(isdn_net_local *); - -extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc); -extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc); - -#define IPPP_OPEN 0x01 -#define IPPP_CONNECT 0x02 -#define IPPP_CLOSEWAIT 0x04 -#define IPPP_NOBLOCK 0x08 -#define IPPP_ASSIGNED 0x10 - -#define IPPP_MAX_HEADER 10 diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c deleted file mode 100644 index 43700fc19a31..000000000000 --- a/drivers/isdn/i4l/isdn_tty.c +++ /dev/null @@ -1,3756 +0,0 @@ -/* - * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#undef ISDN_TTY_STAT_DEBUG - -#include -#include /* ASYNC_* flags */ -#include -#include -#include -#include -#include "isdn_common.h" -#include "isdn_tty.h" -#ifdef CONFIG_ISDN_AUDIO -#include "isdn_audio.h" -#define VBUF 0x3e0 -#define VBUFX (VBUF/16) -#endif - -#define FIX_FILE_TRANSFER -#define DUMMY_HAYES_AT - -/* Prototypes */ - -static DEFINE_MUTEX(modem_info_mutex); -static int isdn_tty_edit_at(const char *, int, modem_info *); -static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *); -static void isdn_tty_modem_reset_regs(modem_info *, int); -static void isdn_tty_cmd_ATA(modem_info *); -static void isdn_tty_flush_buffer(struct tty_struct *); -static void isdn_tty_modem_result(int, modem_info *); -#ifdef CONFIG_ISDN_AUDIO -static int isdn_tty_countDLE(unsigned char *, int); -#endif - -/* Leave this unchanged unless you know what you do! */ -#define MODEM_PARANOIA_CHECK -#define MODEM_DO_RESTART - -static int bit2si[8] = -{1, 5, 7, 7, 7, 7, 7, 7}; -static int si2bit[8] = -{4, 1, 4, 4, 4, 4, 4, 4}; - -/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() - * to stuff incoming data directly into a tty's flip-buffer. This - * is done to speed up tty-receiving if the receive-queue is empty. - * This routine MUST be called with interrupts off. - * Return: - * 1 = Success - * 0 = Failure, data has to be buffered and later processed by - * isdn_tty_readmodem(). - */ -static int -isdn_tty_try_read(modem_info *info, struct sk_buff *skb) -{ - struct tty_port *port = &info->port; - int c; - int len; - char last; - - if (!info->online) - return 0; - - if (!(info->mcr & UART_MCR_RTS)) - return 0; - - len = skb->len -#ifdef CONFIG_ISDN_AUDIO - + ISDN_AUDIO_SKB_DLECOUNT(skb) -#endif - ; - - c = tty_buffer_request_room(port, len); - if (c < len) - return 0; - -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_DLECOUNT(skb)) { - int l = skb->len; - unsigned char *dp = skb->data; - while (--l) { - if (*dp == DLE) - tty_insert_flip_char(port, DLE, 0); - tty_insert_flip_char(port, *dp++, 0); - } - if (*dp == DLE) - tty_insert_flip_char(port, DLE, 0); - last = *dp; - } else { -#endif - if (len > 1) - tty_insert_flip_string(port, skb->data, len - 1); - last = skb->data[len - 1]; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP) - tty_insert_flip_char(port, last, 0xFF); - else - tty_insert_flip_char(port, last, TTY_NORMAL); - tty_flip_buffer_push(port); - kfree_skb(skb); - - return 1; -} - -/* isdn_tty_readmodem() is called periodically from within timer-interrupt. - * It tries getting received data from the receive queue an stuff it into - * the tty's flip-buffer. - */ -void -isdn_tty_readmodem(void) -{ - int resched = 0; - int midx; - int i; - int r; - modem_info *info; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - midx = dev->m_idx[i]; - if (midx < 0) - continue; - - info = &dev->mdm.info[midx]; - if (!info->online) - continue; - - r = 0; -#ifdef CONFIG_ISDN_AUDIO - isdn_audio_eval_dtmf(info); - if ((info->vonline & 1) && (info->emu.vpar[1])) - isdn_audio_eval_silence(info); -#endif - if (info->mcr & UART_MCR_RTS) { - /* CISCO AsyncPPP Hack */ - if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) - r = isdn_readbchan_tty(info->isdn_driver, - info->isdn_channel, - &info->port, 0); - else - r = isdn_readbchan_tty(info->isdn_driver, - info->isdn_channel, - &info->port, 1); - if (r) - tty_flip_buffer_push(&info->port); - } else - r = 1; - - if (r) { - info->rcvsched = 0; - resched = 1; - } else - info->rcvsched = 1; - } - if (!resched) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); -} - -int -isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) -{ - ulong flags; - int midx; -#ifdef CONFIG_ISDN_AUDIO - int ifmt; -#endif - modem_info *info; - - if ((midx = dev->m_idx[i]) < 0) { - /* if midx is invalid, packet is not for tty */ - return 0; - } - info = &dev->mdm.info[midx]; -#ifdef CONFIG_ISDN_AUDIO - ifmt = 1; - - if ((info->vonline) && (!info->emu.vpar[4])) - isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); - if ((info->vonline & 1) && (info->emu.vpar[1])) - isdn_audio_calc_silence(info, skb->data, skb->len, ifmt); -#endif - if ((info->online < 2) -#ifdef CONFIG_ISDN_AUDIO - && (!(info->vonline & 1)) -#endif - ) { - /* If Modem not listening, drop data */ - kfree_skb(skb); - return 1; - } - if (info->emu.mdmreg[REG_T70] & BIT_T70) { - if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) { - /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */ - if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */ - skb_pull(skb, 4); - else - if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */ - skb_pull(skb, 2); - } else - /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */ - if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) - skb_pull(skb, 4); - } -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; - if (info->vonline & 1) { - /* voice conversion/compression */ - switch (info->emu.vpar[3]) { - case 2: - case 3: - case 4: - /* adpcm - * Since compressed data takes less - * space, we can overwrite the buffer. - */ - skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr, - ifmt, - skb->data, - skb->data, - skb->len)); - break; - case 5: - /* a-law */ - if (!ifmt) - isdn_audio_ulaw2alaw(skb->data, skb->len); - break; - case 6: - /* u-law */ - if (ifmt) - isdn_audio_alaw2ulaw(skb->data, skb->len); - break; - } - ISDN_AUDIO_SKB_DLECOUNT(skb) = - isdn_tty_countDLE(skb->data, skb->len); - } -#ifdef CONFIG_ISDN_TTY_FAX - else { - if (info->faxonline & 2) { - isdn_tty_fax_bitorder(info, skb); - ISDN_AUDIO_SKB_DLECOUNT(skb) = - isdn_tty_countDLE(skb->data, skb->len); - } - } -#endif -#endif - /* Try to deliver directly via tty-buf if queue is empty */ - spin_lock_irqsave(&info->readlock, flags); - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) - if (isdn_tty_try_read(info, skb)) { - spin_unlock_irqrestore(&info->readlock, flags); - return 1; - } - /* Direct deliver failed or queue wasn't empty. - * Queue up for later dequeueing via timer-irq. - */ - __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb); - dev->drv[di]->rcvcount[channel] += - (skb->len -#ifdef CONFIG_ISDN_AUDIO - + ISDN_AUDIO_SKB_DLECOUNT(skb) -#endif - ); - spin_unlock_irqrestore(&info->readlock, flags); - /* Schedule dequeuing */ - if ((dev->modempoll) && (info->rcvsched)) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - return 1; -} - -static void -isdn_tty_cleanup_xmit(modem_info *info) -{ - skb_queue_purge(&info->xmit_queue); -#ifdef CONFIG_ISDN_AUDIO - skb_queue_purge(&info->dtmf_queue); -#endif -} - -static void -isdn_tty_tint(modem_info *info) -{ - struct sk_buff *skb = skb_dequeue(&info->xmit_queue); - int len, slen; - - if (!skb) - return; - len = skb->len; - if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, - info->isdn_channel, 1, skb)) == len) { - struct tty_struct *tty = info->port.tty; - info->send_outstanding++; - info->msr &= ~UART_MSR_CTS; - info->lsr &= ~UART_LSR_TEMT; - tty_wakeup(tty); - return; - } - if (slen < 0) { - /* Error: no channel, already shutdown, or wrong parameter */ - dev_kfree_skb(skb); - return; - } - skb_queue_head(&info->xmit_queue, skb); -} - -#ifdef CONFIG_ISDN_AUDIO -static int -isdn_tty_countDLE(unsigned char *buf, int len) -{ - int count = 0; - - while (len--) - if (*buf++ == DLE) - count++; - return count; -} - -/* This routine is called from within isdn_tty_write() to perform - * DLE-decoding when sending audio-data. - */ -static int -isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len) -{ - unsigned char *p = &info->port.xmit_buf[info->xmit_count]; - int count = 0; - - while (len > 0) { - if (m->lastDLE) { - m->lastDLE = 0; - switch (*p) { - case DLE: - /* Escape code */ - if (len > 1) - memmove(p, p + 1, len - 1); - p--; - count++; - break; - case ETX: - /* End of data */ - info->vonline |= 4; - return count; - case DC4: - /* Abort RX */ - info->vonline &= ~1; -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\020\003", info); - if (!info->vonline) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "DLEdown: send VCON on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\r\nVCON\r\n", info); - } - /* Fall through */ - case 'q': - case 's': - /* Silence */ - if (len > 1) - memmove(p, p + 1, len - 1); - p--; - break; - } - } else { - if (*p == DLE) - m->lastDLE = 1; - else - count++; - } - p++; - len--; - } - if (len < 0) { - printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n"); - return 0; - } - return count; -} - -/* This routine is called from within isdn_tty_write() when receiving - * audio-data. It interrupts receiving, if an character other than - * ^S or ^Q is sent. - */ -static int -isdn_tty_end_vrx(const char *buf, int c) -{ - char ch; - - while (c--) { - ch = *buf; - if ((ch != 0x11) && (ch != 0x13)) - return 1; - buf++; - } - return 0; -} - -static int voice_cf[7] = -{0, 0, 4, 3, 2, 0, 0}; - -#endif /* CONFIG_ISDN_AUDIO */ - -/* isdn_tty_senddown() is called either directly from within isdn_tty_write() - * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls - * outgoing data from the tty's xmit-buffer, handles voice-decompression or - * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint. - */ -static void -isdn_tty_senddown(modem_info *info) -{ - int buflen; - int skb_res; -#ifdef CONFIG_ISDN_AUDIO - int audio_len; -#endif - struct sk_buff *skb; - -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 4) { - info->vonline &= ~6; - if (!info->vonline) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "senddown: send VCON on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\r\nVCON\r\n", info); - } - } -#endif - if (!(buflen = info->xmit_count)) - return; - if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0) - info->msr &= ~UART_MSR_CTS; - info->lsr &= ~UART_LSR_TEMT; - /* info->xmit_count is modified here and in isdn_tty_write(). - * So we return here if isdn_tty_write() is in the - * critical section. - */ - atomic_inc(&info->xmit_lock); - if (!(atomic_dec_and_test(&info->xmit_lock))) - return; - if (info->isdn_driver < 0) { - info->xmit_count = 0; - return; - } - skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 2) - audio_len = buflen * voice_cf[info->emu.vpar[3]]; - else - audio_len = 0; - skb = dev_alloc_skb(skb_res + buflen + audio_len); -#else - skb = dev_alloc_skb(skb_res + buflen); -#endif - if (!skb) { - printk(KERN_WARNING - "isdn_tty: Out of memory in ttyI%d senddown\n", - info->line); - return; - } - skb_reserve(skb, skb_res); - skb_put_data(skb, info->port.xmit_buf, buflen); - info->xmit_count = 0; -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 2) { - /* For now, ifmt is fixed to 1 (alaw), since this - * is used with ISDN everywhere in the world, except - * US, Canada and Japan. - * Later, when US-ISDN protocols are implemented, - * this setting will depend on the D-channel protocol. - */ - int ifmt = 1; - - /* voice conversion/decompression */ - switch (info->emu.vpar[3]) { - case 2: - case 3: - case 4: - /* adpcm, compatible to ZyXel 1496 modem - * with ROM revision 6.01 - */ - audio_len = isdn_audio_adpcm2xlaw(info->adpcms, - ifmt, - skb->data, - skb_put(skb, audio_len), - buflen); - skb_pull(skb, buflen); - skb_trim(skb, audio_len); - break; - case 5: - /* a-law */ - if (!ifmt) - isdn_audio_alaw2ulaw(skb->data, - buflen); - break; - case 6: - /* u-law */ - if (ifmt) - isdn_audio_ulaw2alaw(skb->data, - buflen); - break; - } - } -#endif /* CONFIG_ISDN_AUDIO */ - if (info->emu.mdmreg[REG_T70] & BIT_T70) { - /* Add T.70 simplified header */ - if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) - memcpy(skb_push(skb, 2), "\1\0", 2); - else - memcpy(skb_push(skb, 4), "\1\0\1\0", 4); - } - skb_queue_tail(&info->xmit_queue, skb); -} - -/************************************************************ - * - * Modem-functions - * - * mostly "stolen" from original Linux-serial.c and friends. - * - ************************************************************/ - -/* The next routine is called once from within timer-interrupt - * triggered within isdn_tty_modem_ncarrier(). It calls - * isdn_tty_modem_result() to stuff a "NO CARRIER" Message - * into the tty's buffer. - */ -static void -isdn_tty_modem_do_ncarrier(struct timer_list *t) -{ - modem_info *info = from_timer(info, t, nc_timer); - isdn_tty_modem_result(RESULT_NO_CARRIER, info); -} - -/* Next routine is called, whenever the DTR-signal is raised. - * It checks the ncarrier-flag, and triggers the above routine - * when necessary. The ncarrier-flag is set, whenever DTR goes - * low. - */ -static void -isdn_tty_modem_ncarrier(modem_info *info) -{ - if (info->ncarrier) { - info->nc_timer.expires = jiffies + HZ; - add_timer(&info->nc_timer); - } -} - -/* - * return the usage calculated by si and layer 2 protocol - */ -static int -isdn_calc_usage(int si, int l2) -{ - int usg = ISDN_USAGE_MODEM; - -#ifdef CONFIG_ISDN_AUDIO - if (si == 1) { - switch (l2) { - case ISDN_PROTO_L2_MODEM: - usg = ISDN_USAGE_MODEM; - break; -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_PROTO_L2_FAX: - usg = ISDN_USAGE_FAX; - break; -#endif - case ISDN_PROTO_L2_TRANS: - default: - usg = ISDN_USAGE_VOICE; - break; - } - } -#endif - return (usg); -} - -/* isdn_tty_dial() performs dialing of a tty an the necessary - * setup of the lower levels before that. - */ -static void -isdn_tty_dial(char *n, modem_info *info, atemu *m) -{ - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[REG_L2PROT]; - u_long flags; - isdn_ctrl cmd; - int i; - int j; - - for (j = 7; j >= 0; j--) - if (m->mdmreg[REG_SI1] & (1 << j)) { - si = bit2si[j]; - break; - } - usg = isdn_calc_usage(si, l2); -#ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && - (l2 != ISDN_PROTO_L2_MODEM) -#ifdef CONFIG_ISDN_TTY_FAX - && (l2 != ISDN_PROTO_L2_FAX) -#endif - ) { - l2 = ISDN_PROTO_L2_TRANS; - usg = ISDN_USAGE_VOICE; - } -#endif - m->mdmreg[REG_SI1I] = si2bit[si]; - spin_lock_irqsave(&dev->lock, flags); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } else { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - info->last_dir = 1; - strcpy(info->last_num, n); - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - info->last_l2 = l2; - cmd.arg = info->isdn_channel + (l2 << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); -#ifdef CONFIG_ISDN_TTY_FAX - if (l2 == ISDN_PROTO_L2_FAX) { - cmd.parm.fax = info->fax; - info->fax->direction = ISDN_TTY_FAX_CONN_OUT; - } -#endif - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - sprintf(cmd.parm.setup.phone, "%s", n); - sprintf(cmd.parm.setup.eazmsn, "%s", - isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.parm.setup.si1 = si; - cmd.parm.setup.si2 = m->mdmreg[REG_SI2]; - cmd.command = ISDN_CMD_DIAL; - info->dialing = 1; - info->emu.carrierwait = 0; - strcpy(dev->num[i], n); - isdn_info_update(); - isdn_command(&cmd); - isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); - } -} - -/* isdn_tty_hangup() disassociates a tty from the real - * ISDN-line (hangup). The usage-status is cleared - * and some cleanup is done also. - */ -void -isdn_tty_modem_hup(modem_info *info, int local) -{ - isdn_ctrl cmd; - int di, ch; - - if (!info) - return; - - di = info->isdn_driver; - ch = info->isdn_channel; - if (di < 0 || ch < 0) - return; - - info->isdn_driver = -1; - info->isdn_channel = -1; - -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); -#endif - info->rcvsched = 0; - isdn_tty_flush_buffer(info->port.tty); - if (info->online) { - info->last_lhup = local; - info->online = 0; - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - } -#ifdef CONFIG_ISDN_AUDIO - info->vonline = 0; -#ifdef CONFIG_ISDN_TTY_FAX - info->faxonline = 0; - info->fax->phase = ISDN_FAX_PHASE_IDLE; -#endif - info->emu.vpar[4] = 0; - info->emu.vpar[5] = 8; - kfree(info->dtmf_state); - info->dtmf_state = NULL; - kfree(info->silence_state); - info->silence_state = NULL; - kfree(info->adpcms); - info->adpcms = NULL; - kfree(info->adpcmr); - info->adpcmr = NULL; -#endif - if ((info->msr & UART_MSR_RI) && - (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) - isdn_tty_modem_result(RESULT_RUNG, info); - info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); - info->lsr |= UART_LSR_TEMT; - - if (local) { - cmd.driver = di; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = ch; - isdn_command(&cmd); - } - - isdn_all_eaz(di, ch); - info->emu.mdmreg[REG_RINGCNT] = 0; - isdn_free_channel(di, ch, 0); - - if (info->drv_index >= 0) { - dev->m_idx[info->drv_index] = -1; - info->drv_index = -1; - } -} - -/* - * Begin of a CAPI like interface, currently used only for - * supplementary service (CAPI 2.0 part III) - */ -#include -#include - -int -isdn_tty_capi_facility(capi_msg *cm) { - return (-1); /* dummy */ -} - -/* isdn_tty_suspend() tries to suspend the current tty connection - */ -static void -isdn_tty_suspend(char *id, modem_info *info, atemu *m) -{ - isdn_ctrl cmd; - - int l; - - if (!info) - return; - -#ifdef ISDN_DEBUG_MODEM_SERVICES - printk(KERN_DEBUG "Msusp ttyI%d\n", info->line); -#endif - l = strlen(id); - if ((info->isdn_driver >= 0)) { - cmd.parm.cmsg.Length = l + 18; - cmd.parm.cmsg.Command = CAPI_FACILITY; - cmd.parm.cmsg.Subcommand = CAPI_REQ; - cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; - cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ - cmd.parm.cmsg.para[1] = 0; - cmd.parm.cmsg.para[2] = l + 3; - cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */ - cmd.parm.cmsg.para[4] = 0; - cmd.parm.cmsg.para[5] = l; - memcpy(&cmd.parm.cmsg.para[6], id, l); - cmd.command = CAPI_PUT_MESSAGE; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - isdn_command(&cmd); - } -} - -/* isdn_tty_resume() tries to resume a suspended call - * setup of the lower levels before that. unfortunately here is no - * checking for compatibility of used protocols implemented by Q931 - * It does the same things like isdn_tty_dial, the last command - * is different, may be we can merge it. - */ - -static void -isdn_tty_resume(char *id, modem_info *info, atemu *m) -{ - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[REG_L2PROT]; - isdn_ctrl cmd; - ulong flags; - int i; - int j; - int l; - - l = strlen(id); - for (j = 7; j >= 0; j--) - if (m->mdmreg[REG_SI1] & (1 << j)) { - si = bit2si[j]; - break; - } - usg = isdn_calc_usage(si, l2); -#ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && - (l2 != ISDN_PROTO_L2_MODEM) -#ifdef CONFIG_ISDN_TTY_FAX - && (l2 != ISDN_PROTO_L2_FAX) -#endif - ) { - l2 = ISDN_PROTO_L2_TRANS; - usg = ISDN_USAGE_VOICE; - } -#endif - m->mdmreg[REG_SI1I] = si2bit[si]; - spin_lock_irqsave(&dev->lock, flags); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } else { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - info->last_dir = 1; -// strcpy(info->last_num, n); - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - info->last_l2 = l2; - cmd.arg = info->isdn_channel + (l2 << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.parm.cmsg.Length = l + 18; - cmd.parm.cmsg.Command = CAPI_FACILITY; - cmd.parm.cmsg.Subcommand = CAPI_REQ; - cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; - cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ - cmd.parm.cmsg.para[1] = 0; - cmd.parm.cmsg.para[2] = l + 3; - cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */ - cmd.parm.cmsg.para[4] = 0; - cmd.parm.cmsg.para[5] = l; - memcpy(&cmd.parm.cmsg.para[6], id, l); - cmd.command = CAPI_PUT_MESSAGE; - info->dialing = 1; -// strcpy(dev->num[i], n); - isdn_info_update(); - isdn_command(&cmd); - isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); - } -} - -/* isdn_tty_send_msg() sends a message to a HL driver - * This is used for hybrid modem cards to send AT commands to it - */ - -static void -isdn_tty_send_msg(modem_info *info, atemu *m, char *msg) -{ - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[REG_L2PROT]; - isdn_ctrl cmd; - ulong flags; - int i; - int j; - int l; - - l = min(strlen(msg), sizeof(cmd.parm) - sizeof(cmd.parm.cmsg) - + sizeof(cmd.parm.cmsg.para) - 2); - - if (!l) { - isdn_tty_modem_result(RESULT_ERROR, info); - return; - } - for (j = 7; j >= 0; j--) - if (m->mdmreg[REG_SI1] & (1 << j)) { - si = bit2si[j]; - break; - } - usg = isdn_calc_usage(si, l2); -#ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && - (l2 != ISDN_PROTO_L2_MODEM) -#ifdef CONFIG_ISDN_TTY_FAX - && (l2 != ISDN_PROTO_L2_FAX) -#endif - ) { - l2 = ISDN_PROTO_L2_TRANS; - usg = ISDN_USAGE_VOICE; - } -#endif - m->mdmreg[REG_SI1I] = si2bit[si]; - spin_lock_irqsave(&dev->lock, flags); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } else { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - info->last_dir = 1; - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - info->last_l2 = l2; - cmd.arg = info->isdn_channel + (l2 << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.parm.cmsg.Length = l + 14; - cmd.parm.cmsg.Command = CAPI_MANUFACTURER; - cmd.parm.cmsg.Subcommand = CAPI_REQ; - cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; - cmd.parm.cmsg.para[0] = l + 1; - strncpy(&cmd.parm.cmsg.para[1], msg, l); - cmd.parm.cmsg.para[l + 1] = 0xd; - cmd.command = CAPI_PUT_MESSAGE; -/* info->dialing = 1; - strcpy(dev->num[i], n); - isdn_info_update(); -*/ - isdn_command(&cmd); - } -} - -static inline int -isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine) -{ -#ifdef MODEM_PARANOIA_CHECK - if (!info) { - printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n", - name, routine); - return 1; - } - if (info->magic != ISDN_ASYNC_MAGIC) { - printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n", - name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void -isdn_tty_change_speed(modem_info *info) -{ - struct tty_port *port = &info->port; - uint cflag, - cval, - quot; - int i; - - if (!port->tty) - return; - cflag = port->tty->termios.c_cflag; - - quot = i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 2) - port->tty->termios.c_cflag &= ~CBAUDEX; - else - i += 15; - } - if (quot) { - info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); - } else { - info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in changespeed\n"); -#endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_reset_regs(info, 0); - isdn_tty_modem_hup(info, 1); - } - return; - } - /* byte size and parity */ - cval = cflag & (CSIZE | CSTOPB); - cval >>= 4; - if (cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; - - tty_port_set_check_carrier(port, ~cflag & CLOCAL); -} - -static int -isdn_tty_startup(modem_info *info) -{ - if (tty_port_initialized(&info->port)) - return 0; - isdn_lock_drivers(); -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line); -#endif - /* - * Now, initialize the UART - */ - info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - /* - * and set the speed of the serial port - */ - isdn_tty_change_speed(info); - - tty_port_set_initialized(&info->port, 1); - info->msr |= (UART_MSR_DSR | UART_MSR_CTS); - info->send_outstanding = 0; - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void -isdn_tty_shutdown(modem_info *info) -{ - if (!tty_port_initialized(&info->port)) - return; -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line); -#endif - isdn_unlock_drivers(); - info->msr &= ~UART_MSR_RI; - if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) { - info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { - isdn_tty_modem_reset_regs(info, 0); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); -#endif - isdn_tty_modem_hup(info, 1); - } - } - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, 0); -} - -/* isdn_tty_write() is the main send-routine. It is called from the upper - * levels within the kernel to perform sending data. Depending on the - * online-flag it either directs output to the at-command-interpreter or - * to the lower level. Additional tasks done here: - * - If online, check for escape-sequence (+++) - * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes. - * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed. - * - If dialing, abort dial. - */ -static int -isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count) -{ - int c; - int total = 0; - modem_info *info = (modem_info *) tty->driver_data; - atemu *m = &info->emu; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write")) - return 0; - /* See isdn_tty_senddown() */ - atomic_inc(&info->xmit_lock); - while (1) { - c = count; - if (c > info->xmit_size - info->xmit_count) - c = info->xmit_size - info->xmit_count; - if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize) - c = dev->drv[info->isdn_driver]->maxbufsize; - if (c <= 0) - break; - if ((info->online > 1) -#ifdef CONFIG_ISDN_AUDIO - || (info->vonline & 3) -#endif - ) { -#ifdef CONFIG_ISDN_AUDIO - if (!info->vonline) -#endif - isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c, - &(m->pluscount), - &(m->lastplus)); - memcpy(&info->port.xmit_buf[info->xmit_count], buf, c); -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline) { - int cc = isdn_tty_handleDLEdown(info, m, c); - if (info->vonline & 2) { - if (!cc) { - /* If DLE decoding results in zero-transmit, but - * c originally was non-zero, do a wakeup. - */ - tty_wakeup(tty); - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; - } - info->xmit_count += cc; - } - if ((info->vonline & 3) == 1) { - /* Do NOT handle Ctrl-Q or Ctrl-S - * when in full-duplex audio mode. - */ - if (isdn_tty_end_vrx(buf, c)) { - info->vonline &= ~1; -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); - } - } - } else - if (TTY_IS_FCLASS1(info)) { - int cc = isdn_tty_handleDLEdown(info, m, c); - - if (info->vonline & 4) { /* ETX seen */ - isdn_ctrl c; - - c.command = ISDN_CMD_FAXCMD; - c.driver = info->isdn_driver; - c.arg = info->isdn_channel; - c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL; - c.parm.aux.subcmd = ETX; - isdn_command(&c); - } - info->vonline = 0; -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c); -#endif - info->xmit_count += cc; - } else -#endif - info->xmit_count += c; - } else { - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; - if (info->dialing) { - info->dialing = 0; -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); -#endif - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - isdn_tty_modem_hup(info, 1); - } else - c = isdn_tty_edit_at(buf, c, info); - } - buf += c; - count -= c; - total += c; - } - atomic_dec(&info->xmit_lock); - if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) { - if (m->mdmreg[REG_DXMT] & BIT_DXMT) { - isdn_tty_senddown(info); - isdn_tty_tint(info); - } - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); - } - return total; -} - -static int -isdn_tty_write_room(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - int ret; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room")) - return 0; - if (!info->online) - return info->xmit_size; - ret = info->xmit_size - info->xmit_count; - return (ret < 0) ? 0 : ret; -} - -static int -isdn_tty_chars_in_buffer(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer")) - return 0; - if (!info->online) - return 0; - return (info->xmit_count); -} - -static void -isdn_tty_flush_buffer(struct tty_struct *tty) -{ - modem_info *info; - - if (!tty) { - return; - } - info = (modem_info *) tty->driver_data; - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) { - return; - } - isdn_tty_cleanup_xmit(info); - info->xmit_count = 0; - tty_wakeup(tty); -} - -static void -isdn_tty_flush_chars(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars")) - return; - if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); -} - -/* - * ------------------------------------------------------------ - * isdn_tty_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void -isdn_tty_throttle(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle")) - return; - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - info->mcr &= ~UART_MCR_RTS; -} - -static void -isdn_tty_unthrottle(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle")) - return; - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } - info->mcr |= UART_MCR_RTS; -} - -/* - * ------------------------------------------------------------ - * isdn_tty_ioctl() and friends - * ------------------------------------------------------------ - */ - -/* - * isdn_tty_get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows RS485 driver to be written in user space. - */ -static int -isdn_tty_get_lsr_info(modem_info *info, uint __user *value) -{ - u_char status; - uint result; - - status = info->lsr; - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result, value); -} - - -static int -isdn_tty_tiocmget(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - u_char control, status; - - if (isdn_tty_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - if (tty_io_error(tty)) - return -EIO; - - mutex_lock(&modem_info_mutex); -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); -#endif - - control = info->mcr; - status = info->msr; - mutex_unlock(&modem_info_mutex); - return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -} - -static int -isdn_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - if (tty_io_error(tty)) - return -EIO; - -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear); -#endif - - mutex_lock(&modem_info_mutex); - if (set & TIOCM_RTS) - info->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) { - info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); - } - - if (clear & TIOCM_RTS) - info->mcr &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) { - info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { - isdn_tty_modem_reset_regs(info, 0); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMSET\n"); -#endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_hup(info, 1); - } - } - mutex_unlock(&modem_info_mutex); - return 0; -} - -static int -isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl")) - return -ENODEV; - if (tty_io_error(tty)) - return -EIO; - switch (cmd) { - case TIOCSERGETLSR: /* Get line status register */ -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); -#endif - return isdn_tty_get_lsr_info(info, (uint __user *) arg); - default: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); -#endif - return -ENOIOCTLCMD; - } - return 0; -} - -static void -isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - modem_info *info = (modem_info *) tty->driver_data; - - mutex_lock(&modem_info_mutex); - if (!old_termios) - isdn_tty_change_speed(info); - else { - if (tty->termios.c_cflag == old_termios->c_cflag && - tty->termios.c_ispeed == old_termios->c_ispeed && - tty->termios.c_ospeed == old_termios->c_ospeed) { - mutex_unlock(&modem_info_mutex); - return; - } - isdn_tty_change_speed(info); - } - mutex_unlock(&modem_info_mutex); -} - -/* - * ------------------------------------------------------------ - * isdn_tty_open() and friends - * ------------------------------------------------------------ - */ - -static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - modem_info *info = &dev->mdm.info[tty->index]; - - if (isdn_tty_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - tty->driver_data = info; - - return tty_port_install(&info->port, driver, tty); -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int -isdn_tty_open(struct tty_struct *tty, struct file *filp) -{ - modem_info *info = tty->driver_data; - struct tty_port *port = &info->port; - int retval; - -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, - port->count); -#endif - port->count++; - port->tty = tty; - /* - * Start up serial port - */ - retval = isdn_tty_startup(info); - if (retval) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open return after startup\n"); -#endif - return retval; - } - retval = tty_port_block_til_ready(port, tty, filp); - if (retval) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n"); -#endif - return retval; - } -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line); -#endif - dev->modempoll++; -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open normal exit\n"); -#endif - return 0; -} - -static void -isdn_tty_close(struct tty_struct *tty, struct file *filp) -{ - modem_info *info = (modem_info *) tty->driver_data; - struct tty_port *port = &info->port; - ulong timeout; - - if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close")) - return; - if (tty_hung_up_p(filp)) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n"); -#endif - return; - } - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, " - "info->count is %d\n", port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n", - info->line, port->count); - port->count = 0; - } - if (port->count) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n"); -#endif - return; - } - info->closing = 1; - - tty->closing = 1; - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - if (tty_port_initialized(port)) { - tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = jiffies + HZ; - while (!(info->lsr & UART_LSR_TEMT)) { - schedule_timeout_interruptible(20); - if (time_after(jiffies, timeout)) - break; - } - } - dev->modempoll--; - isdn_tty_shutdown(info); - isdn_tty_flush_buffer(tty); - tty_ldisc_flush(tty); - port->tty = NULL; - info->ncarrier = 0; - - tty_port_close_end(port, tty); - info->closing = 0; -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_close normal exit\n"); -#endif -} - -/* - * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void -isdn_tty_hangup(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - struct tty_port *port = &info->port; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup")) - return; - isdn_tty_shutdown(info); - port->count = 0; - tty_port_set_active(port, 0); - port->tty = NULL; - wake_up_interruptible(&port->open_wait); -} - -/* This routine initializes all emulator-data. - */ -static void -isdn_tty_reset_profile(atemu *m) -{ - m->profile[0] = 0; - m->profile[1] = 0; - m->profile[2] = 43; - m->profile[3] = 13; - m->profile[4] = 10; - m->profile[5] = 8; - m->profile[6] = 3; - m->profile[7] = 60; - m->profile[8] = 2; - m->profile[9] = 6; - m->profile[10] = 7; - m->profile[11] = 70; - m->profile[12] = 0x45; - m->profile[13] = 4; - m->profile[14] = ISDN_PROTO_L2_X75I; - m->profile[15] = ISDN_PROTO_L3_TRANS; - m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16; - m->profile[17] = ISDN_MODEM_WINSIZE; - m->profile[18] = 4; - m->profile[19] = 0; - m->profile[20] = 0; - m->profile[23] = 0; - m->pmsn[0] = '\0'; - m->plmsn[0] = '\0'; -} - -#ifdef CONFIG_ISDN_AUDIO -static void -isdn_tty_modem_reset_vpar(atemu *m) -{ - m->vpar[0] = 2; /* Voice-device (2 = phone line) */ - m->vpar[1] = 0; /* Silence detection level (0 = none ) */ - m->vpar[2] = 70; /* Silence interval (7 sec. ) */ - m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ - m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */ - m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */ -} -#endif - -#ifdef CONFIG_ISDN_TTY_FAX -static void -isdn_tty_modem_reset_faxpar(modem_info *info) -{ - T30_s *f = info->fax; - - f->code = 0; - f->phase = ISDN_FAX_PHASE_IDLE; - f->direction = 0; - f->resolution = 1; /* fine */ - f->rate = 5; /* 14400 bit/s */ - f->width = 0; - f->length = 0; - f->compression = 0; - f->ecm = 0; - f->binary = 0; - f->scantime = 0; - memset(&f->id[0], 32, FAXIDLEN - 1); - f->id[FAXIDLEN - 1] = 0; - f->badlin = 0; - f->badmul = 0; - f->bor = 0; - f->nbc = 0; - f->cq = 0; - f->cr = 0; - f->ctcrty = 0; - f->minsp = 0; - f->phcto = 30; - f->rel = 0; - memset(&f->pollid[0], 32, FAXIDLEN - 1); - f->pollid[FAXIDLEN - 1] = 0; -} -#endif - -static void -isdn_tty_modem_reset_regs(modem_info *info, int force) -{ - atemu *m = &info->emu; - if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { - memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG); - memcpy(m->msn, m->pmsn, ISDN_MSNLEN); - memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - } -#ifdef CONFIG_ISDN_AUDIO - isdn_tty_modem_reset_vpar(m); -#endif -#ifdef CONFIG_ISDN_TTY_FAX - isdn_tty_modem_reset_faxpar(info); -#endif - m->mdmcmdl = 0; -} - -static void -modem_write_profile(atemu *m) -{ - memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG); - memcpy(m->pmsn, m->msn, ISDN_MSNLEN); - memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); - if (dev->profd) - send_sig(SIGIO, dev->profd, 1); -} - -static const struct tty_operations modem_ops = { - .install = isdn_tty_install, - .open = isdn_tty_open, - .close = isdn_tty_close, - .write = isdn_tty_write, - .flush_chars = isdn_tty_flush_chars, - .write_room = isdn_tty_write_room, - .chars_in_buffer = isdn_tty_chars_in_buffer, - .flush_buffer = isdn_tty_flush_buffer, - .ioctl = isdn_tty_ioctl, - .throttle = isdn_tty_throttle, - .unthrottle = isdn_tty_unthrottle, - .set_termios = isdn_tty_set_termios, - .hangup = isdn_tty_hangup, - .tiocmget = isdn_tty_tiocmget, - .tiocmset = isdn_tty_tiocmset, -}; - -static int isdn_tty_carrier_raised(struct tty_port *port) -{ - modem_info *info = container_of(port, modem_info, port); - return info->msr & UART_MSR_DCD; -} - -static const struct tty_port_operations isdn_tty_port_ops = { - .carrier_raised = isdn_tty_carrier_raised, -}; - -int -isdn_tty_modem_init(void) -{ - isdn_modem_t *m; - int i, retval; - modem_info *info; - - m = &dev->mdm; - m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS); - if (!m->tty_modem) - return -ENOMEM; - m->tty_modem->name = "ttyI"; - m->tty_modem->major = ISDN_TTY_MAJOR; - m->tty_modem->minor_start = 0; - m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL; - m->tty_modem->subtype = SERIAL_TYPE_NORMAL; - m->tty_modem->init_termios = tty_std_termios; - m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - m->tty_modem->flags = TTY_DRIVER_REAL_RAW; - m->tty_modem->driver_name = "isdn_tty"; - tty_set_operations(m->tty_modem, &modem_ops); - retval = tty_register_driver(m->tty_modem); - if (retval) { - printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n"); - goto err; - } - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &m->info[i]; -#ifdef CONFIG_ISDN_TTY_FAX - if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) { - printk(KERN_ERR "Could not allocate fax t30-buffer\n"); - retval = -ENOMEM; - goto err_unregister; - } -#endif - tty_port_init(&info->port); - info->port.ops = &isdn_tty_port_ops; - spin_lock_init(&info->readlock); - sprintf(info->last_cause, "0000"); - sprintf(info->last_num, "none"); - info->last_dir = 0; - info->last_lhup = 1; - info->last_l2 = -1; - info->last_si = 0; - isdn_tty_reset_profile(&info->emu); - isdn_tty_modem_reset_regs(info, 1); - info->magic = ISDN_ASYNC_MAGIC; - info->line = i; - info->x_char = 0; - info->isdn_driver = -1; - info->isdn_channel = -1; - info->drv_index = -1; - info->xmit_size = ISDN_SERIAL_XMIT_SIZE; - timer_setup(&info->nc_timer, isdn_tty_modem_do_ncarrier, 0); - skb_queue_head_init(&info->xmit_queue); -#ifdef CONFIG_ISDN_AUDIO - skb_queue_head_init(&info->dtmf_queue); -#endif - info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, - GFP_KERNEL); - if (!info->port.xmit_buf) { - printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); - retval = -ENOMEM; - goto err_unregister; - } - /* Make room for T.70 header */ - info->port.xmit_buf += 4; - } - return 0; -err_unregister: - for (i--; i >= 0; i--) { - info = &m->info[i]; -#ifdef CONFIG_ISDN_TTY_FAX - kfree(info->fax); -#endif - kfree(info->port.xmit_buf - 4); - info->port.xmit_buf = NULL; - tty_port_destroy(&info->port); - } - tty_unregister_driver(m->tty_modem); -err: - put_tty_driver(m->tty_modem); - m->tty_modem = NULL; - return retval; -} - -void -isdn_tty_exit(void) -{ - modem_info *info; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &dev->mdm.info[i]; - isdn_tty_cleanup_xmit(info); -#ifdef CONFIG_ISDN_TTY_FAX - kfree(info->fax); -#endif - kfree(info->port.xmit_buf - 4); - info->port.xmit_buf = NULL; - tty_port_destroy(&info->port); - } - tty_unregister_driver(dev->mdm.tty_modem); - put_tty_driver(dev->mdm.tty_modem); - dev->mdm.tty_modem = NULL; -} - - -/* - * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) - * match the MSN against the MSNs (glob patterns) defined for tty_emulator, - * and return 0 for match, 1 for no match, 2 if MSN could match if longer. - */ - -static int -isdn_tty_match_icall(char *cid, atemu *emu, int di) -{ -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n", - emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di), - emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]); -#endif - if (strlen(emu->lmsn)) { - char *p = emu->lmsn; - char *q; - int tmp; - int ret = 0; - - while (1) { - if ((q = strchr(p, ';'))) - *q = '\0'; - if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret) - ret = tmp; -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n", - p, isdn_map_eaz2msn(emu->msn, di), tmp); -#endif - if (q) { - *q = ';'; - p = q; - p++; - } - if (!tmp) - return 0; - if (!q) - break; - } - return ret; - } else { - int tmp; - tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di)); -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n", - isdn_map_eaz2msn(emu->msn, di), tmp); -#endif - return tmp; - } -} - -/* - * An incoming call-request has arrived. - * Search the tty-devices for an appropriate device and bind - * it to the ISDN-Channel. - * Return: - * - * 0 = No matching device found. - * 1 = A matching device found. - * 3 = No match found, but eventually would match, if - * CID is longer. - */ -int -isdn_tty_find_icall(int di, int ch, setup_parm *setup) -{ - char *eaz; - int i; - int wret; - int idx; - int si1; - int si2; - char *nr; - ulong flags; - - if (!setup->phone[0]) { - nr = "0"; - printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); - } else - nr = setup->phone; - si1 = (int) setup->si1; - si2 = (int) setup->si2; - if (!setup->eazmsn[0]) { - printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); - eaz = "0"; - } else - eaz = setup->eazmsn; -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); -#endif - wret = 0; - spin_lock_irqsave(&dev->lock, flags); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - - if (info->port.count == 0) - continue; - if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ - (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ - idx = isdn_dc2minor(di, ch); -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret); - printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx, - info->port.flags, info->isdn_driver, - info->isdn_channel, dev->usage[idx]); -#endif - if ( -#ifndef FIX_FILE_TRANSFER - tty_port_active(&info->port) && -#endif - (info->isdn_driver == -1) && - (info->isdn_channel == -1) && - (USG_NONE(dev->usage[idx]))) { - int matchret; - - if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret) - wret = matchret; - if (!matchret) { /* EAZ is matching */ - info->isdn_driver = di; - info->isdn_channel = ch; - info->drv_index = idx; - dev->m_idx[idx] = info->line; - dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); - strcpy(dev->num[idx], nr); - strcpy(info->emu.cpn, eaz); - info->emu.mdmreg[REG_SI1I] = si2bit[si1]; - info->emu.mdmreg[REG_PLAN] = setup->plan; - info->emu.mdmreg[REG_SCREEN] = setup->screen; - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, - info->line); - info->msr |= UART_MSR_RI; - isdn_tty_modem_result(RESULT_RING, info); - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); - return 1; - } - } - } - } - spin_unlock_irqrestore(&dev->lock, flags); - printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, - ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2)) ? "rejected" : "ignored"); - return (wret == 2) ? 3 : 0; -} - -int -isdn_tty_stat_callback(int i, isdn_ctrl *c) -{ - int mi; - modem_info *info; - char *e; - - if (i < 0) - return 0; - if ((mi = dev->m_idx[i]) >= 0) { - info = &dev->mdm.info[mi]; - switch (c->command) { - case ISDN_STAT_CINF: - printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num); - info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10); - if (e == (char *)c->parm.num) - info->emu.charge = 0; - - break; - case ISDN_STAT_BSENT: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line); -#endif - if ((info->isdn_driver == c->driver) && - (info->isdn_channel == c->arg)) { - info->msr |= UART_MSR_CTS; - if (info->send_outstanding) - if (!(--info->send_outstanding)) - info->lsr |= UART_LSR_TEMT; - isdn_tty_tint(info); - return 1; - } - break; - case ISDN_STAT_CAUSE: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line); -#endif - /* Signal cause to tty-device */ - strncpy(info->last_cause, c->parm.num, 5); - return 1; - case ISDN_STAT_DISPLAY: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line); -#endif - /* Signal display to tty-device */ - if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) && - !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) { - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout("DISPLAY: ", info); - isdn_tty_at_cout(c->parm.display, info); - isdn_tty_at_cout("\r\n", info); - } - return 1; - case ISDN_STAT_DCONN: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { - if (info->dialing == 1) { - info->dialing = 2; - return 1; - } - } - break; - case ISDN_STAT_DHUP: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { - if (info->dialing == 1) - isdn_tty_modem_result(RESULT_BUSY, info); - if (info->dialing > 1) - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - info->dialing = 0; -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); -#endif - isdn_tty_modem_hup(info, 0); - return 1; - } - break; - case ISDN_STAT_BCONN: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line); -#endif - /* Wake up any processes waiting - * for incoming call of this device when - * DCD follow the state of incoming carrier - */ - if (info->port.blocked_open && - (info->emu.mdmreg[REG_DCD] & BIT_DCD)) { - wake_up_interruptible(&info->port.open_wait); - } - - /* Schedule CONNECT-Message to any tty - * waiting for it and - * set DCD-bit of its modem-status. - */ - if (tty_port_active(&info->port) || - (info->port.blocked_open && - (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { - info->msr |= UART_MSR_DCD; - info->emu.charge = 0; - if (info->dialing & 0xf) - info->last_dir = 1; - else - info->last_dir = 0; - info->dialing = 0; - info->rcvsched = 1; - if (USG_MODEM(dev->usage[i])) { - if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { - strcpy(info->emu.connmsg, c->parm.num); - isdn_tty_modem_result(RESULT_CONNECT, info); - } else - isdn_tty_modem_result(RESULT_CONNECT64000, info); - } - if (USG_VOICE(dev->usage[i])) - isdn_tty_modem_result(RESULT_VCON, info); - return 1; - } - break; - case ISDN_STAT_BHUP: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); -#endif - isdn_tty_modem_hup(info, 0); - return 1; - } - break; - case ISDN_STAT_NODCH: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { - if (info->dialing) { - info->dialing = 0; - info->last_l2 = -1; - info->last_si = 0; - sprintf(info->last_cause, "0000"); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } - isdn_tty_modem_hup(info, 0); - return 1; - } - break; - case ISDN_STAT_UNLOAD: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line); -#endif - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &dev->mdm.info[i]; - if (info->isdn_driver == c->driver) { - if (info->online) - isdn_tty_modem_hup(info, 1); - } - } - return 1; -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_STAT_FAXIND: - if (tty_port_active(&info->port)) { - isdn_tty_fax_command(info, c); - } - break; -#endif -#ifdef CONFIG_ISDN_AUDIO - case ISDN_STAT_AUDIO: - if (tty_port_active(&info->port)) { - switch (c->parm.num[0]) { - case ISDN_AUDIO_DTMF: - if (info->vonline) { - isdn_audio_put_dle_code(info, - c->parm.num[1]); - } - break; - } - } - break; -#endif - } - } - return 0; -} - -/********************************************************************* - Modem-Emulator-Routines -*********************************************************************/ - -#define cmdchar(c) ((c >= ' ') && (c <= 0x7f)) - -/* - * Put a message from the AT-emulator into receive-buffer of tty, - * convert CR, LF, and BS to values in modem-registers 3, 4 and 5. - */ -void -isdn_tty_at_cout(char *msg, modem_info *info) -{ - struct tty_port *port = &info->port; - atemu *m = &info->emu; - char *p; - char c; - u_long flags; - struct sk_buff *skb = NULL; - char *sp = NULL; - int l; - - if (!msg) { - printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); - return; - } - - l = strlen(msg); - - spin_lock_irqsave(&info->readlock, flags); - if (info->closing) { - spin_unlock_irqrestore(&info->readlock, flags); - return; - } - - /* use queue instead of direct, if online and */ - /* data is in queue or buffer is full */ - if (info->online && ((tty_buffer_request_room(port, l) < l) || - !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) { - skb = alloc_skb(l, GFP_ATOMIC); - if (!skb) { - spin_unlock_irqrestore(&info->readlock, flags); - return; - } - sp = skb_put(skb, l); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - - for (p = msg; *p; p++) { - switch (*p) { - case '\r': - c = m->mdmreg[REG_CR]; - break; - case '\n': - c = m->mdmreg[REG_LF]; - break; - case '\b': - c = m->mdmreg[REG_BS]; - break; - default: - c = *p; - } - if (skb) { - *sp++ = c; - } else { - if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0) - break; - } - } - if (skb) { - __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb); - dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len; - spin_unlock_irqrestore(&info->readlock, flags); - /* Schedule dequeuing */ - if (dev->modempoll && info->rcvsched) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - - } else { - spin_unlock_irqrestore(&info->readlock, flags); - tty_flip_buffer_push(port); - } -} - -/* - * Perform ATH Hangup - */ -static void -isdn_tty_on_hook(modem_info *info) -{ - if (info->isdn_channel >= 0) { -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n"); -#endif - isdn_tty_modem_hup(info, 1); - } -} - -static void -isdn_tty_off_hook(void) -{ - printk(KERN_DEBUG "isdn_tty_off_hook\n"); -} - -#define PLUSWAIT1 (HZ / 2) /* 0.5 sec. */ -#define PLUSWAIT2 (HZ * 3 / 2) /* 1.5 sec */ - -/* - * Check Buffer for Modem-escape-sequence, activate timer-callback to - * isdn_tty_modem_escape() if sequence found. - * - * Parameters: - * p pointer to databuffer - * plus escape-character - * count length of buffer - * pluscount count of valid escape-characters so far - * lastplus timestamp of last character - */ -static void -isdn_tty_check_esc(const u_char *p, u_char plus, int count, int *pluscount, - u_long *lastplus) -{ - if (plus > 127) - return; - if (count > 3) { - p += count - 3; - count = 3; - *pluscount = 0; - } - while (count > 0) { - if (*(p++) == plus) { - if ((*pluscount)++) { - /* Time since last '+' > 0.5 sec. ? */ - if (time_after(jiffies, *lastplus + PLUSWAIT1)) - *pluscount = 1; - } else { - /* Time since last non-'+' < 1.5 sec. ? */ - if (time_before(jiffies, *lastplus + PLUSWAIT2)) - *pluscount = 0; - } - if ((*pluscount == 3) && (count == 1)) - isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1); - if (*pluscount > 3) - *pluscount = 1; - } else - *pluscount = 0; - *lastplus = jiffies; - count--; - } -} - -/* - * Return result of AT-emulator to tty-receive-buffer, depending on - * modem-register 12, bit 0 and 1. - * For CONNECT-messages also switch to online-mode. - * For RING-message handle auto-ATA if register 0 != 0 - */ - -static void -isdn_tty_modem_result(int code, modem_info *info) -{ - atemu *m = &info->emu; - static char *msg[] = - {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR", - "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", - "RINGING", "NO MSN/EAZ", "VCON", "RUNG"}; - char s[ISDN_MSNLEN + 10]; - - switch (code) { - case RESULT_RING: - m->mdmreg[REG_RINGCNT]++; - if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA]) - /* Automatically accept incoming call */ - isdn_tty_cmd_ATA(info); - break; - case RESULT_NO_CARRIER: -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", - info->closing, !info->port.tty); -#endif - m->mdmreg[REG_RINGCNT] = 0; - del_timer(&info->nc_timer); - info->ncarrier = 0; - if (info->closing || !info->port.tty) - return; - -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 1) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n", - info->line); -#endif - /* voice-recording, add DLE-ETX */ - isdn_tty_at_cout("\020\003", info); - } - if (info->vonline & 2) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n", - info->line); -#endif - /* voice-playing, add DLE-DC4 */ - isdn_tty_at_cout("\020\024", info); - } -#endif - break; - case RESULT_CONNECT: - case RESULT_CONNECT64000: - sprintf(info->last_cause, "0000"); - if (!info->online) - info->online = 2; - break; - case RESULT_VCON: -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "res3: send VCON on ttyI%d\n", - info->line); -#endif - sprintf(info->last_cause, "0000"); - if (!info->online) - info->online = 1; - break; - } /* switch (code) */ - - if (m->mdmreg[REG_RESP] & BIT_RESP) { - /* Show results */ - if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) { - /* Show numeric results only */ - sprintf(s, "\r\n%d\r\n", code); - isdn_tty_at_cout(s, info); - } else { - if (code == RESULT_RING) { - /* return if "show RUNG" and ringcounter>1 */ - if ((m->mdmreg[REG_RUNG] & BIT_RUNG) && - (m->mdmreg[REG_RINGCNT] > 1)) - return; - /* print CID, _before_ _every_ ring */ - if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) { - isdn_tty_at_cout("\r\nCALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - if (m->mdmreg[REG_CDN] & BIT_CDN) { - isdn_tty_at_cout("\r\nCALLED NUMBER: ", info); - isdn_tty_at_cout(info->emu.cpn, info); - } - } - } - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(msg[code], info); - switch (code) { - case RESULT_CONNECT: - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_MODEM: - isdn_tty_at_cout(" ", info); - isdn_tty_at_cout(m->connmsg, info); - break; - } - break; - case RESULT_RING: - /* Append CPN, if enabled */ - if ((m->mdmreg[REG_CPN] & BIT_CPN)) { - sprintf(s, "/%s", m->cpn); - isdn_tty_at_cout(s, info); - } - /* Print CID only once, _after_ 1st RING */ - if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && - (m->mdmreg[REG_RINGCNT] == 1)) { - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout("CALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - if (m->mdmreg[REG_CDN] & BIT_CDN) { - isdn_tty_at_cout("\r\nCALLED NUMBER: ", info); - isdn_tty_at_cout(info->emu.cpn, info); - } - } - break; - case RESULT_NO_CARRIER: - case RESULT_NO_DIALTONE: - case RESULT_BUSY: - case RESULT_NO_ANSWER: - m->mdmreg[REG_RINGCNT] = 0; - /* Append Cause-Message if enabled */ - if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) { - sprintf(s, "/%s", info->last_cause); - isdn_tty_at_cout(s, info); - } - break; - case RESULT_CONNECT64000: - /* Append Protocol to CONNECT message */ - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - isdn_tty_at_cout("/X.75", info); - break; - case ISDN_PROTO_L2_HDLC: - isdn_tty_at_cout("/HDLC", info); - break; - case ISDN_PROTO_L2_V11096: - isdn_tty_at_cout("/V110/9600", info); - break; - case ISDN_PROTO_L2_V11019: - isdn_tty_at_cout("/V110/19200", info); - break; - case ISDN_PROTO_L2_V11038: - isdn_tty_at_cout("/V110/38400", info); - break; - } - if (m->mdmreg[REG_T70] & BIT_T70) { - isdn_tty_at_cout("/T.70", info); - if (m->mdmreg[REG_T70] & BIT_T70_EXT) - isdn_tty_at_cout("+", info); - } - break; - } - isdn_tty_at_cout("\r\n", info); - } - } - if (code == RESULT_NO_CARRIER) { - if (info->closing || (!info->port.tty)) - return; - - if (tty_port_check_carrier(&info->port)) - tty_hangup(info->port.tty); - } -} - - -/* - * Display a modem-register-value. - */ -static void -isdn_tty_show_profile(int ridx, modem_info *info) -{ - char v[6]; - - sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]); - isdn_tty_at_cout(v, info); -} - -/* - * Get MSN-string from char-pointer, set pointer to end of number - */ -static void -isdn_tty_get_msnstr(char *n, char **p) -{ - int limit = ISDN_MSNLEN - 1; - - while (((*p[0] >= '0' && *p[0] <= '9') || - /* Why a comma ??? */ - (*p[0] == ',') || (*p[0] == ':')) && - (limit--)) - *n++ = *p[0]++; - *n = '\0'; -} - -/* - * Get phone-number from modem-commandbuffer - */ -static void -isdn_tty_getdial(char *p, char *q, int cnt) -{ - int first = 1; - int limit = ISDN_MSNLEN - 1; /* MUST match the size of interface var to avoid - buffer overflow */ - - while (strchr(" 0123456789,#.*WPTSR-", *p) && *p && --cnt > 0) { - if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) || - ((*p == 'R') && first) || - (*p == '*') || (*p == '#')) { - *q++ = *p; - limit--; - } - if (!limit) - break; - p++; - first = 0; - } - *q = 0; -} - -#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; } -#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; } - -static void -isdn_tty_report(modem_info *info) -{ - atemu *m = &info->emu; - char s[80]; - - isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info); - sprintf(s, " Remote Number: %s\r\n", info->last_num); - isdn_tty_at_cout(s, info); - sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming"); - isdn_tty_at_cout(s, info); - isdn_tty_at_cout(" Layer-2 Protocol: ", info); - switch (info->last_l2) { - case ISDN_PROTO_L2_X75I: - isdn_tty_at_cout("X.75i", info); - break; - case ISDN_PROTO_L2_X75UI: - isdn_tty_at_cout("X.75ui", info); - break; - case ISDN_PROTO_L2_X75BUI: - isdn_tty_at_cout("X.75bui", info); - break; - case ISDN_PROTO_L2_HDLC: - isdn_tty_at_cout("HDLC", info); - break; - case ISDN_PROTO_L2_V11096: - isdn_tty_at_cout("V.110 9600 Baud", info); - break; - case ISDN_PROTO_L2_V11019: - isdn_tty_at_cout("V.110 19200 Baud", info); - break; - case ISDN_PROTO_L2_V11038: - isdn_tty_at_cout("V.110 38400 Baud", info); - break; - case ISDN_PROTO_L2_TRANS: - isdn_tty_at_cout("transparent", info); - break; - case ISDN_PROTO_L2_MODEM: - isdn_tty_at_cout("modem", info); - break; - case ISDN_PROTO_L2_FAX: - isdn_tty_at_cout("fax", info); - break; - default: - isdn_tty_at_cout("unknown", info); - break; - } - if (m->mdmreg[REG_T70] & BIT_T70) { - isdn_tty_at_cout("/T.70", info); - if (m->mdmreg[REG_T70] & BIT_T70_EXT) - isdn_tty_at_cout("+", info); - } - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(" Service: ", info); - switch (info->last_si) { - case 1: - isdn_tty_at_cout("audio\r\n", info); - break; - case 5: - isdn_tty_at_cout("btx\r\n", info); - break; - case 7: - isdn_tty_at_cout("data\r\n", info); - break; - default: - sprintf(s, "%d\r\n", info->last_si); - isdn_tty_at_cout(s, info); - break; - } - sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote"); - isdn_tty_at_cout(s, info); - sprintf(s, " Last cause: %s\r\n", info->last_cause); - isdn_tty_at_cout(s, info); -} - -/* - * Parse AT&.. commands. - */ -static int -isdn_tty_cmd_ATand(char **p, modem_info *info) -{ - atemu *m = &info->emu; - int i; - char rb[100]; - -#define MAXRB (sizeof(rb) - 1) - - switch (*p[0]) { - case 'B': - /* &B - Set Buffersize */ - p[0]++; - i = isdn_getnum(p); - if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX)) - PARSE_ERROR1; -#ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF)) - PARSE_ERROR1; -#endif - m->mdmreg[REG_PSIZE] = i / 16; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - info->xmit_size /= 10; - } - break; - case 'C': - /* &C - DCD Status */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[REG_DCD] &= ~BIT_DCD; - break; - case 1: - m->mdmreg[REG_DCD] |= BIT_DCD; - break; - default: - PARSE_ERROR1 - } - break; - case 'D': - /* &D - Set DTR-Low-behavior */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP; - m->mdmreg[REG_DTRR] &= ~BIT_DTRR; - break; - case 2: - m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP; - m->mdmreg[REG_DTRR] &= ~BIT_DTRR; - break; - case 3: - m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP; - m->mdmreg[REG_DTRR] |= BIT_DTRR; - break; - default: - PARSE_ERROR1 - } - break; - case 'E': - /* &E -Set EAZ/MSN */ - p[0]++; - isdn_tty_get_msnstr(m->msn, p); - break; - case 'F': - /* &F -Set Factory-Defaults */ - p[0]++; - if (info->msr & UART_MSR_DCD) - PARSE_ERROR1; - isdn_tty_reset_profile(m); - isdn_tty_modem_reset_regs(info, 1); - break; -#ifdef DUMMY_HAYES_AT - case 'K': - /* only for be compilant with common scripts */ - /* &K Flowcontrol - no function */ - p[0]++; - isdn_getnum(p); - break; -#endif - case 'L': - /* &L -Set Numbers to listen on */ - p[0]++; - i = 0; - while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) && - (i < ISDN_LMSNLEN - 1)) - m->lmsn[i++] = *p[0]++; - m->lmsn[i] = '\0'; - break; - case 'R': - /* &R - Set V.110 bitrate adaption */ - p[0]++; - i = isdn_getnum(p); - switch (i) { - case 0: - /* Switch off V.110, back to X.75 */ - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - m->mdmreg[REG_SI2] = 0; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - break; - case 9600: - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096; - m->mdmreg[REG_SI2] = 197; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10; - break; - case 19200: - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019; - m->mdmreg[REG_SI2] = 199; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10; - break; - case 38400: - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038; - m->mdmreg[REG_SI2] = 198; /* no existing standard for this */ - info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10; - break; - default: - PARSE_ERROR1; - } - /* Switch off T.70 */ - m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT); - /* Set Service 7 */ - m->mdmreg[REG_SI1] |= 4; - break; - case 'S': - /* &S - Set Windowsize */ - p[0]++; - i = isdn_getnum(p); - if ((i > 0) && (i < 9)) - m->mdmreg[REG_WSIZE] = i; - else - PARSE_ERROR1; - break; - case 'V': - /* &V - Show registers */ - p[0]++; - isdn_tty_at_cout("\r\n", info); - for (i = 0; i < ISDN_MODEM_NUMREG; i++) { - sprintf(rb, "S%02d=%03d%s", i, - m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n"); - isdn_tty_at_cout(rb, info); - } - sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n", - strlen(m->msn) ? m->msn : "None"); - isdn_tty_at_cout(rb, info); - if (strlen(m->lmsn)) { - isdn_tty_at_cout("\r\nListen: ", info); - isdn_tty_at_cout(m->lmsn, info); - isdn_tty_at_cout("\r\n", info); - } - break; - case 'W': - /* &W - Write Profile */ - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - modem_write_profile(m); - break; - default: - PARSE_ERROR1; - } - break; - case 'X': - /* &X - Switch to BTX-Mode and T.70 */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT); - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - break; - case 1: - m->mdmreg[REG_T70] |= BIT_T70; - m->mdmreg[REG_T70] &= ~BIT_T70_EXT; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - info->xmit_size = 112; - m->mdmreg[REG_SI1] = 4; - m->mdmreg[REG_SI2] = 0; - break; - case 2: - m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT); - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - info->xmit_size = 112; - m->mdmreg[REG_SI1] = 4; - m->mdmreg[REG_SI2] = 0; - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; -} - -static int -isdn_tty_check_ats(int mreg, int mval, modem_info *info, atemu *m) -{ - /* Some plausibility checks */ - switch (mreg) { - case REG_L2PROT: - if (mval > ISDN_PROTO_L2_MAX) - return 1; - break; - case REG_PSIZE: - if ((mval * 16) > ISDN_SERIAL_XMIT_MAX) - return 1; -#ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX)) - return 1; -#endif - info->xmit_size = mval * 16; - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - info->xmit_size /= 10; - } - break; - case REG_SI1I: - case REG_PLAN: - case REG_SCREEN: - /* readonly registers */ - return 1; - } - return 0; -} - -/* - * Perform ATS command - */ -static int -isdn_tty_cmd_ATS(char **p, modem_info *info) -{ - atemu *m = &info->emu; - int bitpos; - int mreg; - int mval; - int bval; - - mreg = isdn_getnum(p); - if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG) - PARSE_ERROR1; - switch (*p[0]) { - case '=': - p[0]++; - mval = isdn_getnum(p); - if (mval < 0 || mval > 255) - PARSE_ERROR1; - if (isdn_tty_check_ats(mreg, mval, info, m)) - PARSE_ERROR1; - m->mdmreg[mreg] = mval; - break; - case '.': - /* Set/Clear a single bit */ - p[0]++; - bitpos = isdn_getnum(p); - if ((bitpos < 0) || (bitpos > 7)) - PARSE_ERROR1; - switch (*p[0]) { - case '=': - p[0]++; - bval = isdn_getnum(p); - if (bval < 0 || bval > 1) - PARSE_ERROR1; - if (bval) - mval = m->mdmreg[mreg] | (1 << bitpos); - else - mval = m->mdmreg[mreg] & ~(1 << bitpos); - if (isdn_tty_check_ats(mreg, mval, info, m)) - PARSE_ERROR1; - m->mdmreg[mreg] = mval; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0", - info); - break; - default: - PARSE_ERROR1; - } - break; - case '?': - p[0]++; - isdn_tty_show_profile(mreg, info); - break; - default: - PARSE_ERROR1; - break; - } - return 0; -} - -/* - * Perform ATA command - */ -static void -isdn_tty_cmd_ATA(modem_info *info) -{ - atemu *m = &info->emu; - isdn_ctrl cmd; - int l2; - - if (info->msr & UART_MSR_RI) { - /* Accept incoming call */ - info->last_dir = 0; - strcpy(info->last_num, dev->num[info->drv_index]); - m->mdmreg[REG_RINGCNT] = 0; - info->msr &= ~UART_MSR_RI; - l2 = m->mdmreg[REG_L2PROT]; -#ifdef CONFIG_ISDN_AUDIO - /* If more than one bit set in reg18, autoselect Layer2 */ - if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) { - if (m->mdmreg[REG_SI1I] == 1) { - if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX)) - l2 = ISDN_PROTO_L2_TRANS; - } else - l2 = ISDN_PROTO_L2_X75I; - } -#endif - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = info->isdn_channel + (l2 << 8); - info->last_l2 = l2; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); -#ifdef CONFIG_ISDN_TTY_FAX - if (l2 == ISDN_PROTO_L2_FAX) { - cmd.parm.fax = info->fax; - info->fax->direction = ISDN_TTY_FAX_CONN_IN; - } -#endif - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTD; - info->dialing = 16; - info->emu.carrierwait = 0; - isdn_command(&cmd); - isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); - } else - isdn_tty_modem_result(RESULT_NO_ANSWER, info); -} - -#ifdef CONFIG_ISDN_AUDIO -/* - * Parse AT+F.. commands - */ -static int -isdn_tty_cmd_PLUSF(char **p, modem_info *info) -{ - atemu *m = &info->emu; - char rs[20]; - - if (!strncmp(p[0], "CLASS", 5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", - (m->mdmreg[REG_SI1] & 1) ? 8 : 0); -#ifdef CONFIG_ISDN_TTY_FAX - if (TTY_IS_FCLASS2(info)) - sprintf(rs, "\r\n2"); - else if (TTY_IS_FCLASS1(info)) - sprintf(rs, "\r\n1"); -#endif - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS; - m->mdmreg[REG_SI1] = 4; - info->xmit_size = - m->mdmreg[REG_PSIZE] * 16; - break; -#ifdef CONFIG_ISDN_TTY_FAX - case '1': - p[0]++; - if (!(dev->global_features & - ISDN_FEATURE_L3_FCLASS1)) - PARSE_ERROR1; - m->mdmreg[REG_SI1] = 1; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1; - info->xmit_size = - m->mdmreg[REG_PSIZE] * 16; - break; - case '2': - p[0]++; - if (!(dev->global_features & - ISDN_FEATURE_L3_FCLASS2)) - PARSE_ERROR1; - m->mdmreg[REG_SI1] = 1; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2; - info->xmit_size = - m->mdmreg[REG_PSIZE] * 16; - break; -#endif - case '8': - p[0]++; - /* L2 will change on dialout with si=1 */ - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS; - m->mdmreg[REG_SI1] = 5; - info->xmit_size = VBUF; - break; - case '?': - p[0]++; - strcpy(rs, "\r\n0,"); -#ifdef CONFIG_ISDN_TTY_FAX - if (dev->global_features & - ISDN_FEATURE_L3_FCLASS1) - strcat(rs, "1,"); - if (dev->global_features & - ISDN_FEATURE_L3_FCLASS2) - strcat(rs, "2,"); -#endif - strcat(rs, "8"); - isdn_tty_at_cout(rs, info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; - } -#ifdef CONFIG_ISDN_TTY_FAX - return (isdn_tty_cmd_PLUSF_FAX(p, info)); -#else - PARSE_ERROR1; -#endif -} - -/* - * Parse AT+V.. commands - */ -static int -isdn_tty_cmd_PLUSV(char **p, modem_info *info) -{ - atemu *m = &info->emu; - isdn_ctrl cmd; - static char *vcmd[] = - {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL}; - int i; - int par1; - int par2; - char rs[20]; - - i = 0; - while (vcmd[i]) { - if (!strncmp(vcmd[i], p[0], 2)) { - p[0] += 2; - break; - } - i++; - } - switch (i) { - case 0: - /* AT+VNH - Auto hangup feature */ - switch (*p[0]) { - case '?': - p[0]++; - isdn_tty_at_cout("\r\n1", info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '1': - p[0]++; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n1", info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 1: - /* AT+VIP - Reset all voice parameters */ - isdn_tty_modem_reset_vpar(m); - break; - case 2: - /* AT+VLS - Select device, accept incoming call */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", m->vpar[0]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - m->vpar[0] = 0; - break; - case '2': - p[0]++; - m->vpar[0] = 2; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n0,2", info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 3: - /* AT+VRX - Start recording */ - if (!m->vpar[0]) - PARSE_ERROR1; - if (info->online != 1) { - isdn_tty_modem_result(RESULT_NO_ANSWER, info); - return 1; - } - info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); - if (!info->dtmf_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); - PARSE_ERROR1; - } - info->silence_state = isdn_audio_silence_init(info->silence_state); - if (!info->silence_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n"); - PARSE_ERROR1; - } - if (m->vpar[3] < 5) { - info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); - if (!info->adpcmr) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); - PARSE_ERROR1; - } - } -#ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: +VRX\n"); -#endif - info->vonline |= 1; - isdn_tty_modem_result(RESULT_CONNECT, info); - return 0; - break; - case 4: - /* AT+VSD - Silence detection */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n<%d>,<%d>", - m->vpar[1], - m->vpar[2]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if ((*p[0] >= '0') && (*p[0] <= '9')) { - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 31)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[1] = par1; - m->vpar[2] = par2; - break; - } else - if (*p[0] == '?') { - p[0]++; - isdn_tty_at_cout("\r\n<0-31>,<0-255>", - info); - break; - } else - PARSE_ERROR1; - break; - default: - PARSE_ERROR1; - } - break; - case 5: - /* AT+VSM - Select compression */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n<%d>,<%d><8000>", - m->vpar[3], - m->vpar[1]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '2': - case '3': - case '4': - case '5': - case '6': - par1 = isdn_getnum(p); - if ((par1 < 2) || (par1 > 6)) - PARSE_ERROR1; - m->vpar[3] = par1; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n", - info); - isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n", - info); - isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n", - info); - isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n", - info); - isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n", - info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 6: - /* AT+VTX - Start sending */ - if (!m->vpar[0]) - PARSE_ERROR1; - if (info->online != 1) { - isdn_tty_modem_result(RESULT_NO_ANSWER, info); - return 1; - } - info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); - if (!info->dtmf_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); - PARSE_ERROR1; - } - if (m->vpar[3] < 5) { - info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]); - if (!info->adpcms) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); - PARSE_ERROR1; - } - } -#ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: +VTX\n"); -#endif - m->lastDLE = 0; - info->vonline |= 2; - isdn_tty_modem_result(RESULT_CONNECT, info); - return 0; - break; - case 7: - /* AT+VDD - DTMF detection */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n<%d>,<%d>", - m->vpar[4], - m->vpar[5]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if ((*p[0] >= '0') && (*p[0] <= '9')) { - if (info->online != 1) - PARSE_ERROR1; - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 15)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[4] = par1; - m->vpar[5] = par2; - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_AUDIO; - cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8); - cmd.parm.num[0] = par1; - cmd.parm.num[1] = par2; - isdn_command(&cmd); - break; - } else - if (*p[0] == '?') { - p[0]++; - isdn_tty_at_cout("\r\n<0-15>,<0-255>", - info); - break; - } else - PARSE_ERROR1; - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; -} -#endif /* CONFIG_ISDN_AUDIO */ - -/* - * Parse and perform an AT-command-line. - */ -static void -isdn_tty_parse_at(modem_info *info) -{ - atemu *m = &info->emu; - char *p; - char ds[ISDN_MSNLEN]; - -#ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); -#endif - for (p = &m->mdmcmd[2]; *p;) { - switch (*p) { - case ' ': - p++; - break; - case 'A': - /* A - Accept incoming call */ - p++; - isdn_tty_cmd_ATA(info); - return; - case 'D': - /* D - Dial */ - if (info->msr & UART_MSR_DCD) - PARSE_ERROR; - if (info->msr & UART_MSR_RI) { - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - return; - } - isdn_tty_getdial(++p, ds, sizeof ds); - p += strlen(p); - if (!strlen(m->msn)) - isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info); - else if (strlen(ds)) - isdn_tty_dial(ds, info, m); - else - PARSE_ERROR; - return; - case 'E': - /* E - Turn Echo on/off */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[REG_ECHO] &= ~BIT_ECHO; - break; - case 1: - m->mdmreg[REG_ECHO] |= BIT_ECHO; - break; - default: - PARSE_ERROR; - } - break; - case 'H': - /* H - On/Off-hook */ - p++; - switch (*p) { - case '0': - p++; - isdn_tty_on_hook(info); - break; - case '1': - p++; - isdn_tty_off_hook(); - break; - default: - isdn_tty_on_hook(info); - break; - } - break; - case 'I': - /* I - Information */ - p++; - isdn_tty_at_cout("\r\nLinux ISDN", info); - switch (*p) { - case '0': - case '1': - p++; - break; - case '2': - p++; - isdn_tty_report(info); - break; - case '3': - p++; - snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge); - isdn_tty_at_cout(ds, info); - break; - default:; - } - break; -#ifdef DUMMY_HAYES_AT - case 'L': - case 'M': - /* only for be compilant with common scripts */ - /* no function */ - p++; - isdn_getnum(&p); - break; -#endif - case 'O': - /* O - Go online */ - p++; - if (info->msr & UART_MSR_DCD) - /* if B-Channel is up */ - isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT : RESULT_CONNECT64000, info); - else - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - return; - case 'Q': - /* Q - Turn Emulator messages on/off */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[REG_RESP] |= BIT_RESP; - break; - case 1: - m->mdmreg[REG_RESP] &= ~BIT_RESP; - break; - default: - PARSE_ERROR; - } - break; - case 'S': - /* S - Set/Get Register */ - p++; - if (isdn_tty_cmd_ATS(&p, info)) - return; - break; - case 'V': - /* V - Numeric or ASCII Emulator-messages */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[REG_RESP] |= BIT_RESPNUM; - break; - case 1: - m->mdmreg[REG_RESP] &= ~BIT_RESPNUM; - break; - default: - PARSE_ERROR; - } - break; - case 'Z': - /* Z - Load Registers from Profile */ - p++; - if (info->msr & UART_MSR_DCD) { - info->online = 0; - isdn_tty_on_hook(info); - } - isdn_tty_modem_reset_regs(info, 1); - break; - case '+': - p++; - switch (*p) { -#ifdef CONFIG_ISDN_AUDIO - case 'F': - p++; - if (isdn_tty_cmd_PLUSF(&p, info)) - return; - break; - case 'V': - if ((!(m->mdmreg[REG_SI1] & 1)) || - (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) - PARSE_ERROR; - p++; - if (isdn_tty_cmd_PLUSV(&p, info)) - return; - break; -#endif /* CONFIG_ISDN_AUDIO */ - case 'S': /* SUSPEND */ - p++; - isdn_tty_get_msnstr(ds, &p); - isdn_tty_suspend(ds, info, m); - break; - case 'R': /* RESUME */ - p++; - isdn_tty_get_msnstr(ds, &p); - isdn_tty_resume(ds, info, m); - break; - case 'M': /* MESSAGE */ - p++; - isdn_tty_send_msg(info, m, p); - break; - default: - PARSE_ERROR; - } - break; - case '&': - p++; - if (isdn_tty_cmd_ATand(&p, info)) - return; - break; - default: - PARSE_ERROR; - } - } -#ifdef CONFIG_ISDN_AUDIO - if (!info->vonline) -#endif - isdn_tty_modem_result(RESULT_OK, info); -} - -/* Need own toupper() because standard-toupper is not available - * within modules. - */ -#define my_toupper(c) (((c >= 'a') && (c <= 'z')) ? (c & 0xdf) : c) - -/* - * Perform line-editing of AT-commands - * - * Parameters: - * p inputbuffer - * count length of buffer - * channel index to line (minor-device) - */ -static int -isdn_tty_edit_at(const char *p, int count, modem_info *info) -{ - atemu *m = &info->emu; - int total = 0; - u_char c; - char eb[2]; - int cnt; - - for (cnt = count; cnt > 0; p++, cnt--) { - c = *p; - total++; - if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) { - /* Separator (CR or LF) */ - m->mdmcmd[m->mdmcmdl] = 0; - if (m->mdmreg[REG_ECHO] & BIT_ECHO) { - eb[0] = c; - eb[1] = 0; - isdn_tty_at_cout(eb, info); - } - if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2)))) - isdn_tty_parse_at(info); - m->mdmcmdl = 0; - continue; - } - if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) { - /* Backspace-Function */ - if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) { - if (m->mdmcmdl) - m->mdmcmdl--; - if (m->mdmreg[REG_ECHO] & BIT_ECHO) - isdn_tty_at_cout("\b", info); - } - continue; - } - if (cmdchar(c)) { - if (m->mdmreg[REG_ECHO] & BIT_ECHO) { - eb[0] = c; - eb[1] = 0; - isdn_tty_at_cout(eb, info); - } - if (m->mdmcmdl < 255) { - c = my_toupper(c); - switch (m->mdmcmdl) { - case 1: - if (c == 'T') { - m->mdmcmd[m->mdmcmdl] = c; - m->mdmcmd[++m->mdmcmdl] = 0; - break; - } else - m->mdmcmdl = 0; - /* Fall through - check for 'A' */ - case 0: - if (c == 'A') { - m->mdmcmd[m->mdmcmdl] = c; - m->mdmcmd[++m->mdmcmdl] = 0; - } - break; - default: - m->mdmcmd[m->mdmcmdl] = c; - m->mdmcmd[++m->mdmcmdl] = 0; - } - } - } - } - return total; -} - -/* - * Switch all modem-channels who are online and got a valid - * escape-sequence 1.5 seconds ago, to command-mode. - * This function is called every second via timer-interrupt from within - * timer-dispatcher isdn_timer_function() - */ -void -isdn_tty_modem_escape(void) -{ - int ton = 0; - int i; - int midx; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) { - modem_info *info = &dev->mdm.info[midx]; - if (info->online) { - ton = 1; - if ((info->emu.pluscount == 3) && - time_after(jiffies, - info->emu.lastplus + PLUSWAIT2)) { - info->emu.pluscount = 0; - info->online = 0; - isdn_tty_modem_result(RESULT_OK, info); - } - } - } - isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton); -} - -/* - * Put a RING-message to all modem-channels who have the RI-bit set. - * This function is called every second via timer-interrupt from within - * timer-dispatcher isdn_timer_function() - */ -void -isdn_tty_modem_ring(void) -{ - int ton = 0; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (info->msr & UART_MSR_RI) { - ton = 1; - isdn_tty_modem_result(RESULT_RING, info); - } - } - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); -} - -/* - * For all online tty's, try sending data to - * the lower levels. - */ -void -isdn_tty_modem_xmit(void) -{ - int ton = 1; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (info->online) { - ton = 1; - isdn_tty_senddown(info); - isdn_tty_tint(info); - } - } - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); -} - -/* - * Check all channels if we have a 'no carrier' timeout. - * Timeout value is set by Register S7. - */ -void -isdn_tty_carrier_timeout(void) -{ - int ton = 0; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (!info->dialing) - continue; - if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { - info->dialing = 0; - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - isdn_tty_modem_hup(info, 1); - } else - ton = 1; - } - isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton); -} diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h deleted file mode 100644 index a6f801d2263b..000000000000 --- a/drivers/isdn/i4l/isdn_tty.h +++ /dev/null @@ -1,120 +0,0 @@ -/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, tty related functions (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#define DLE 0x10 -#define ETX 0x03 -#define DC4 0x14 - - -/* - * Definition of some special Registers of AT-Emulator - */ -#define REG_RINGATA 0 -#define REG_RINGCNT 1 /* ring counter register */ -#define REG_ESC 2 -#define REG_CR 3 -#define REG_LF 4 -#define REG_BS 5 - -#define REG_WAITC 7 - -#define REG_RESP 12 /* show response messages register */ -#define BIT_RESP 1 /* show response messages bit */ -#define REG_RESPNUM 12 /* show numeric responses register */ -#define BIT_RESPNUM 2 /* show numeric responses bit */ -#define REG_ECHO 12 -#define BIT_ECHO 4 -#define REG_DCD 12 -#define BIT_DCD 8 -#define REG_CTS 12 -#define BIT_CTS 16 -#define REG_DTRR 12 -#define BIT_DTRR 32 -#define REG_DSR 12 -#define BIT_DSR 64 -#define REG_CPPP 12 -#define BIT_CPPP 128 - -#define REG_DXMT 13 -#define BIT_DXMT 1 -#define REG_T70 13 -#define BIT_T70 2 -#define BIT_T70_EXT 32 -#define REG_DTRHUP 13 -#define BIT_DTRHUP 4 -#define REG_RESPXT 13 -#define BIT_RESPXT 8 -#define REG_CIDONCE 13 -#define BIT_CIDONCE 16 -#define REG_RUNG 13 /* show RUNG message register */ -#define BIT_RUNG 64 /* show RUNG message bit */ -#define REG_DISPLAY 13 -#define BIT_DISPLAY 128 - -#define REG_L2PROT 14 -#define REG_L3PROT 15 -#define REG_PSIZE 16 -#define REG_WSIZE 17 -#define REG_SI1 18 -#define REG_SI2 19 -#define REG_SI1I 20 -#define REG_PLAN 21 -#define REG_SCREEN 22 - -#define REG_CPN 23 -#define BIT_CPN 1 -#define REG_CPNFCON 23 -#define BIT_CPNFCON 2 -#define REG_CDN 23 -#define BIT_CDN 4 - -/* defines for result codes */ -#define RESULT_OK 0 -#define RESULT_CONNECT 1 -#define RESULT_RING 2 -#define RESULT_NO_CARRIER 3 -#define RESULT_ERROR 4 -#define RESULT_CONNECT64000 5 -#define RESULT_NO_DIALTONE 6 -#define RESULT_BUSY 7 -#define RESULT_NO_ANSWER 8 -#define RESULT_RINGING 9 -#define RESULT_NO_MSN_EAZ 10 -#define RESULT_VCON 11 -#define RESULT_RUNG 12 - -#define TTY_IS_FCLASS1(info) \ - ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ - (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1)) -#define TTY_IS_FCLASS2(info) \ - ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ - (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2)) - -extern void isdn_tty_modem_escape(void); -extern void isdn_tty_modem_ring(void); -extern void isdn_tty_carrier_timeout(void); -extern void isdn_tty_modem_xmit(void); -extern int isdn_tty_modem_init(void); -extern void isdn_tty_exit(void); -extern void isdn_tty_readmodem(void); -extern int isdn_tty_find_icall(int, int, setup_parm *); -extern int isdn_tty_stat_callback(int, isdn_ctrl *); -extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); -extern int isdn_tty_capi_facility(capi_msg *cm); -extern void isdn_tty_at_cout(char *, modem_info *); -extern void isdn_tty_modem_hup(modem_info *, int); -#ifdef CONFIG_ISDN_TTY_FAX -extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *); -extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *); -extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *); -#endif diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c deleted file mode 100644 index 47aae4916730..000000000000 --- a/drivers/isdn/i4l/isdn_ttyfax.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). - * - * Copyright 1999 by Armin Schindler (mac@melware.de) - * Copyright 1999 by Ralf Spachmann (mel@melware.de) - * Copyright 1999 by Cytronics & Melware - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#undef ISDN_TTY_FAX_STAT_DEBUG -#undef ISDN_TTY_FAX_CMD_DEBUG - -#include -#include "isdn_common.h" -#include "isdn_tty.h" -#include "isdn_ttyfax.h" - - -static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $"; - -#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } - -static char * -isdn_getrev(const char *revision) -{ - char *rev; - char *p; - - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; -} - -/* - * Fax Class 2 Modem results - * - */ - -static void -isdn_tty_fax_modem_result(int code, modem_info *info) -{ - atemu *m = &info->emu; - T30_s *f = info->fax; - char rs[50]; - char rss[50]; - char *rp; - int i; - static char *msg[] = - {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:", - "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:", - "+FCFR", "+FPTS:", "+FET:"}; - - - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(msg[code], info); - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n", - msg[code], info->line); -#endif - switch (code) { - case 0: /* OK */ - break; - case 1: /* ERROR */ - break; - case 2: /* +FCON */ - /* Append CPN, if enabled */ - if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) && - (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) { - sprintf(rs, "/%s", m->cpn); - isdn_tty_at_cout(rs, info); - } - info->online = 1; - f->fet = 0; - if (f->phase == ISDN_FAX_PHASE_A) - f->phase = ISDN_FAX_PHASE_B; - break; - case 3: /* +FCSI */ - case 8: /* +FTSI */ - sprintf(rs, "\"%s\"", f->r_id); - isdn_tty_at_cout(rs, info); - break; - case 4: /* +FDIS */ - rs[0] = 0; - rp = &f->r_resolution; - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n", - rs, info->line); -#endif - break; - case 5: /* +FHNG */ - sprintf(rs, "%d", f->code); - isdn_tty_at_cout(rs, info); - info->faxonline = 0; - break; - case 6: /* +FDCS */ - rs[0] = 0; - rp = &f->r_resolution; - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n", - rs, info->line); -#endif - break; - case 7: /* CONNECT */ - info->faxonline |= 2; - break; - case 9: /* FCFR */ - break; - case 10: /* FPTS */ - isdn_tty_at_cout("1", info); - break; - case 11: /* FET */ - sprintf(rs, "%d", f->fet); - isdn_tty_at_cout(rs, info); - break; - } - - isdn_tty_at_cout("\r\n", info); - - switch (code) { - case 7: /* CONNECT */ - info->online = 2; - if (info->faxonline & 1) { - sprintf(rs, "%c", XON); - isdn_tty_at_cout(rs, info); - } - break; - } -} - -static int -isdn_tty_fax_command1(modem_info *info, isdn_ctrl *c) -{ - static char *msg[] = - {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"}; - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd); -#endif - if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) { - if (info->online) - info->online = 1; - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(msg[c->parm.aux.cmd], info); - isdn_tty_at_cout("\r\n", info); - } - switch (c->parm.aux.cmd) { - case ISDN_FAX_CLASS1_CONNECT: - info->online = 2; - break; - case ISDN_FAX_CLASS1_OK: - case ISDN_FAX_CLASS1_FCERROR: - case ISDN_FAX_CLASS1_ERROR: - case ISDN_FAX_CLASS1_NOCARR: - break; - case ISDN_FAX_CLASS1_QUERY: - isdn_tty_at_cout("\r\n", info); - if (!c->parm.aux.para[0]) { - isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info); - isdn_tty_at_cout("\r\n", info); - } else { - isdn_tty_at_cout(c->parm.aux.para, info); - isdn_tty_at_cout("\r\nOK\r\n", info); - } - break; - } - return (0); -} - -int -isdn_tty_fax_command(modem_info *info, isdn_ctrl *c) -{ - T30_s *f = info->fax; - char rs[10]; - - if (TTY_IS_FCLASS1(info)) - return (isdn_tty_fax_command1(info, c)); - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n", - f->r_code, info->line); -#endif - switch (f->r_code) { - case ISDN_TTY_FAX_FCON: - info->faxonline = 1; - isdn_tty_fax_modem_result(2, info); /* +FCON */ - return (0); - case ISDN_TTY_FAX_FCON_I: - info->faxonline = 16; - isdn_tty_fax_modem_result(2, info); /* +FCON */ - return (0); - case ISDN_TTY_FAX_RID: - if (info->faxonline & 1) - isdn_tty_fax_modem_result(3, info); /* +FCSI */ - if (info->faxonline & 16) - isdn_tty_fax_modem_result(8, info); /* +FTSI */ - return (0); - case ISDN_TTY_FAX_DIS: - isdn_tty_fax_modem_result(4, info); /* +FDIS */ - return (0); - case ISDN_TTY_FAX_HNG: - if (f->phase == ISDN_FAX_PHASE_C) { - if (f->direction == ISDN_TTY_FAX_CONN_IN) { - sprintf(rs, "%c%c", DLE, ETX); - isdn_tty_at_cout(rs, info); - } else { - sprintf(rs, "%c", 0x18); - isdn_tty_at_cout(rs, info); - } - info->faxonline &= ~2; /* leave data mode */ - info->online = 1; - } - f->phase = ISDN_FAX_PHASE_E; - isdn_tty_fax_modem_result(5, info); /* +FHNG */ - isdn_tty_fax_modem_result(0, info); /* OK */ - return (0); - case ISDN_TTY_FAX_DCS: - isdn_tty_fax_modem_result(6, info); /* +FDCS */ - isdn_tty_fax_modem_result(7, info); /* CONNECT */ - f->phase = ISDN_FAX_PHASE_C; - return (0); - case ISDN_TTY_FAX_TRAIN_OK: - isdn_tty_fax_modem_result(6, info); /* +FDCS */ - isdn_tty_fax_modem_result(0, info); /* OK */ - return (0); - case ISDN_TTY_FAX_SENT: - isdn_tty_fax_modem_result(0, info); /* OK */ - return (0); - case ISDN_TTY_FAX_CFR: - isdn_tty_fax_modem_result(9, info); /* +FCFR */ - return (0); - case ISDN_TTY_FAX_ET: - sprintf(rs, "%c%c", DLE, ETX); - isdn_tty_at_cout(rs, info); - isdn_tty_fax_modem_result(10, info); /* +FPTS */ - isdn_tty_fax_modem_result(11, info); /* +FET */ - isdn_tty_fax_modem_result(0, info); /* OK */ - info->faxonline &= ~2; /* leave data mode */ - info->online = 1; - f->phase = ISDN_FAX_PHASE_D; - return (0); - case ISDN_TTY_FAX_PTS: - isdn_tty_fax_modem_result(10, info); /* +FPTS */ - if (f->direction == ISDN_TTY_FAX_CONN_OUT) { - if (f->fet == 1) - f->phase = ISDN_FAX_PHASE_B; - if (f->fet == 0) - isdn_tty_fax_modem_result(0, info); /* OK */ - } - return (0); - case ISDN_TTY_FAX_EOP: - info->faxonline &= ~2; /* leave data mode */ - info->online = 1; - f->phase = ISDN_FAX_PHASE_D; - return (0); - - } - return (-1); -} - - -void -isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb) -{ - __u8 LeftMask; - __u8 RightMask; - __u8 fBit; - __u8 Data; - int i; - - if (!info->fax->bor) { - for (i = 0; i < skb->len; i++) { - Data = skb->data[i]; - for ( - LeftMask = 0x80, RightMask = 0x01; - LeftMask > RightMask; - LeftMask >>= 1, RightMask <<= 1 - ) { - fBit = (Data & LeftMask); - if (Data & RightMask) - Data |= LeftMask; - else - Data &= ~LeftMask; - if (fBit) - Data |= RightMask; - else - Data &= ~RightMask; - - } - skb->data[i] = Data; - } - } -} - -/* - * Parse AT+F.. FAX class 1 commands - */ - -static int -isdn_tty_cmd_FCLASS1(char **p, modem_info *info) -{ - static char *cmd[] = - {"AE", "TS", "RS", "TM", "RM", "TH", "RH"}; - isdn_ctrl c; - int par, i; - u_long flags; - - for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) - if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) - break; - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd); -#endif - if (c.parm.aux.cmd == 7) - PARSE_ERROR1; - - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - c.parm.aux.subcmd = AT_QUERY; - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - c.parm.aux.subcmd = AT_EQ_QUERY; - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - c.parm.aux.subcmd = AT_EQ_VALUE; - c.parm.aux.para[0] = par; - } - break; - case 0: - c.parm.aux.subcmd = AT_COMMAND; - break; - default: - PARSE_ERROR1; - } - c.command = ISDN_CMD_FAXCMD; -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n", - c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]); -#endif - if (info->isdn_driver < 0) { - if ((c.parm.aux.subcmd == AT_EQ_VALUE) || - (c.parm.aux.subcmd == AT_COMMAND)) { - PARSE_ERROR1; - } - spin_lock_irqsave(&dev->lock, flags); - /* get a temporary connection to the first free fax driver */ - i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX, - ISDN_PROTO_L3_FCLASS1, -1, -1, "00"); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - PARSE_ERROR1; - } - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - spin_unlock_irqrestore(&dev->lock, flags); - c.driver = info->isdn_driver; - c.arg = info->isdn_channel; - isdn_command(&c); - spin_lock_irqsave(&dev->lock, flags); - isdn_free_channel(info->isdn_driver, info->isdn_channel, - ISDN_USAGE_FAX); - info->isdn_driver = -1; - info->isdn_channel = -1; - if (info->drv_index >= 0) { - dev->m_idx[info->drv_index] = -1; - info->drv_index = -1; - } - spin_unlock_irqrestore(&dev->lock, flags); - } else { - c.driver = info->isdn_driver; - c.arg = info->isdn_channel; - isdn_command(&c); - } - return 1; -} - -/* - * Parse AT+F.. FAX class 2 commands - */ - -static int -isdn_tty_cmd_FCLASS2(char **p, modem_info *info) -{ - atemu *m = &info->emu; - T30_s *f = info->fax; - isdn_ctrl cmd; - int par; - char rs[50]; - char rss[50]; - int maxdccval[] = - {1, 5, 2, 2, 3, 2, 0, 7}; - - /* FAA still unchanged */ - if (!strncmp(p[0], "AA", 2)) { /* TODO */ - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", 0); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */ - if (!strncmp(p[0], "BADLIN", 6)) { - p[0] += 6; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->badlin); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->badlin = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */ - if (!strncmp(p[0], "BADMUL", 6)) { - p[0] += 6; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->badmul); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->badmul = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BOR=n - Phase C bit order, 0=direct, 1=reverse */ - if (!strncmp(p[0], "BOR", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->bor); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->bor = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* NBC=n - No Best Capabilities */ - if (!strncmp(p[0], "NBC", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->nbc); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->nbc = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BUF? - Readonly buffersize readout */ - if (!strncmp(p[0], "BUF?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE])); -#endif - p[0]++; - sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE])); - isdn_tty_at_cout(rs, info); - return 0; - } - /* CIG=string - local fax station id string for polling rx */ - if (!strncmp(p[0], "CIG", 3)) { - int i, r; - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n\"%s\"", f->pollid); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n\"STRING\""); - isdn_tty_at_cout(rs, info); - } else { - if (*p[0] == '"') - p[0]++; - for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) { - f->pollid[i] = *p[0]++; - } - if (*p[0] == '"') - p[0]++; - for (r = i; r < FAXIDLEN; r++) { - f->pollid[r] = 32; - } - f->pollid[FAXIDLEN - 1] = 0; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */ - if (!strncmp(p[0], "CQ", 2)) { - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->cq); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1,2"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 2)) - PARSE_ERROR1; - f->cq = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */ - if (!strncmp(p[0], "CR", 2)) { - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */ - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); /* display online help */ - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->cr = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* CTCRTY=value - ECM retry count */ - if (!strncmp(p[0], "CTCRTY", 6)) { - p[0] += 6; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->ctcrty); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->ctcrty = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */ - if (!strncmp(p[0], "DCC", 3)) { - char *rp = &f->resolution; - int i; - - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - strcpy(rs, "\r\n"); - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info); - p[0]++; - } else { - for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) { - if (*p[0] != ',') { - if ((*p[0] - 48) > maxdccval[i]) { - PARSE_ERROR1; - } - rp[i] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } else - p[0]++; - } -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n", - rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */ - if (!strncmp(p[0], "DIS", 3)) { - char *rp = &f->resolution; - int i; - - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - strcpy(rs, "\r\n"); - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info); - p[0]++; - } else { - for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) { - if (*p[0] != ',') { - if ((*p[0] - 48) > maxdccval[i]) { - PARSE_ERROR1; - } - rp[i] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } else - p[0]++; - } -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n", - rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* DR - Receive Phase C data command, initiates document reception */ - if (!strncmp(p[0], "DR", 2)) { - p[0] += 2; - if ((info->faxonline & 16) && /* incoming connection */ - ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) { -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDR\n"); -#endif - f->code = ISDN_TTY_FAX_DR; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_FAXCMD; - isdn_command(&cmd); - if (f->phase == ISDN_FAX_PHASE_B) { - f->phase = ISDN_FAX_PHASE_C; - } else if (f->phase == ISDN_FAX_PHASE_D) { - switch (f->fet) { - case 0: /* next page will be received */ - f->phase = ISDN_FAX_PHASE_C; - isdn_tty_fax_modem_result(7, info); /* CONNECT */ - break; - case 1: /* next doc will be received */ - f->phase = ISDN_FAX_PHASE_B; - break; - case 2: /* fax session is terminating */ - f->phase = ISDN_FAX_PHASE_E; - break; - default: - PARSE_ERROR1; - } - } - } else { - PARSE_ERROR1; - } - return 1; - } - /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */ - if (!strncmp(p[0], "DT", 2)) { - int i, val[] = - {4, 0, 2, 3}; - char *rp = &f->resolution; - - p[0] += 2; - if (!(info->faxonline & 1)) /* not outgoing connection */ - PARSE_ERROR1; - - for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) { - if (*p[0] != ',') { - if ((*p[0] - 48) > maxdccval[val[i]]) { - PARSE_ERROR1; - } - rp[val[i]] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } else - p[0]++; - } -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n", - rp[4], rp[0], rp[2], rp[3]); -#endif - if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) { - f->code = ISDN_TTY_FAX_DT; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_FAXCMD; - isdn_command(&cmd); - if (f->phase == ISDN_FAX_PHASE_D) { - f->phase = ISDN_FAX_PHASE_C; - isdn_tty_fax_modem_result(7, info); /* CONNECT */ - } - } else { - PARSE_ERROR1; - } - return 1; - } - /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */ - if (!strncmp(p[0], "ECM", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->ecm); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,2"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par != 0) && (par != 2)) - PARSE_ERROR1; - f->ecm = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* ET=n - End of page or document */ - if (!strncmp(p[0], "ET=", 3)) { - p[0] += 3; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-2"); - isdn_tty_at_cout(rs, info); - } else { - if ((f->phase != ISDN_FAX_PHASE_D) || - (!(info->faxonline & 1))) - PARSE_ERROR1; - par = isdn_getnum(p); - if ((par < 0) || (par > 2)) - PARSE_ERROR1; - f->fet = par; - f->code = ISDN_TTY_FAX_ET; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_FAXCMD; - isdn_command(&cmd); -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par); -#endif - return 1; - } - return 0; - } - /* K - terminate */ - if (!strncmp(p[0], "K", 1)) { - p[0] += 1; - if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E)) - PARSE_ERROR1; - isdn_tty_modem_hup(info, 1); - return 1; - } - /* LID=string - local fax ID */ - if (!strncmp(p[0], "LID", 3)) { - int i, r; - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n\"%s\"", f->id); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n\"STRING\""); - isdn_tty_at_cout(rs, info); - } else { - if (*p[0] == '"') - p[0]++; - for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) { - f->id[i] = *p[0]++; - } - if (*p[0] == '"') - p[0]++; - for (r = i; r < FAXIDLEN; r++) { - f->id[r] = 32; - } - f->id[FAXIDLEN - 1] = 0; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - - /* MDL? - DCE Model */ - if (!strncmp(p[0], "MDL?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FMDL?\n"); -#endif - isdn_tty_at_cout("\r\nisdn4linux", info); - return 0; - } - /* MFR? - DCE Manufacturer */ - if (!strncmp(p[0], "MFR?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FMFR?\n"); -#endif - isdn_tty_at_cout("\r\nisdn4linux", info); - return 0; - } - /* MINSP=n - Minimum Speed for Phase C */ - if (!strncmp(p[0], "MINSP", 5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->minsp); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-5"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 5)) - PARSE_ERROR1; - f->minsp = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* PHCTO=value - DTE phase C timeout */ - if (!strncmp(p[0], "PHCTO", 5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->phcto); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->phcto = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - - /* REL=n - Phase C received EOL alignment */ - if (!strncmp(p[0], "REL", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->rel); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->rel = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* REV? - DCE Revision */ - if (!strncmp(p[0], "REV?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FREV?\n"); -#endif - strcpy(rss, isdn_tty_fax_revision); - sprintf(rs, "\r\nRev: %s", isdn_getrev(rss)); - isdn_tty_at_cout(rs, info); - return 0; - } - - /* Phase C Transmit Data Block Size */ - if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */ - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]); -#endif - switch (*p[0]) { - case '0': - p[0]++; - break; - default: - PARSE_ERROR1; - } - return 0; - } - printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]); - PARSE_ERROR1; -} - -int -isdn_tty_cmd_PLUSF_FAX(char **p, modem_info *info) -{ - if (TTY_IS_FCLASS2(info)) - return (isdn_tty_cmd_FCLASS2(p, info)); - else if (TTY_IS_FCLASS1(info)) - return (isdn_tty_cmd_FCLASS1(p, info)); - PARSE_ERROR1; -} diff --git a/drivers/isdn/i4l/isdn_ttyfax.h b/drivers/isdn/i4l/isdn_ttyfax.h deleted file mode 100644 index ccda4fcf8f7b..000000000000 --- a/drivers/isdn/i4l/isdn_ttyfax.h +++ /dev/null @@ -1,17 +0,0 @@ -/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, tty_fax related functions (linklevel). - * - * Copyright 1999 by Armin Schindler (mac@melware.de) - * Copyright 1999 by Ralf Spachmann (mel@melware.de) - * Copyright 1999 by Cytronics & Melware - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#define XON 0x11 -#define XOFF 0x13 -#define DC2 0x12 diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c deleted file mode 100644 index d11fe76f138f..000000000000 --- a/drivers/isdn/i4l/isdn_v110.c +++ /dev/null @@ -1,625 +0,0 @@ -/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, V.110 related functions (linklevel). - * - * Copyright by Thomas Pfeiffer (pfeiffer@pds.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include - -#include -#include "isdn_v110.h" - -#undef ISDN_V110_DEBUG - -char *isdn_v110_revision = "$Revision: 1.1.2.2 $"; - -#define V110_38400 255 -#define V110_19200 15 -#define V110_9600 3 - -/* - * The following data are precoded matrices, online and offline matrix - * for 9600, 19200 und 38400, respectively - */ -static unsigned char V110_OnMatrix_9600[] = -{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd}; - -static unsigned char V110_OffMatrix_9600[] = -{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static unsigned char V110_OnMatrix_19200[] = -{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, - 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7}; - -static unsigned char V110_OffMatrix_19200[] = -{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static unsigned char V110_OnMatrix_38400[] = -{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f}; - -static unsigned char V110_OffMatrix_38400[] = -{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff}; - -/* - * FlipBits reorders sequences of keylen bits in one byte. - * E.g. source order 7654321 will be converted to 45670123 when keylen = 4, - * and to 67452301 when keylen = 2. This is necessary because ordering on - * the isdn line is the other way. - */ -static inline unsigned char -FlipBits(unsigned char c, int keylen) -{ - unsigned char b = c; - unsigned char bit = 128; - int i; - int j; - int hunks = (8 / keylen); - - c = 0; - for (i = 0; i < hunks; i++) { - for (j = 0; j < keylen; j++) { - if (b & (bit >> j)) - c |= bit >> (keylen - j - 1); - } - bit >>= keylen; - } - return c; -} - - -/* isdn_v110_open allocates and initializes private V.110 data - * structures and returns a pointer to these. - */ -static isdn_v110_stream * -isdn_v110_open(unsigned char key, int hdrlen, int maxsize) -{ - int i; - isdn_v110_stream *v; - - if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL) - return NULL; - v->key = key; - v->nbits = 0; - for (i = 0; key & (1 << i); i++) - v->nbits++; - - v->nbytes = 8 / v->nbits; - v->decodelen = 0; - - switch (key) { - case V110_38400: - v->OnlineFrame = V110_OnMatrix_38400; - v->OfflineFrame = V110_OffMatrix_38400; - break; - case V110_19200: - v->OnlineFrame = V110_OnMatrix_19200; - v->OfflineFrame = V110_OffMatrix_19200; - break; - default: - v->OnlineFrame = V110_OnMatrix_9600; - v->OfflineFrame = V110_OffMatrix_9600; - break; - } - v->framelen = v->nbytes * 10; - v->SyncInit = 5; - v->introducer = 0; - v->dbit = 1; - v->b = 0; - v->skbres = hdrlen; - v->maxsize = maxsize - hdrlen; - if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) { - kfree(v); - return NULL; - } - return v; -} - -/* isdn_v110_close frees private V.110 data structures */ -void -isdn_v110_close(isdn_v110_stream *v) -{ - if (v == NULL) - return; -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "v110 close\n"); -#endif - kfree(v->encodebuf); - kfree(v); -} - - -/* - * ValidHeaderBytes return the number of valid bytes in v->decodebuf - */ -static int -ValidHeaderBytes(isdn_v110_stream *v) -{ - int i; - for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++) - if ((v->decodebuf[i] & v->key) != 0) - break; - return i; -} - -/* - * SyncHeader moves the decodebuf ptr to the next valid header - */ -static void -SyncHeader(isdn_v110_stream *v) -{ - unsigned char *rbuf = v->decodebuf; - int len = v->decodelen; - - if (len == 0) - return; - for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */ - if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */ - break; /* jupp! */ - if (len) - memcpy(v->decodebuf, rbuf, len); - - v->decodelen = len; -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "isdn_v110: Header resync\n"); -#endif -} - -/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where - len is the number of matrix-lines. len must be a multiple of 10, i.e. - only complete matices must be given. - From these, netto data is extracted and returned in buf. The return-value - is the bytecount of the decoded data. -*/ -static int -DecodeMatrix(isdn_v110_stream *v, unsigned char *m, int len, unsigned char *buf) -{ - int line = 0; - int buflen = 0; - int mbit = 64; - int introducer = v->introducer; - int dbit = v->dbit; - unsigned char b = v->b; - - while (line < len) { /* Are we done with all lines of the matrix? */ - if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */ - if (m[line] != 0x00) { /* not 0 ? -> error! */ -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n"); - /* returning now is not the right thing, though :-( */ -#endif - } - line++; /* next line of matrix */ - continue; - } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */ - if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */ -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n"); - /* returning now is not the right thing, though :-( */ -#endif - } - line++; /* next line */ - continue; - } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */ - introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */ - next_byte: - if (mbit > 2) { /* was it the last bit in this line ? */ - mbit >>= 1; /* no -> take next */ - continue; - } /* otherwise start with leftmost bit in the next line */ - mbit = 64; - line++; - continue; - } else { /* otherwise we need to set a data bit */ - if (m[line] & mbit) /* was that bit set in the matrix ? */ - b |= dbit; /* yes -> set it in the data byte */ - else - b &= dbit - 1; /* no -> clear it in the data byte */ - if (dbit < 128) /* is that data byte done ? */ - dbit <<= 1; /* no, got the next bit */ - else { /* data byte is done */ - buf[buflen++] = b; /* copy byte into the output buffer */ - introducer = b = 0; /* init of the intro sequence and of the data byte */ - dbit = 1; /* next we look for the 0th bit */ - } - goto next_byte; /* look for next bit in the matrix */ - } - } - v->introducer = introducer; - v->dbit = dbit; - v->b = b; - return buflen; /* return number of bytes in the output buffer */ -} - -/* - * DecodeStream receives V.110 coded data from the input stream. It recovers the - * original frames. - * The input stream doesn't need to be framed - */ -struct sk_buff * -isdn_v110_decode(isdn_v110_stream *v, struct sk_buff *skb) -{ - int i; - int j; - int len; - unsigned char *v110_buf; - unsigned char *rbuf; - - if (!skb) { - printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n"); - return NULL; - } - rbuf = skb->data; - len = skb->len; - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n"); - dev_kfree_skb(skb); - return NULL; - } - if (v->decodelen == 0) /* cache empty? */ - for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */ - if ((*rbuf & v->key) == 0) - break; /* found first byte */ - if (len == 0) { - dev_kfree_skb(skb); - return NULL; - } - /* copy new data to decode-buffer */ - memcpy(&(v->decodebuf[v->decodelen]), rbuf, len); - v->decodelen += len; -ReSync: - if (v->decodelen < v->nbytes) { /* got a new header ? */ - dev_kfree_skb(skb); - return NULL; /* no, try later */ - } - if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */ - SyncHeader(v); /* no -> look for header */ - goto ReSync; - } - len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes; - if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) { - printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n"); - dev_kfree_skb(skb); - return NULL; - } - for (i = 0; i < len; i++) { - v110_buf[i] = 0; - for (j = 0; j < v->nbytes; j++) - v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits)); - v110_buf[i] = FlipBits(v110_buf[i], v->nbits); - } - v->decodelen = (v->decodelen % (10 * v->nbytes)); - memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen); - - skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data)); - kfree(v110_buf); - if (skb->len) - return skb; - else { - kfree_skb(skb); - return NULL; - } -} - -/* EncodeMatrix takes input data in buf, len is the bytecount. - Data is encoded into v110 frames in m. Return value is the number of - matrix-lines generated. -*/ -static int -EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen) -{ - int line = 0; - int i = 0; - int mbit = 128; - int dbit = 1; - int introducer = 3; - int ibit[] = {0, 1, 1}; - - while ((i < len) && (line < mlen)) { /* while we still have input data */ - switch (line % 10) { /* in which line of the matrix are we? */ - case 0: - m[line++] = 0x00; /* line 0 is always 0 */ - mbit = 128; /* go on with the 7th bit */ - break; - case 5: - m[line++] = 0xbf; /* line 5 is always 10111111 */ - mbit = 128; /* go on with the 7th bit */ - break; - } - if (line >= mlen) { - printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n"); - return line; - } - next_bit: - switch (mbit) { /* leftmost or rightmost bit ? */ - case 1: - line++; /* rightmost -> go to next line */ - if (line >= mlen) { - printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n"); - return line; - } - /* fall through */ - case 128: - m[line] = 128; /* leftmost -> set byte to 1000000 */ - mbit = 64; /* current bit in the matrix line */ - continue; - } - if (introducer) { /* set 110 sequence ? */ - introducer--; /* set on digit less */ - m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */ - mbit >>= 1; /* bit of matrix line >> 1 */ - goto next_bit; /* and go on there */ - } /* else push data bits into the matrix! */ - m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */ - if (dbit == 128) { /* was it the last one? */ - dbit = 1; /* then go on with first bit of */ - i++; /* next byte in input buffer */ - if (i < len) /* input buffer done ? */ - introducer = 3; /* no, write introducer 110 */ - else { /* input buffer done ! */ - m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */ - break; - } - } else /* not the last data bit */ - dbit <<= 1; /* then go to next data bit */ - mbit >>= 1; /* go to next bit of matrix */ - goto next_bit; - - } - /* if necessary, generate remaining lines of the matrix... */ - if ((line) && ((line + 10) < mlen)) - switch (++line % 10) { - case 1: - m[line++] = 0xfe; - /* fall through */ - case 2: - m[line++] = 0xfe; - /* fall through */ - case 3: - m[line++] = 0xfe; - /* fall through */ - case 4: - m[line++] = 0xfe; - /* fall through */ - case 5: - m[line++] = 0xbf; - /* fall through */ - case 6: - m[line++] = 0xfe; - /* fall through */ - case 7: - m[line++] = 0xfe; - /* fall through */ - case 8: - m[line++] = 0xfe; - /* fall through */ - case 9: - m[line++] = 0xfe; - } - return line; /* that's how many lines we have */ -} - -/* - * Build a sync frame. - */ -static struct sk_buff * -isdn_v110_sync(isdn_v110_stream *v) -{ - struct sk_buff *skb; - - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n"); - return NULL; - } - if ((skb = dev_alloc_skb(v->framelen + v->skbres))) { - skb_reserve(skb, v->skbres); - skb_put_data(skb, v->OfflineFrame, v->framelen); - } - return skb; -} - -/* - * Build an idle frame. - */ -static struct sk_buff * -isdn_v110_idle(isdn_v110_stream *v) -{ - struct sk_buff *skb; - - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n"); - return NULL; - } - if ((skb = dev_alloc_skb(v->framelen + v->skbres))) { - skb_reserve(skb, v->skbres); - skb_put_data(skb, v->OnlineFrame, v->framelen); - } - return skb; -} - -struct sk_buff * -isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb) -{ - int i; - int j; - int rlen; - int mlen; - int olen; - int size; - int sval1; - int sval2; - int nframes; - unsigned char *v110buf; - unsigned char *rbuf; - struct sk_buff *nskb; - - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n"); - return NULL; - } - if (!skb) { - /* invalid skb, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n"); - return NULL; - } - rlen = skb->len; - nframes = (rlen + 3) / 4; - v110buf = v->encodebuf; - if ((nframes * 40) > v->maxsize) { - size = v->maxsize; - rlen = v->maxsize / 40; - } else - size = nframes * 40; - if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) { - printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n"); - return NULL; - } - skb_reserve(nskb, v->skbres + sizeof(int)); - if (skb->len == 0) { - skb_put_data(nskb, v->OnlineFrame, v->framelen); - *((int *)skb_push(nskb, sizeof(int))) = 0; - return nskb; - } - mlen = EncodeMatrix(skb->data, rlen, v110buf, size); - /* now distribute 2 or 4 bits each to the output stream! */ - rbuf = skb_put(nskb, size); - olen = 0; - sval1 = 8 - v->nbits; - sval2 = v->key << sval1; - for (i = 0; i < mlen; i++) { - v110buf[i] = FlipBits(v110buf[i], v->nbits); - for (j = 0; j < v->nbytes; j++) { - if (size--) - *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1); - else { - printk(KERN_WARNING "isdn_v110_encode: buffers full!\n"); - goto buffer_full; - } - olen++; - } - } -buffer_full: - skb_trim(nskb, olen); - *((int *)skb_push(nskb, sizeof(int))) = rlen; - return nskb; -} - -int -isdn_v110_stat_callback(int idx, isdn_ctrl *c) -{ - isdn_v110_stream *v = NULL; - int i; - int ret = 0; - - if (idx < 0) - return 0; - switch (c->command) { - case ISDN_STAT_BSENT: - /* Keep the send-queue of the driver filled - * with frames: - * If number of outstanding frames < 3, - * send down an Idle-Frame (or an Sync-Frame, if - * v->SyncInit != 0). - */ - if (!(v = dev->v110[idx])) - return 0; - atomic_inc(&dev->v110use[idx]); - for (i = 0; i * v->framelen < c->parm.length; i++) { - if (v->skbidle > 0) { - v->skbidle--; - ret = 1; - } else { - if (v->skbuser > 0) - v->skbuser--; - ret = 0; - } - } - for (i = v->skbuser + v->skbidle; i < 2; i++) { - struct sk_buff *skb; - if (v->SyncInit > 0) - skb = isdn_v110_sync(v); - else - skb = isdn_v110_idle(v); - if (skb) { - if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) { - dev_kfree_skb(skb); - break; - } else { - if (v->SyncInit) - v->SyncInit--; - v->skbidle++; - } - } else - break; - } - atomic_dec(&dev->v110use[idx]); - return ret; - case ISDN_STAT_DHUP: - case ISDN_STAT_BHUP: - while (1) { - atomic_inc(&dev->v110use[idx]); - if (atomic_dec_and_test(&dev->v110use[idx])) { - isdn_v110_close(dev->v110[idx]); - dev->v110[idx] = NULL; - break; - } - mdelay(1); - } - break; - case ISDN_STAT_BCONN: - if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) { - int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen; - int maxsize = dev->drv[c->driver]->interface->maxbufsize; - atomic_inc(&dev->v110use[idx]); - switch (dev->v110emu[idx]) { - case ISDN_PROTO_L2_V11096: - dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize); - break; - case ISDN_PROTO_L2_V11019: - dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize); - break; - case ISDN_PROTO_L2_V11038: - dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize); - break; - default:; - } - if ((v = dev->v110[idx])) { - while (v->SyncInit) { - struct sk_buff *skb = isdn_v110_sync(v); - if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) { - dev_kfree_skb(skb); - /* Unable to send, try later */ - break; - } - v->SyncInit--; - v->skbidle++; - } - } else - printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx); - atomic_dec(&dev->v110use[idx]); - } - break; - default: - return 0; - } - return 0; -} diff --git a/drivers/isdn/i4l/isdn_v110.h b/drivers/isdn/i4l/isdn_v110.h deleted file mode 100644 index de774ab598c9..000000000000 --- a/drivers/isdn/i4l/isdn_v110.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, V.110 related functions (linklevel). - * - * Copyright by Thomas Pfeiffer (pfeiffer@pds.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _isdn_v110_h_ -#define _isdn_v110_h_ - -/* - * isdn_v110_encode will take raw data and encode it using V.110 - */ -extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *); - -/* - * isdn_v110_decode receives V.110 coded data from the stream and rebuilds - * frames from them. The source stream doesn't need to be framed. - */ -extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *); - -extern int isdn_v110_stat_callback(int, isdn_ctrl *); -extern void isdn_v110_close(isdn_v110_stream *v); - -#endif diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c deleted file mode 100644 index 48bfbcb4a09d..000000000000 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ /dev/null @@ -1,332 +0,0 @@ -/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, X.25 related functions - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * stuff needed to support the Linux X.25 PLP code on top of devices that - * can provide a lab_b service using the concap_proto mechanism. - * This module supports a network interface which provides lapb_sematics - * -- as defined in Documentation/networking/x25-iface.txt -- to - * the upper layer and assumes that the lower layer provides a reliable - * data link service by means of the concap_device_ops callbacks. - * - * Only protocol specific stuff goes here. Device specific stuff - * goes to another -- device related -- concap_proto support source file. - * - */ - -/* #include */ -#include -#include -#include -#include -#include -#include "isdn_x25iface.h" - -/* for debugging messages not to cause an oops when device pointer is NULL*/ -#define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED") - - -typedef struct isdn_x25iface_proto_data { - int magic; - enum wan_states state; - /* Private stuff, not to be accessed via proto_data. We provide the - other storage for the concap_proto instance here as well, - enabling us to allocate both with just one kmalloc(): */ - struct concap_proto priv; -} ix25_pdata_t; - - - -/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */ -static void isdn_x25iface_proto_del(struct concap_proto *); -static int isdn_x25iface_proto_close(struct concap_proto *); -static int isdn_x25iface_proto_restart(struct concap_proto *, - struct net_device *, - struct concap_device_ops *); -static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *); -static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *); -static int isdn_x25iface_connect_ind(struct concap_proto *); -static int isdn_x25iface_disconn_ind(struct concap_proto *); - - -static struct concap_proto_ops ix25_pops = { - .proto_new = &isdn_x25iface_proto_new, - .proto_del = &isdn_x25iface_proto_del, - .restart = &isdn_x25iface_proto_restart, - .close = &isdn_x25iface_proto_close, - .encap_and_xmit = &isdn_x25iface_xmit, - .data_ind = &isdn_x25iface_receive, - .connect_ind = &isdn_x25iface_connect_ind, - .disconn_ind = &isdn_x25iface_disconn_ind -}; - -/* error message helper function */ -static void illegal_state_warn(unsigned state, unsigned char firstbyte) -{ - printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in" - "current state %d\n", firstbyte, state); -} - -/* check protocol data field for consistency */ -static int pdata_is_bad(ix25_pdata_t *pda) { - - if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0; - printk(KERN_WARNING - "isdn_x25iface_xxx: illegal pointer to proto data\n"); - return 1; -} - -/* create a new x25 interface protocol instance - */ -struct concap_proto *isdn_x25iface_proto_new(void) -{ - ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL); - IX25DEBUG("isdn_x25iface_proto_new\n"); - if (tmp) { - tmp->magic = ISDN_X25IFACE_MAGIC; - tmp->state = WAN_UNCONFIGURED; - /* private data space used to hold the concap_proto data. - Only to be accessed via the returned pointer */ - spin_lock_init(&tmp->priv.lock); - tmp->priv.dops = NULL; - tmp->priv.net_dev = NULL; - tmp->priv.pops = &ix25_pops; - tmp->priv.flags = 0; - tmp->priv.proto_data = tmp; - return (&(tmp->priv)); - } - return NULL; -}; - -/* close the x25iface encapsulation protocol - */ -static int isdn_x25iface_proto_close(struct concap_proto *cprot) { - - ix25_pdata_t *tmp; - int ret = 0; - ulong flags; - - if (!cprot) { - printk(KERN_ERR "isdn_x25iface_proto_close: " - "invalid concap_proto pointer\n"); - return -1; - } - IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev)); - spin_lock_irqsave(&cprot->lock, flags); - cprot->dops = NULL; - cprot->net_dev = NULL; - tmp = cprot->proto_data; - if (pdata_is_bad(tmp)) { - ret = -1; - } else { - tmp->state = WAN_UNCONFIGURED; - } - spin_unlock_irqrestore(&cprot->lock, flags); - return ret; -} - -/* Delete the x25iface encapsulation protocol instance - */ -static void isdn_x25iface_proto_del(struct concap_proto *cprot) { - - ix25_pdata_t *tmp; - - IX25DEBUG("isdn_x25iface_proto_del \n"); - if (!cprot) { - printk(KERN_ERR "isdn_x25iface_proto_del: " - "concap_proto pointer is NULL\n"); - return; - } - tmp = cprot->proto_data; - if (tmp == NULL) { - printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent " - "proto_data pointer (maybe already deleted?)\n"); - return; - } - /* close if the protocol is still open */ - if (cprot->dops) isdn_x25iface_proto_close(cprot); - /* freeing the storage should be sufficient now. But some additional - settings might help to catch wild pointer bugs */ - tmp->magic = 0; - cprot->proto_data = NULL; - - kfree(tmp); - return; -} - -/* (re-)initialize the data structures for x25iface encapsulation - */ -static int isdn_x25iface_proto_restart(struct concap_proto *cprot, - struct net_device *ndev, - struct concap_device_ops *dops) -{ - ix25_pdata_t *pda = cprot->proto_data; - ulong flags; - - IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev)); - - if (pdata_is_bad(pda)) return -1; - - if (!(dops && dops->data_req && dops->connect_req - && dops->disconn_req)) { - printk(KERN_WARNING "isdn_x25iface_restart: required dops" - " missing\n"); - isdn_x25iface_proto_close(cprot); - return -1; - } - spin_lock_irqsave(&cprot->lock, flags); - cprot->net_dev = ndev; - cprot->pops = &ix25_pops; - cprot->dops = dops; - pda->state = WAN_DISCONNECTED; - spin_unlock_irqrestore(&cprot->lock, flags); - return 0; -} - -/* deliver a dl_data frame received from i4l HL driver to the network layer - */ -static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb) -{ - IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev)); - if (((ix25_pdata_t *)(cprot->proto_data)) - ->state == WAN_CONNECTED) { - if (skb_push(skb, 1)) { - skb->data[0] = X25_IFACE_DATA; - skb->protocol = x25_type_trans(skb, cprot->net_dev); - netif_rx(skb); - return 0; - } - } - printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev)); - dev_kfree_skb(skb); - return -1; -} - -/* a connection set up is indicated by lower layer - */ -static int isdn_x25iface_connect_ind(struct concap_proto *cprot) -{ - struct sk_buff *skb; - enum wan_states *state_p - = &(((ix25_pdata_t *)(cprot->proto_data))->state); - IX25DEBUG("isdn_x25iface_connect_ind %s \n" - , MY_DEVNAME(cprot->net_dev)); - if (*state_p == WAN_UNCONFIGURED) { - printk(KERN_WARNING - "isdn_x25iface_connect_ind while unconfigured %s\n" - , MY_DEVNAME(cprot->net_dev)); - return -1; - } - *state_p = WAN_CONNECTED; - - skb = dev_alloc_skb(1); - if (skb) { - skb_put_u8(skb, X25_IFACE_CONNECT); - skb->protocol = x25_type_trans(skb, cprot->net_dev); - netif_rx(skb); - return 0; - } else { - printk(KERN_WARNING "isdn_x25iface_connect_ind: " - " out of memory -- disconnecting\n"); - cprot->dops->disconn_req(cprot); - return -1; - } -} - -/* a disconnect is indicated by lower layer - */ -static int isdn_x25iface_disconn_ind(struct concap_proto *cprot) -{ - struct sk_buff *skb; - enum wan_states *state_p - = &(((ix25_pdata_t *)(cprot->proto_data))->state); - IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev)); - if (*state_p == WAN_UNCONFIGURED) { - printk(KERN_WARNING - "isdn_x25iface_disconn_ind while unconfigured\n"); - return -1; - } - if (!cprot->net_dev) return -1; - *state_p = WAN_DISCONNECTED; - skb = dev_alloc_skb(1); - if (skb) { - skb_put_u8(skb, X25_IFACE_DISCONNECT); - skb->protocol = x25_type_trans(skb, cprot->net_dev); - netif_rx(skb); - return 0; - } else { - printk(KERN_WARNING "isdn_x25iface_disconn_ind:" - " out of memory\n"); - return -1; - } -} - -/* process a frame handed over to us from linux network layer. First byte - semantics as defined in Documentation/networking/x25-iface.txt -*/ -static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb) -{ - unsigned char firstbyte = skb->data[0]; - enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state; - int ret = 0; - IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n", - MY_DEVNAME(cprot->net_dev), firstbyte, *state); - switch (firstbyte) { - case X25_IFACE_DATA: - if (*state == WAN_CONNECTED) { - skb_pull(skb, 1); - netif_trans_update(cprot->net_dev); - ret = (cprot->dops->data_req(cprot, skb)); - /* prepare for future retransmissions */ - if (ret) skb_push(skb, 1); - return ret; - } - illegal_state_warn(*state, firstbyte); - break; - case X25_IFACE_CONNECT: - if (*state == WAN_DISCONNECTED) { - *state = WAN_CONNECTING; - ret = cprot->dops->connect_req(cprot); - if (ret) { - /* reset state and notify upper layer about - * immidiatly failed attempts */ - isdn_x25iface_disconn_ind(cprot); - } - } else { - illegal_state_warn(*state, firstbyte); - } - break; - case X25_IFACE_DISCONNECT: - switch (*state) { - case WAN_DISCONNECTED: - /* Should not happen. However, give upper layer a - chance to recover from inconstistency but don't - trust the lower layer sending the disconn_confirm - when already disconnected */ - printk(KERN_WARNING "isdn_x25iface_xmit: disconnect " - " requested while disconnected\n"); - isdn_x25iface_disconn_ind(cprot); - break; /* prevent infinite loops */ - case WAN_CONNECTING: - case WAN_CONNECTED: - *state = WAN_DISCONNECTED; - cprot->dops->disconn_req(cprot); - break; - default: - illegal_state_warn(*state, firstbyte); - } - break; - case X25_IFACE_PARAMS: - printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb" - " options not yet supported\n"); - break; - default: - printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal" - " first byte %x ignored:\n", firstbyte); - } - dev_kfree_skb(skb); - return 0; -} diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h deleted file mode 100644 index ca08e082cf7c..000000000000 --- a/drivers/isdn/i4l/isdn_x25iface.h +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, x.25 related functions - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _LINUX_ISDN_X25IFACE_H -#define _LINUX_ISDN_X25IFACE_H - -#define ISDN_X25IFACE_MAGIC 0x1e75a2b9 -/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */ -#ifdef DEBUG_ISDN_X25 -# define IX25DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args) -#else -# define IX25DEBUG(fmt, args...) -#endif - -#include -#include -#include - -extern struct concap_proto_ops *isdn_x25iface_concap_proto_ops_pt; -extern struct concap_proto *isdn_x25iface_proto_new(void); - - - -#endif diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile deleted file mode 100644 index 5ff4c0e09768..000000000000 --- a/drivers/isdn/isdnloop/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the isdnloop ISDN device driver - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c deleted file mode 100644 index 755c6bbc9553..000000000000 --- a/drivers/isdn/isdnloop/isdnloop.c +++ /dev/null @@ -1,1528 +0,0 @@ -/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $ - * - * ISDN low-level module implementing a dummy loop driver. - * - * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include "isdnloop.h" - -static char *isdnloop_id = "loop0"; - -MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); -MODULE_AUTHOR("Fritz Elfert"); -MODULE_LICENSE("GPL"); -module_param(isdnloop_id, charp, 0); -MODULE_PARM_DESC(isdnloop_id, "ID-String of first card"); - -static int isdnloop_addcard(char *); - -/* - * Free queue completely. - * - * Parameter: - * card = pointer to card struct - * channel = channel number - */ -static void -isdnloop_free_queue(isdnloop_card *card, int channel) -{ - struct sk_buff_head *queue = &card->bqueue[channel]; - - skb_queue_purge(queue); - card->sndcount[channel] = 0; -} - -/* - * Send B-Channel data to another virtual card. - * This routine is called via timer-callback from isdnloop_pollbchan(). - * - * Parameter: - * card = pointer to card struct. - * ch = channel number (0-based) - */ -static void -isdnloop_bchan_send(isdnloop_card *card, int ch) -{ - isdnloop_card *rcard = card->rcard[ch]; - int rch = card->rch[ch], len, ack; - struct sk_buff *skb; - isdn_ctrl cmd; - - while (card->sndcount[ch]) { - skb = skb_dequeue(&card->bqueue[ch]); - if (skb) { - len = skb->len; - card->sndcount[ch] -= len; - ack = *(skb->head); /* used as scratch area */ - cmd.driver = card->myid; - cmd.arg = ch; - if (rcard) { - rcard->interface.rcvcallb_skb(rcard->myid, rch, skb); - } else { - printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n"); - dev_kfree_skb(skb); - - } - cmd.command = ISDN_STAT_BSENT; - cmd.parm.length = len; - card->interface.statcallb(&cmd); - } else - card->sndcount[ch] = 0; - } -} - -/* - * Send/Receive Data to/from the B-Channel. - * This routine is called via timer-callback. - * It schedules itself while any B-Channel is open. - * - * Parameter: - * data = pointer to card struct, set by kernel timer.data - */ -static void -isdnloop_pollbchan(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, rb_timer); - unsigned long flags; - - if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE) - isdnloop_bchan_send(card, 0); - if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE) - isdnloop_bchan_send(card, 1); - if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) { - /* schedule b-channel polling again */ - spin_lock_irqsave(&card->isdnloop_lock, flags); - card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; - add_timer(&card->rb_timer); - card->flags |= ISDNLOOP_FLAGS_RBTIMER; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - } else - card->flags &= ~ISDNLOOP_FLAGS_RBTIMER; -} - -/* - * Parse ICN-type setup string and fill fields of setup-struct - * with parsed data. - * - * Parameter: - * setup = setup string, format: [caller-id],si1,si2,[called-id] - * cmd = pointer to struct to be filled. - */ -static void -isdnloop_parse_setup(char *setup, isdn_ctrl *cmd) -{ - char *t = setup; - char *s = strchr(t, ','); - - *s++ = '\0'; - strlcpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone)); - s = strchr(t = s, ','); - *s++ = '\0'; - if (!strlen(t)) - cmd->parm.setup.si1 = 0; - else - cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10); - s = strchr(t = s, ','); - *s++ = '\0'; - if (!strlen(t)) - cmd->parm.setup.si2 = 0; - else - cmd->parm.setup.si2 = - simple_strtoul(t, NULL, 10); - strlcpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn)); - cmd->parm.setup.plan = 0; - cmd->parm.setup.screen = 0; -} - -typedef struct isdnloop_stat { - char *statstr; - int command; - int action; -} isdnloop_stat; -/* *INDENT-OFF* */ -static isdnloop_stat isdnloop_stat_table[] = { - {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ - {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ - {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ - {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */ - {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */ - {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */ - {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */ - {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */ - {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */ - {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */ - {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */ - {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ - {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */ - {"E_L1: ACTIVATION FAILED", - ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ - {NULL, 0, -1} -}; -/* *INDENT-ON* */ - - -/* - * Parse Status message-strings from virtual card. - * Depending on status, call statcallb for sending messages to upper - * levels. Also set/reset B-Channel active-flags. - * - * Parameter: - * status = status string to parse. - * channel = channel where message comes from. - * card = card where message comes from. - */ -static void -isdnloop_parse_status(u_char *status, int channel, isdnloop_card *card) -{ - isdnloop_stat *s = isdnloop_stat_table; - int action = -1; - isdn_ctrl cmd; - - while (s->statstr) { - if (!strncmp(status, s->statstr, strlen(s->statstr))) { - cmd.command = s->command; - action = s->action; - break; - } - s++; - } - if (action == -1) - return; - cmd.driver = card->myid; - cmd.arg = channel; - switch (action) { - case 1: - /* BCON_x */ - card->flags |= (channel) ? - ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE; - break; - case 2: - /* BDIS_x */ - card->flags &= ~((channel) ? - ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE); - isdnloop_free_queue(card, channel); - break; - case 3: - /* DCAL_I and DSCA_I */ - isdnloop_parse_setup(status + 6, &cmd); - break; - case 4: - /* FCALL */ - sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid); - sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1); - cmd.parm.setup.si1 = 7; - cmd.parm.setup.si2 = 0; - cmd.parm.setup.plan = 0; - cmd.parm.setup.screen = 0; - break; - case 5: - /* CIF */ - strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num)); - break; - case 6: - /* AOC */ - snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d", - (int) simple_strtoul(status + 7, NULL, 16)); - break; - case 7: - /* CAU */ - status += 3; - if (strlen(status) == 4) - snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c", - status + 2, *status, *(status + 1)); - else - strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num)); - break; - case 8: - /* Misc Errors on L1 and L2 */ - card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE; - isdnloop_free_queue(card, 0); - cmd.arg = 0; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 0; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_BHUP; - card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE; - isdnloop_free_queue(card, 1); - cmd.arg = 1; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 1; - cmd.driver = card->myid; - break; - } - card->interface.statcallb(&cmd); -} - -/* - * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl - * - * Parameter: - * card = pointer to card struct. - * c = char to store. - */ -static void -isdnloop_putmsg(isdnloop_card *card, unsigned char c) -{ - ulong flags; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; - if (card->msg_buf_write == card->msg_buf_read) { - if (++card->msg_buf_read > card->msg_buf_end) - card->msg_buf_read = card->msg_buf; - } - if (card->msg_buf_write > card->msg_buf_end) - card->msg_buf_write = card->msg_buf; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Poll a virtual cards message queue. - * If there are new status-replies from the card, copy them to - * ringbuffer for reading on /dev/isdnctrl and call - * isdnloop_parse_status() for processing them. Watch for special - * Firmware bootmessage and parse it, to get the D-Channel protocol. - * If there are B-Channels open, initiate a timer-callback to - * isdnloop_pollbchan(). - * This routine is called periodically via timer interrupt. - * - * Parameter: - * data = pointer to card struct - */ -static void -isdnloop_polldchan(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, st_timer); - struct sk_buff *skb; - int avail; - int left; - u_char c; - int ch; - unsigned long flags; - u_char *p; - isdn_ctrl cmd; - - skb = skb_dequeue(&card->dqueue); - if (skb) - avail = skb->len; - else - avail = 0; - for (left = avail; left > 0; left--) { - c = *skb->data; - skb_pull(skb, 1); - isdnloop_putmsg(card, c); - card->imsg[card->iptr] = c; - if (card->iptr < 59) - card->iptr++; - if (!skb->len) { - avail++; - isdnloop_putmsg(card, '\n'); - card->imsg[card->iptr] = 0; - card->iptr = 0; - if (card->imsg[0] == '0' && card->imsg[1] >= '0' && - card->imsg[1] <= '2' && card->imsg[2] == ';') { - ch = (card->imsg[1] - '0') - 1; - p = &card->imsg[3]; - isdnloop_parse_status(p, ch, card); - } else { - p = card->imsg; - if (!strncmp(p, "DRV1.", 5)) { - printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p); - if (!strncmp(p + 7, "TC", 2)) { - card->ptype = ISDN_PTYPE_1TR6; - card->interface.features |= ISDN_FEATURE_P_1TR6; - printk(KERN_INFO - "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID); - } - if (!strncmp(p + 7, "EC", 2)) { - card->ptype = ISDN_PTYPE_EURO; - card->interface.features |= ISDN_FEATURE_P_EURO; - printk(KERN_INFO - "isdnloop: (%s) Euro-Protocol loaded and running\n", CID); - } - continue; - - } - } - } - } - if (avail) { - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = avail; - card->interface.statcallb(&cmd); - } - if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) - if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) { - /* schedule b-channel polling */ - card->flags |= ISDNLOOP_FLAGS_RBTIMER; - spin_lock_irqsave(&card->isdnloop_lock, flags); - del_timer(&card->rb_timer); - card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; - add_timer(&card->rb_timer); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - } - /* schedule again */ - spin_lock_irqsave(&card->isdnloop_lock, flags); - card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; - add_timer(&card->st_timer); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Append a packet to the transmit buffer-queue. - * - * Parameter: - * channel = Number of B-channel - * skb = packet to send. - * card = pointer to card-struct - * Return: - * Number of bytes transferred, -E??? on error - */ -static int -isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card *card) -{ - int len = skb->len; - unsigned long flags; - struct sk_buff *nskb; - - if (len > 4000) { - printk(KERN_WARNING - "isdnloop: Send packet too large\n"); - return -EINVAL; - } - if (len) { - if (!(card->flags & (channel ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))) - return 0; - if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE) - return 0; - spin_lock_irqsave(&card->isdnloop_lock, flags); - nskb = dev_alloc_skb(skb->len); - if (nskb) { - skb_copy_from_linear_data(skb, - skb_put(nskb, len), len); - skb_queue_tail(&card->bqueue[channel], nskb); - dev_kfree_skb(skb); - } else - len = 0; - card->sndcount[channel] += len; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - } - return len; -} - -/* - * Read the messages from the card's ringbuffer - * - * Parameter: - * buf = pointer to buffer. - * len = number of bytes to read. - * user = flag, 1: called from userlevel 0: called from kernel. - * card = pointer to card struct. - * Return: - * number of bytes actually transferred. - */ -static int -isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card *card) -{ - int count; - u_char __user *p; - - for (p = buf, count = 0; count < len; p++, count++) { - if (card->msg_buf_read == card->msg_buf_write) - return count; - if (put_user(*card->msg_buf_read++, p)) - return -EFAULT; - if (card->msg_buf_read > card->msg_buf_end) - card->msg_buf_read = card->msg_buf; - } - return count; -} - -/* - * Simulate a card's response by appending it to the cards - * message queue. - * - * Parameter: - * card = pointer to card struct. - * s = pointer to message-string. - * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages. - * Return: - * 0 on success, 1 on memory squeeze. - */ -static int -isdnloop_fake(isdnloop_card *card, char *s, int ch) -{ - struct sk_buff *skb; - int len = strlen(s) + ((ch >= 0) ? 3 : 0); - skb = dev_alloc_skb(len); - if (!skb) { - printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n"); - return 1; - } - if (ch >= 0) - sprintf(skb_put(skb, 3), "%02d;", ch); - skb_put_data(skb, s, strlen(s)); - skb_queue_tail(&card->dqueue, skb); - return 0; -} -/* *INDENT-OFF* */ -static isdnloop_stat isdnloop_cmd_table[] = { - {"BCON_R", 0, 1}, /* B-Channel connect */ - {"BCON_I", 0, 17}, /* B-Channel connect ind */ - {"BDIS_R", 0, 2}, /* B-Channel disconnect */ - {"DDIS_R", 0, 3}, /* D-Channel disconnect */ - {"DCON_R", 0, 16}, /* D-Channel connect */ - {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */ - {"DCAL_R", 0, 5}, /* Dial */ - {"EAZC", 0, 6}, /* Clear EAZ listener */ - {"EAZ", 0, 7}, /* Set EAZ listener */ - {"SEEAZ", 0, 8}, /* Get EAZ listener */ - {"MSN", 0, 9}, /* Set/Clear MSN listener */ - {"MSALL", 0, 10}, /* Set multi MSN listeners */ - {"SETSIL", 0, 11}, /* Set SI list */ - {"SEESIL", 0, 12}, /* Get SI list */ - {"SILC", 0, 13}, /* Clear SI list */ - {"LOCK", 0, -1}, /* LOCK channel */ - {"UNLOCK", 0, -1}, /* UNLOCK channel */ - {"FV2ON", 1, 14}, /* Leased mode on */ - {"FV2OFF", 1, 15}, /* Leased mode off */ - {NULL, 0, -1} -}; -/* *INDENT-ON* */ - - -/* - * Simulate an error-response from a card. - * - * Parameter: - * card = pointer to card struct. - */ -static void -isdnloop_fake_err(isdnloop_card *card) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "E%s", card->omsg); - isdnloop_fake(card, buf, -1); - isdnloop_fake(card, "NAK", -1); -} - -static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12}; -static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a}; - -/* - * Assemble a simplified cause message depending on the - * D-channel protocol used. - * - * Parameter: - * card = pointer to card struct. - * loc = location: 0 = local, 1 = remote. - * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding. - * Return: - * Pointer to buffer containing the assembled message. - */ -static char * -isdnloop_unicause(isdnloop_card *card, int loc, int cau) -{ - static char buf[6]; - - switch (card->ptype) { - case ISDN_PTYPE_EURO: - sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]); - break; - case ISDN_PTYPE_1TR6: - sprintf(buf, "%02X44", ctable_1t[cau]); - break; - default: - return "0000"; - } - return buf; -} - -/* - * Release a virtual connection. Called from timer interrupt, when - * called party did not respond. - * - * Parameter: - * card = pointer to card struct. - * ch = channel (0-based) - */ -static void -isdnloop_atimeout(isdnloop_card *card, int ch) -{ - unsigned long flags; - char buf[60]; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - if (card->rcard[ch]) { - isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1); - card->rcard[ch]->rcard[card->rch[ch]] = NULL; - card->rcard[ch] = NULL; - } - isdnloop_fake(card, "DDIS_I", ch + 1); - /* No user responding */ - sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3)); - isdnloop_fake(card, buf, ch + 1); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Wrapper for isdnloop_atimeout(). - */ -static void -isdnloop_atimeout0(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, c_timer[0]); - - isdnloop_atimeout(card, 0); -} - -/* - * Wrapper for isdnloop_atimeout(). - */ -static void -isdnloop_atimeout1(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, c_timer[1]); - - isdnloop_atimeout(card, 1); -} - -/* - * Install a watchdog for a user, not responding. - * - * Parameter: - * card = pointer to card struct. - * ch = channel to watch for. - */ -static void -isdnloop_start_ctimer(isdnloop_card *card, int ch) -{ - unsigned long flags; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - timer_setup(&card->c_timer[ch], ch ? isdnloop_atimeout1 - : isdnloop_atimeout0, 0); - card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT; - add_timer(&card->c_timer[ch]); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Kill a pending channel watchdog. - * - * Parameter: - * card = pointer to card struct. - * ch = channel (0-based). - */ -static void -isdnloop_kill_ctimer(isdnloop_card *card, int ch) -{ - unsigned long flags; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - del_timer(&card->c_timer[ch]); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0}; -static u_char bit2si[] = {1, 5, 7}; - -/* - * Try finding a listener for an outgoing call. - * - * Parameter: - * card = pointer to calling card. - * p = pointer to ICN-type setup-string. - * lch = channel of calling card. - * cmd = pointer to struct to be filled when parsing setup. - * Return: - * 0 = found match, alerting should happen. - * 1 = found matching number but it is busy. - * 2 = no matching listener. - * 3 = found matching number but SI does not match. - */ -static int -isdnloop_try_call(isdnloop_card *card, char *p, int lch, isdn_ctrl *cmd) -{ - isdnloop_card *cc = cards; - unsigned long flags; - int ch; - int num_match; - int i; - char *e; - char nbuf[32]; - - isdnloop_parse_setup(p, cmd); - while (cc) { - for (ch = 0; ch < 2; ch++) { - /* Exclude ourself */ - if ((cc == card) && (ch == lch)) - continue; - num_match = 0; - switch (cc->ptype) { - case ISDN_PTYPE_EURO: - for (i = 0; i < 3; i++) - if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone))) - num_match = 1; - break; - case ISDN_PTYPE_1TR6: - e = cc->eazlist[ch]; - while (*e) { - sprintf(nbuf, "%s%c", cc->s0num[0], *e); - if (!(strcmp(nbuf, cmd->parm.setup.phone))) - num_match = 1; - e++; - } - } - if (num_match) { - spin_lock_irqsave(&card->isdnloop_lock, flags); - /* channel idle? */ - if (!(cc->rcard[ch])) { - /* Check SI */ - if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return 3; - } - /* ch is idle, si and number matches */ - cc->rcard[ch] = card; - cc->rch[ch] = lch; - card->rcard[lch] = cc; - card->rch[lch] = ch; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return 0; - } else { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - /* num matches, but busy */ - if (ch == 1) - return 1; - } - } - } - cc = cc->next; - } - return 2; -} - -/* - * Depending on D-channel protocol and caller/called, modify - * phone number. - * - * Parameter: - * card = pointer to card struct. - * phone = pointer phone number. - * caller = flag: 1 = caller, 0 = called. - * Return: - * pointer to new phone number. - */ -static char * -isdnloop_vstphone(isdnloop_card *card, char *phone, int caller) -{ - int i; - static char nphone[30]; - - if (!card) { - printk("BUG!!!\n"); - return ""; - } - switch (card->ptype) { - case ISDN_PTYPE_EURO: - if (caller) { - for (i = 0; i < 2; i++) - if (!(strcmp(card->s0num[i], phone))) - return phone; - return card->s0num[0]; - } - return phone; - break; - case ISDN_PTYPE_1TR6: - if (caller) { - sprintf(nphone, "%s%c", card->s0num[0], phone[0]); - return nphone; - } else - return &phone[strlen(phone) - 1]; - break; - } - return ""; -} - -/* - * Parse an ICN-type command string sent to the 'card'. - * Perform misc. actions depending on the command. - * - * Parameter: - * card = pointer to card struct. - */ -static void -isdnloop_parse_cmd(isdnloop_card *card) -{ - char *p = card->omsg; - isdn_ctrl cmd; - char buf[60]; - isdnloop_stat *s = isdnloop_cmd_table; - int action = -1; - int i; - int ch; - - if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) { - isdnloop_fake_err(card); - return; - } - ch = card->omsg[1] - '0'; - if ((ch < 0) || (ch > 2)) { - isdnloop_fake_err(card); - return; - } - p += 3; - while (s->statstr) { - if (!strncmp(p, s->statstr, strlen(s->statstr))) { - action = s->action; - if (s->command && (ch != 0)) { - isdnloop_fake_err(card); - return; - } - break; - } - s++; - } - if (action == -1) - return; - switch (action) { - case 1: - /* 0x;BCON_R */ - if (card->rcard[ch - 1]) { - isdnloop_fake(card->rcard[ch - 1], "BCON_I", - card->rch[ch - 1] + 1); - isdnloop_fake(card, "BCON_C", ch); - } - break; - case 17: - /* 0x;BCON_I */ - if (card->rcard[ch - 1]) { - isdnloop_fake(card->rcard[ch - 1], "BCON_C", - card->rch[ch - 1] + 1); - } - break; - case 2: - /* 0x;BDIS_R */ - isdnloop_fake(card, "BDIS_C", ch); - if (card->rcard[ch - 1]) { - isdnloop_fake(card->rcard[ch - 1], "BDIS_I", - card->rch[ch - 1] + 1); - } - break; - case 16: - /* 0x;DCON_R */ - isdnloop_kill_ctimer(card, ch - 1); - if (card->rcard[ch - 1]) { - isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]); - isdnloop_fake(card->rcard[ch - 1], "DCON_C", - card->rch[ch - 1] + 1); - isdnloop_fake(card, "DCON_C", ch); - } - break; - case 3: - /* 0x;DDIS_R */ - isdnloop_kill_ctimer(card, ch - 1); - if (card->rcard[ch - 1]) { - isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]); - isdnloop_fake(card->rcard[ch - 1], "DDIS_I", - card->rch[ch - 1] + 1); - card->rcard[ch - 1] = NULL; - } - isdnloop_fake(card, "DDIS_C", ch); - break; - case 4: - /* 0x;DSCA_Rdd,yy,zz,oo */ - if (card->ptype != ISDN_PTYPE_1TR6) { - isdnloop_fake_err(card); - return; - } - /* Fall through */ - case 5: - /* 0x;DCAL_Rdd,yy,zz,oo */ - p += 6; - switch (isdnloop_try_call(card, p, ch - 1, &cmd)) { - case 0: - /* Alerting */ - sprintf(buf, "D%s_I%s,%02d,%02d,%s", - (action == 4) ? "SCA" : "CAL", - isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1), - cmd.parm.setup.si1, - cmd.parm.setup.si2, - isdnloop_vstphone(card->rcard[ch - 1], - cmd.parm.setup.phone, 0)); - isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1); - /* Fall through */ - case 3: - /* si1 does not match, don't alert but start timer */ - isdnloop_start_ctimer(card, ch - 1); - break; - case 1: - /* Remote busy */ - isdnloop_fake(card, "DDIS_I", ch); - sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1)); - isdnloop_fake(card, buf, ch); - break; - case 2: - /* No such user */ - isdnloop_fake(card, "DDIS_I", ch); - sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2)); - isdnloop_fake(card, buf, ch); - break; - } - break; - case 6: - /* 0x;EAZC */ - card->eazlist[ch - 1][0] = '\0'; - break; - case 7: - /* 0x;EAZ */ - p += 3; - if (strlen(p) >= sizeof(card->eazlist[0])) - break; - strcpy(card->eazlist[ch - 1], p); - break; - case 8: - /* 0x;SEEAZ */ - sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]); - isdnloop_fake(card, buf, ch + 1); - break; - case 9: - /* 0x;MSN */ - break; - case 10: - /* 0x;MSNALL */ - break; - case 11: - /* 0x;SETSIL */ - p += 6; - i = 0; - while (strchr("0157", *p)) { - if (i) - card->sil[ch - 1] |= si2bit[*p - '0']; - i = (*p++ == '0'); - } - if (*p) - isdnloop_fake_err(card); - break; - case 12: - /* 0x;SEESIL */ - sprintf(buf, "SIN-LIST: "); - p = buf + 10; - for (i = 0; i < 3; i++) - if (card->sil[ch - 1] & (1 << i)) - p += sprintf(p, "%02d", bit2si[i]); - isdnloop_fake(card, buf, ch + 1); - break; - case 13: - /* 0x;SILC */ - card->sil[ch - 1] = 0; - break; - case 14: - /* 00;FV2ON */ - break; - case 15: - /* 00;FV2OFF */ - break; - } -} - -/* - * Put command-strings into the of the 'card'. In reality, execute them - * right in place by calling isdnloop_parse_cmd(). Also copy every - * command to the read message ringbuffer, preceding it with a '>'. - * These mesagges can be read at /dev/isdnctrl. - * - * Parameter: - * buf = pointer to command buffer. - * len = length of buffer data. - * user = flag: 1 = called form userlevel, 0 called from kernel. - * card = pointer to card struct. - * Return: - * number of bytes transferred (currently always equals len). - */ -static int -isdnloop_writecmd(const u_char *buf, int len, int user, isdnloop_card *card) -{ - int xcount = 0; - int ocount = 1; - isdn_ctrl cmd; - - while (len) { - int count = len; - u_char *p; - u_char msg[0x100]; - - if (count > 255) - count = 255; - if (user) { - if (copy_from_user(msg, buf, count)) - return -EFAULT; - } else - memcpy(msg, buf, count); - isdnloop_putmsg(card, '>'); - for (p = msg; count > 0; count--, p++) { - len--; - xcount++; - isdnloop_putmsg(card, *p); - card->omsg[card->optr] = *p; - if (*p == '\n') { - card->omsg[card->optr] = '\0'; - card->optr = 0; - isdnloop_parse_cmd(card); - if (len) { - isdnloop_putmsg(card, '>'); - ocount++; - } - } else { - if (card->optr < 59) - card->optr++; - } - ocount++; - } - } - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = ocount; - card->interface.statcallb(&cmd); - return xcount; -} - -/* - * Delete card's pending timers, send STOP to linklevel - */ -static void -isdnloop_stopcard(isdnloop_card *card) -{ - unsigned long flags; - isdn_ctrl cmd; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - if (card->flags & ISDNLOOP_FLAGS_RUNNING) { - card->flags &= ~ISDNLOOP_FLAGS_RUNNING; - del_timer(&card->st_timer); - del_timer(&card->rb_timer); - del_timer(&card->c_timer[0]); - del_timer(&card->c_timer[1]); - cmd.command = ISDN_STAT_STOP; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - } - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Stop all cards before unload. - */ -static void -isdnloop_stopallcards(void) -{ - isdnloop_card *p = cards; - - while (p) { - isdnloop_stopcard(p); - p = p->next; - } -} - -/* - * Start a 'card'. Simulate card's boot message and set the phone - * number(s) of the virtual 'S0-Interface'. Install D-channel - * poll timer. - * - * Parameter: - * card = pointer to card struct. - * sdefp = pointer to struct holding ioctl parameters. - * Return: - * 0 on success, -E??? otherwise. - */ -static int -isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp) -{ - unsigned long flags; - isdnloop_sdef sdef; - int i; - - if (card->flags & ISDNLOOP_FLAGS_RUNNING) - return -EBUSY; - if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef))) - return -EFAULT; - - for (i = 0; i < 3; i++) { - if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i]))) - return -EINVAL; - } - - spin_lock_irqsave(&card->isdnloop_lock, flags); - switch (sdef.ptype) { - case ISDN_PTYPE_EURO: - if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96", - -1)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - card->sil[0] = card->sil[1] = 4; - if (isdnloop_fake(card, "TEI OK", 0)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - for (i = 0; i < 3; i++) { - strlcpy(card->s0num[i], sdef.num[i], - sizeof(card->s0num[0])); - } - break; - case ISDN_PTYPE_1TR6: - if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95", - -1)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - card->sil[0] = card->sil[1] = 4; - if (isdnloop_fake(card, "TEI OK", 0)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0])); - card->s0num[1][0] = '\0'; - card->s0num[2][0] = '\0'; - break; - default: - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n", - sdef.ptype); - return -EINVAL; - } - timer_setup(&card->rb_timer, isdnloop_pollbchan, 0); - timer_setup(&card->st_timer, isdnloop_polldchan, 0); - card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; - add_timer(&card->st_timer); - card->flags |= ISDNLOOP_FLAGS_RUNNING; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return 0; -} - -/* - * Main handler for commands sent by linklevel. - */ -static int -isdnloop_command(isdn_ctrl *c, isdnloop_card *card) -{ - ulong a; - int i; - char cbuf[80]; - isdn_ctrl cmd; - isdnloop_cdef cdef; - - switch (c->command) { - case ISDN_CMD_IOCTL: - memcpy(&a, c->parm.num, sizeof(ulong)); - switch (c->arg) { - case ISDNLOOP_IOCTL_DEBUGVAR: - return (ulong) card; - case ISDNLOOP_IOCTL_STARTUP: - return isdnloop_start(card, (isdnloop_sdef *) a); - break; - case ISDNLOOP_IOCTL_ADDCARD: - if (copy_from_user((char *)&cdef, - (char *)a, - sizeof(cdef))) - return -EFAULT; - return isdnloop_addcard(cdef.id1); - break; - case ISDNLOOP_IOCTL_LEASEDCFG: - if (a) { - if (!card->leased) { - card->leased = 1; - while (card->ptype == ISDN_PTYPE_UNKNOWN) - schedule_timeout_interruptible(10); - schedule_timeout_interruptible(10); - sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n"); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - printk(KERN_INFO - "isdnloop: (%s) Leased-line mode enabled\n", - CID); - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - } else { - if (card->leased) { - card->leased = 0; - sprintf(cbuf, "00;FV2OFF\n"); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - printk(KERN_INFO - "isdnloop: (%s) Leased-line mode disabled\n", - CID); - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - } - return 0; - default: - return -EINVAL; - } - break; - case ISDN_CMD_DIAL: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (card->leased) - break; - if ((c->arg & 255) < ISDNLOOP_BCH) { - char *p; - char dcode[4]; - - a = c->arg; - p = c->parm.setup.phone; - if (*p == 's' || *p == 'S') { - /* Dial for SPV */ - p++; - strcpy(dcode, "SCA"); - } else - /* Normal Dial */ - strcpy(dcode, "CAL"); - snprintf(cbuf, sizeof(cbuf), - "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), - dcode, p, c->parm.setup.si1, - c->parm.setup.si2, c->parm.setup.eazmsn); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_ACCEPTD: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - cbuf[0] = 0; - switch (card->l2_proto[a - 1]) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) a); - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_PROTO_L2_X25DTE: - sprintf(cbuf, "%02d;BX2T\n", (int) a); - break; - case ISDN_PROTO_L2_X25DCE: - sprintf(cbuf, "%02d;BX2C\n", (int) a); - break; -#endif - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) a); - break; - } - if (strlen(cbuf)) - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - sprintf(cbuf, "%02d;DCON_R\n", (int) a); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_ACCEPTB: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - switch (card->l2_proto[a - 1]) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a); - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_PROTO_L2_X25DTE: - sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a); - break; - case ISDN_PROTO_L2_X25DCE: - sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a); - break; -#endif - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a); - break; - default: - sprintf(cbuf, "%02d;BCON_R\n", (int) a); - } - printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - break; - case ISDN_CMD_HANGUP: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_SETEAZ: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (card->leased) - break; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - if (card->ptype == ISDN_PTYPE_EURO) { - sprintf(cbuf, "%02d;MS%s%s\n", (int) a, - c->parm.num[0] ? "N" : "ALL", c->parm.num); - } else - sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->parm.num[0] ? c->parm.num : (u_char *) "0123456789"); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_CLREAZ: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (card->leased) - break; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - if (card->ptype == ISDN_PTYPE_EURO) - sprintf(cbuf, "%02d;MSNC\n", (int) a); - else - sprintf(cbuf, "%02d;EAZC\n", (int) a); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_SETL2: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if ((c->arg & 255) < ISDNLOOP_BCH) { - a = c->arg; - switch (a >> 8) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_PROTO_L2_X25DTE: - sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1); - break; - case ISDN_PROTO_L2_X25DCE: - sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1); - break; -#endif - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); - break; - case ISDN_PROTO_L2_TRANS: - sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); - break; - default: - return -EINVAL; - } - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - card->l2_proto[a & 255] = (a >> 8); - } - break; - case ISDN_CMD_SETL3: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - return 0; - default: - return -EINVAL; - } - } - return 0; -} - -/* - * Find card with given driverId - */ -static inline isdnloop_card * -isdnloop_findcard(int driverid) -{ - isdnloop_card *p = cards; - - while (p) { - if (p->myid == driverid) - return p; - p = p->next; - } - return (isdnloop_card *) 0; -} - -/* - * Wrapper functions for interface to linklevel - */ -static int -if_command(isdn_ctrl *c) -{ - isdnloop_card *card = isdnloop_findcard(c->driver); - - if (card) - return isdnloop_command(c, card); - printk(KERN_ERR - "isdnloop: if_command called with invalid driverId!\n"); - return -ENODEV; -} - -static int -if_writecmd(const u_char __user *buf, int len, int id, int channel) -{ - isdnloop_card *card = isdnloop_findcard(id); - - if (card) { - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - return isdnloop_writecmd(buf, len, 1, card); - } - printk(KERN_ERR - "isdnloop: if_writecmd called with invalid driverId!\n"); - return -ENODEV; -} - -static int -if_readstatus(u_char __user *buf, int len, int id, int channel) -{ - isdnloop_card *card = isdnloop_findcard(id); - - if (card) { - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - return isdnloop_readstatus(buf, len, card); - } - printk(KERN_ERR - "isdnloop: if_readstatus called with invalid driverId!\n"); - return -ENODEV; -} - -static int -if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) -{ - isdnloop_card *card = isdnloop_findcard(id); - - if (card) { - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - /* ack request stored in skb scratch area */ - *(skb->head) = ack; - return isdnloop_sendbuf(channel, skb, card); - } - printk(KERN_ERR - "isdnloop: if_sendbuf called with invalid driverId!\n"); - return -ENODEV; -} - -/* - * Allocate a new card-struct, initialize it - * link it into cards-list and register it at linklevel. - */ -static isdnloop_card * -isdnloop_initcard(char *id) -{ - isdnloop_card *card; - int i; - card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL); - if (!card) { - printk(KERN_WARNING - "isdnloop: (%s) Could not allocate card-struct.\n", id); - return (isdnloop_card *) 0; - } - card->interface.owner = THIS_MODULE; - card->interface.channels = ISDNLOOP_BCH; - card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/ - card->interface.maxbufsize = 4000; - card->interface.command = if_command; - card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = if_writecmd; - card->interface.readstat = if_readstatus; - card->interface.features = ISDN_FEATURE_L2_X75I | -#ifdef CONFIG_ISDN_X25 - ISDN_FEATURE_L2_X25DTE | - ISDN_FEATURE_L2_X25DCE | -#endif - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN; - card->ptype = ISDN_PTYPE_UNKNOWN; - strlcpy(card->interface.id, id, sizeof(card->interface.id)); - card->msg_buf_write = card->msg_buf; - card->msg_buf_read = card->msg_buf; - card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1]; - for (i = 0; i < ISDNLOOP_BCH; i++) { - card->l2_proto[i] = ISDN_PROTO_L2_X75I; - skb_queue_head_init(&card->bqueue[i]); - } - skb_queue_head_init(&card->dqueue); - spin_lock_init(&card->isdnloop_lock); - card->next = cards; - cards = card; - if (!register_isdn(&card->interface)) { - cards = cards->next; - printk(KERN_WARNING - "isdnloop: Unable to register %s\n", id); - kfree(card); - return (isdnloop_card *) 0; - } - card->myid = card->interface.channels; - return card; -} - -static int -isdnloop_addcard(char *id1) -{ - isdnloop_card *card; - card = isdnloop_initcard(id1); - if (!card) { - return -EIO; - } - printk(KERN_INFO - "isdnloop: (%s) virtual card added\n", - card->interface.id); - return 0; -} - -static int __init -isdnloop_init(void) -{ - if (isdnloop_id) - return isdnloop_addcard(isdnloop_id); - - return 0; -} - -static void __exit -isdnloop_exit(void) -{ - isdn_ctrl cmd; - isdnloop_card *card = cards; - isdnloop_card *last; - int i; - - isdnloop_stopallcards(); - while (card) { - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - for (i = 0; i < ISDNLOOP_BCH; i++) - isdnloop_free_queue(card, i); - card = card->next; - } - card = cards; - while (card) { - last = card; - skb_queue_purge(&card->dqueue); - card = card->next; - kfree(last); - } - printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n"); -} - -module_init(isdnloop_init); -module_exit(isdnloop_exit); diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h deleted file mode 100644 index e9e035552bb4..000000000000 --- a/drivers/isdn/isdnloop/isdnloop.h +++ /dev/null @@ -1,112 +0,0 @@ -/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $ - * - * Loopback lowlevel module for testing of linklevel. - * - * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef isdnloop_h -#define isdnloop_h - -#define ISDNLOOP_IOCTL_DEBUGVAR 0 -#define ISDNLOOP_IOCTL_ADDCARD 1 -#define ISDNLOOP_IOCTL_LEASEDCFG 2 -#define ISDNLOOP_IOCTL_STARTUP 3 - -/* Struct for adding new cards */ -typedef struct isdnloop_cdef { - char id1[10]; -} isdnloop_cdef; - -/* Struct for configuring cards */ -typedef struct isdnloop_sdef { - int ptype; - char num[3][20]; -} isdnloop_sdef; - -#if defined(__KERNEL__) || defined(__DEBUGVAR__) - -#ifdef __KERNEL__ -/* Kernel includes */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif /* __KERNEL__ */ - -#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */ -#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */ -#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */ -#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */ -#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */ -#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */ -#define ISDNLOOP_TIMER_ALERTWAIT (10 * HZ) /* Alert timeout */ -#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */ -#define ISDNLOOP_BCH 2 /* channels per card */ - -/* - * Per card driver data - */ -typedef struct isdnloop_card { - struct isdnloop_card *next; /* Pointer to next device struct */ - struct isdnloop_card - *rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */ - int rch[ISDNLOOP_BCH]; /* 'remote' channel */ - int myid; /* Driver-Nr. assigned by linklevel */ - int leased; /* Flag: This Adapter is connected */ - /* to a leased line */ - int sil[ISDNLOOP_BCH]; /* SI's to listen for */ - char eazlist[ISDNLOOP_BCH][11]; - /* EAZ's to listen for */ - char s0num[3][20]; /* 1TR6 base-number or MSN's */ - unsigned short flags; /* Statusflags */ - int ptype; /* Protocol type (1TR6 or Euro) */ - struct timer_list st_timer; /* Timer for Status-Polls */ - struct timer_list rb_timer; /* Timer for B-Channel-Polls */ - struct timer_list - c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */ - int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */ - isdn_if interface; /* Interface to upper layer */ - int iptr; /* Index to imsg-buffer */ - char imsg[60]; /* Internal buf for status-parsing */ - int optr; /* Index to omsg-buffer */ - char omsg[60]; /* Internal buf for cmd-parsing */ - char msg_buf[2048]; /* Buffer for status-messages */ - char *msg_buf_write; /* Writepointer for statusbuffer */ - char *msg_buf_read; /* Readpointer for statusbuffer */ - char *msg_buf_end; /* Pointer to end of statusbuffer */ - int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */ - struct sk_buff_head - bqueue[ISDNLOOP_BCH]; /* B-Channel queues */ - struct sk_buff_head dqueue; /* D-Channel queue */ - spinlock_t isdnloop_lock; -} isdnloop_card; - -/* - * Main driver data - */ -#ifdef __KERNEL__ -static isdnloop_card *cards = (isdnloop_card *) 0; -#endif /* __KERNEL__ */ - -/* Utility-Macros */ - -#define CID (card->interface.id) - -#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */ -#endif /* isdnloop_h */ diff --git a/include/linux/concap.h b/include/linux/concap.h deleted file mode 100644 index 977acb3d1fb2..000000000000 --- a/include/linux/concap.h +++ /dev/null @@ -1,112 +0,0 @@ -/* $Id: concap.h,v 1.3.2.2 2004/01/12 23:08:35 keil Exp $ - * - * Copyright 1997 by Henner Eisen - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef _LINUX_CONCAP_H -#define _LINUX_CONCAP_H - -#include -#include - -/* Stuff to support encapsulation protocols genericly. The encapsulation - protocol is processed at the uppermost layer of the network interface. - - Based on a ideas developed in a 'synchronous device' thread in the - linux-x25 mailing list contributed by Alan Cox, Thomasz Motylewski - and Jonathan Naylor. - - For more documetation on this refer to Documentation/isdn/README.concap -*/ - -struct concap_proto_ops; -struct concap_device_ops; - -/* this manages all data needed by the encapsulation protocol - */ -struct concap_proto{ - struct net_device *net_dev; /* net device using our service */ - struct concap_device_ops *dops; /* callbacks provided by device */ - struct concap_proto_ops *pops; /* callbacks provided by us */ - spinlock_t lock; - int flags; - void *proto_data; /* protocol specific private data, to - be accessed via *pops methods only*/ - /* - : - whatever - : - */ -}; - -/* Operations to be supported by the net device. Called by the encapsulation - * protocol entity. No receive method is offered because the encapsulation - * protocol directly calls netif_rx(). - */ -struct concap_device_ops{ - - /* to request data is submitted by device*/ - int (*data_req)(struct concap_proto *, struct sk_buff *); - - /* Control methods must be set to NULL by devices which do not - support connection control.*/ - /* to request a connection is set up */ - int (*connect_req)(struct concap_proto *); - - /* to request a connection is released */ - int (*disconn_req)(struct concap_proto *); -}; - -/* Operations to be supported by the encapsulation protocol. Called by - * device driver. - */ -struct concap_proto_ops{ - - /* create a new encapsulation protocol instance of same type */ - struct concap_proto * (*proto_new) (void); - - /* delete encapsulation protocol instance and free all its resources. - cprot may no loger be referenced after calling this */ - void (*proto_del)(struct concap_proto *cprot); - - /* initialize the protocol's data. To be called at interface startup - or when the device driver resets the interface. All services of the - encapsulation protocol may be used after this*/ - int (*restart)(struct concap_proto *cprot, - struct net_device *ndev, - struct concap_device_ops *dops); - - /* inactivate an encapsulation protocol instance. The encapsulation - protocol may not call any *dops methods after this. */ - int (*close)(struct concap_proto *cprot); - - /* process a frame handed down to us by upper layer */ - int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb); - - /* to be called for each data entity received from lower layer*/ - int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb); - - /* to be called when a connection was set up/down. - Protocols that don't process these primitives might fill in - dummy methods here */ - int (*connect_ind)(struct concap_proto *cprot); - int (*disconn_ind)(struct concap_proto *cprot); - /* - Some network device support functions, like net_header(), rebuild_header(), - and others, that depend solely on the encapsulation protocol, might - be provided here, too. The net device would just fill them in its - corresponding fields when it is opened. - */ -}; - -/* dummy restart/close/connect/reset/disconn methods - */ -extern int concap_nop(struct concap_proto *cprot); - -/* dummy submit method - */ -extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb); -#endif diff --git a/include/linux/isdn.h b/include/linux/isdn.h deleted file mode 100644 index df97c8444f5d..000000000000 --- a/include/linux/isdn.h +++ /dev/null @@ -1,473 +0,0 @@ -/* $Id: isdn.h,v 1.125.2.3 2004/02/10 01:07:14 keil Exp $ - * - * Main header for the Linux ISDN subsystem (linklevel). - * - * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#ifndef __ISDN_H__ -#define __ISDN_H__ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ISDN_TTY_MAJOR 43 -#define ISDN_TTYAUX_MAJOR 44 -#define ISDN_MAJOR 45 - -/* The minor-devicenumbers for Channel 0 and 1 are used as arguments for - * physical Channel-Mapping, so they MUST NOT be changed without changing - * the correspondent code in isdn.c - */ - -#define ISDN_MINOR_B 0 -#define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1) -#define ISDN_MINOR_CTRL 64 -#define ISDN_MINOR_CTRLMAX (64 + (ISDN_MAX_CHANNELS-1)) -#define ISDN_MINOR_PPP 128 -#define ISDN_MINOR_PPPMAX (128 + (ISDN_MAX_CHANNELS-1)) -#define ISDN_MINOR_STATUS 255 - -#ifdef CONFIG_ISDN_PPP - -#ifdef CONFIG_ISDN_PPP_VJ -# include -#endif - -#include -#include - -#include -#endif - -#ifdef CONFIG_ISDN_X25 -# include -#endif - -#include - -#define ISDN_DRVIOCTL_MASK 0x7f /* Mask for Device-ioctl */ - -/* Until now unused */ -#define ISDN_SERVICE_VOICE 1 -#define ISDN_SERVICE_AB 1<<1 -#define ISDN_SERVICE_X21 1<<2 -#define ISDN_SERVICE_G4 1<<3 -#define ISDN_SERVICE_BTX 1<<4 -#define ISDN_SERVICE_DFUE 1<<5 -#define ISDN_SERVICE_X25 1<<6 -#define ISDN_SERVICE_TTX 1<<7 -#define ISDN_SERVICE_MIXED 1<<8 -#define ISDN_SERVICE_FW 1<<9 -#define ISDN_SERVICE_GTEL 1<<10 -#define ISDN_SERVICE_BTXN 1<<11 -#define ISDN_SERVICE_BTEL 1<<12 - -/* Macros checking plain usage */ -#define USG_NONE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE) -#define USG_RAW(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW) -#define USG_MODEM(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) -#define USG_VOICE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) -#define USG_NET(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET) -#define USG_FAX(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_FAX) -#define USG_OUTGOING(x) ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING) -#define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \ - ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) ) - -/* Timer-delays and scheduling-flags */ -#define ISDN_TIMER_RES 4 /* Main Timer-Resolution */ -#define ISDN_TIMER_02SEC (HZ/ISDN_TIMER_RES/5) /* Slow-Timer1 .2 sec */ -#define ISDN_TIMER_1SEC (HZ/ISDN_TIMER_RES) /* Slow-Timer2 1 sec */ -#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */ -#define ISDN_TIMER_KEEPINT 10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */ -#define ISDN_TIMER_MODEMREAD 1 -#define ISDN_TIMER_MODEMPLUS 2 -#define ISDN_TIMER_MODEMRING 4 -#define ISDN_TIMER_MODEMXMIT 8 -#define ISDN_TIMER_NETDIAL 16 -#define ISDN_TIMER_NETHANGUP 32 -#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */ -#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \ - ISDN_TIMER_MODEMXMIT) -#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \ - ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER) - -/* Timeout-Values for isdn_net_dial() */ -#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) -#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) -#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) - -/* GLOBAL_FLAGS */ -#define ISDN_GLOBAL_STOPPED 1 - -/*=================== Start of ip-over-ISDN stuff =========================*/ - -/* Feature- and status-flags for a net-interface */ -#define ISDN_NET_CONNECTED 0x01 /* Bound to ISDN-Channel */ -#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */ -#define ISDN_NET_CALLBACK 0x04 /* activate callback */ -#define ISDN_NET_CBHUP 0x08 /* hangup before callback */ -#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */ - -#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */ - -/* Phone-list-element */ -typedef struct { - void *next; - char num[ISDN_MSNLEN]; -} isdn_net_phone; - -/* - Principles when extending structures for generic encapsulation protocol - ("concap") support: - - Stuff which is hardware specific (here i4l-specific) goes in - the netdev -> local structure (here: isdn_net_local) - - Stuff which is encapsulation protocol specific goes in the structure - which holds the linux device structure (here: isdn_net_device) -*/ - -/* Local interface-data */ -typedef struct isdn_net_local_s { - ulong magic; - struct net_device_stats stats; /* Ethernet Statistics */ - int isdn_device; /* Index to isdn-device */ - int isdn_channel; /* Index to isdn-channel */ - int ppp_slot; /* PPPD device slot number */ - int pre_device; /* Preselected isdn-device */ - int pre_channel; /* Preselected isdn-channel */ - int exclusive; /* If non-zero idx to reserved chan.*/ - int flags; /* Connection-flags */ - int dialretry; /* Counter for Dialout-retries */ - int dialmax; /* Max. Number of Dial-retries */ - int cbdelay; /* Delay before Callback starts */ - int dtimer; /* Timeout-counter for dialing */ - char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */ - u_char cbhup; /* Flag: Reject Call before Callback*/ - u_char dialstate; /* State for dialing */ - u_char p_encap; /* Packet encapsulation */ - /* 0 = Ethernet over ISDN */ - /* 1 = RAW-IP */ - /* 2 = IP with type field */ - u_char l2_proto; /* Layer-2-protocol */ - /* See ISDN_PROTO_L2..-constants in */ - /* isdnif.h */ - /* 0 = X75/LAPB with I-Frames */ - /* 1 = X75/LAPB with UI-Frames */ - /* 2 = X75/LAPB with BUI-Frames */ - /* 3 = HDLC */ - u_char l3_proto; /* Layer-3-protocol */ - /* See ISDN_PROTO_L3..-constants in */ - /* isdnif.h */ - /* 0 = Transparent */ - int huptimer; /* Timeout-counter for auto-hangup */ - int charge; /* Counter for charging units */ - ulong chargetime; /* Timer for Charging info */ - int hupflags; /* Flags for charge-unit-hangup: */ - /* bit0: chargeint is invalid */ - /* bit1: Getting charge-interval */ - /* bit2: Do charge-unit-hangup */ - /* bit3: Do hangup even on incoming */ - int outgoing; /* Flag: outgoing call */ - int onhtime; /* Time to keep link up */ - int chargeint; /* Interval between charge-infos */ - int onum; /* Flag: at least 1 outgoing number */ - int cps; /* current speed of this interface */ - int transcount; /* byte-counter for cps-calculation */ - int sqfull; /* Flag: netdev-queue overloaded */ - ulong sqfull_stamp; /* Start-Time of overload */ - ulong slavedelay; /* Dynamic bundling delaytime */ - int triggercps; /* BogoCPS needed for trigger slave */ - isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ - /* phone[0] = Incoming Numbers */ - /* phone[1] = Outgoing Numbers */ - isdn_net_phone *dial; /* Pointer to dialed number */ - struct net_device *master; /* Ptr to Master device for slaves */ - struct net_device *slave; /* Ptr to Slave device for masters */ - struct isdn_net_local_s *next; /* Ptr to next link in bundle */ - struct isdn_net_local_s *last; /* Ptr to last link in bundle */ - struct isdn_net_dev_s *netdev; /* Ptr to netdev */ - struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ - /* be transmitted asap */ - atomic_t frame_cnt; /* number of frames currently */ - /* queued in HL driver */ - /* Ptr to orig. hard_header_cache */ - spinlock_t xmit_lock; /* used to protect the xmit path of */ - /* a particular channel (including */ - /* the frame_cnt */ - - int pppbind; /* ippp device for bindings */ - int dialtimeout; /* How long shall we try on dialing? (jiffies) */ - int dialwait; /* How long shall we wait after failed attempt? (jiffies) */ - ulong dialstarted; /* jiffies of first dialing-attempt */ - ulong dialwait_timer; /* jiffies of earliest next dialing-attempt */ - int huptimeout; /* How long will the connection be up? (seconds) */ -#ifdef CONFIG_ISDN_X25 - struct concap_device_ops *dops; /* callbacks used by encapsulator */ -#endif - /* use an own struct for that in later versions */ - ulong cisco_myseq; /* Local keepalive seq. for Cisco */ - ulong cisco_mineseen; /* returned keepalive seq. from remote */ - ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */ - int cisco_keepalive_period; /* keepalive period */ - ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */ - char cisco_line_state; /* state of line according to keepalive packets */ - char cisco_debserint; /* debugging flag of cisco hdlc with slarp */ - struct timer_list cisco_timer; - struct work_struct tqueue; -} isdn_net_local; - -/* the interface itself */ -typedef struct isdn_net_dev_s { - isdn_net_local *local; - isdn_net_local *queue; /* circular list of all bundled - channels, which are currently - online */ - spinlock_t queue_lock; /* lock to protect queue */ - void *next; /* Pointer to next isdn-interface */ - struct net_device *dev; /* interface to upper levels */ -#ifdef CONFIG_ISDN_PPP - ippp_bundle * pb; /* pointer to the common bundle structure - * with the per-bundle data */ -#endif -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot; /* connection oriented encapsulation protocol */ -#endif - -} isdn_net_dev; - -/*===================== End of ip-over-ISDN stuff ===========================*/ - -/*======================= Start of ISDN-tty stuff ===========================*/ - -#define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */ -#define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */ -#define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */ - -#ifdef CONFIG_ISDN_AUDIO -/* For using sk_buffs with audio we need some private variables - * within each sk_buff. For this purpose, we declare a struct here, - * and put it always at the private skb->cb data array. A few macros help - * accessing the variables. - */ -typedef struct _isdn_audio_data { - unsigned short dle_count; - unsigned char lock; -} isdn_audio_data_t; - -#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_data_t *)&skb->cb[0])->dle_count) -#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_data_t *)&skb->cb[0])->lock) -#endif - -/* Private data of AT-command-interpreter */ -typedef struct atemu { - u_char profile[ISDN_MODEM_NUMREG]; /* Modem-Regs. Profile 0 */ - u_char mdmreg[ISDN_MODEM_NUMREG]; /* Modem-Registers */ - char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */ - char msn[ISDN_MSNLEN]; /* EAZ/MSN */ - char plmsn[ISDN_LMSNLEN]; /* Listening MSNs Profile 0 */ - char lmsn[ISDN_LMSNLEN]; /* Listening MSNs */ - char cpn[ISDN_MSNLEN]; /* CalledPartyNumber on incoming call */ - char connmsg[ISDN_CMSGLEN]; /* CONNECT-Msg from HL-Driver */ -#ifdef CONFIG_ISDN_AUDIO - u_char vpar[10]; /* Voice-parameters */ - int lastDLE; /* Flag for voice-coding: DLE seen */ -#endif - int mdmcmdl; /* Length of Modem-Commandbuffer */ - int pluscount; /* Counter for +++ sequence */ - u_long lastplus; /* Timestamp of last + */ - int carrierwait; /* Seconds of carrier waiting */ - char mdmcmd[255]; /* Modem-Commandbuffer */ - unsigned int charge; /* Charge units of current connection */ -} atemu; - -/* Private data (similar to async_struct in ) */ -typedef struct modem_info { - int magic; - struct tty_port port; - int x_char; /* xon/xoff character */ - int mcr; /* Modem control register */ - int msr; /* Modem status register */ - int lsr; /* Line status register */ - int line; - int online; /* 1 = B-Channel is up, drop data */ - /* 2 = B-Channel is up, deliver d.*/ - int dialing; /* Dial in progress or ATA */ - int closing; - int rcvsched; /* Receive needs schedule */ - int isdn_driver; /* Index to isdn-driver */ - int isdn_channel; /* Index to isdn-channel */ - int drv_index; /* Index to dev->usage */ - int ncarrier; /* Flag: schedule NO CARRIER */ - unsigned char last_cause[8]; /* Last cause message */ - unsigned char last_num[ISDN_MSNLEN]; - /* Last phone-number */ - unsigned char last_l2; /* Last layer-2 protocol */ - unsigned char last_si; /* Last service */ - unsigned char last_lhup; /* Last hangup local? */ - unsigned char last_dir; /* Last direction (in or out) */ - struct timer_list nc_timer; /* Timer for delayed NO CARRIER */ - int send_outstanding;/* # of outstanding send-requests */ - int xmit_size; /* max. # of chars in xmit_buf */ - int xmit_count; /* # of chars in xmit_buf */ - struct sk_buff_head xmit_queue; /* transmit queue */ - atomic_t xmit_lock; /* Semaphore for isdn_tty_write */ -#ifdef CONFIG_ISDN_AUDIO - int vonline; /* Voice-channel status */ - /* Bit 0 = recording */ - /* Bit 1 = playback */ - /* Bit 2 = playback, DLE-ETX seen */ - struct sk_buff_head dtmf_queue; /* queue for dtmf results */ - void *adpcms; /* state for adpcm decompression */ - void *adpcmr; /* state for adpcm compression */ - void *dtmf_state; /* state for dtmf decoder */ - void *silence_state; /* state for silence detection */ -#endif -#ifdef CONFIG_ISDN_TTY_FAX - struct T30_s *fax; /* T30 Fax Group 3 data/interface */ - int faxonline; /* Fax-channel status */ -#endif - atemu emu; /* AT-emulator data */ - spinlock_t readlock; -} modem_info; - -#define ISDN_MODEM_WINSIZE 8 - -/* Description of one ISDN-tty */ -typedef struct _isdn_modem { - int refcount; /* Number of opens */ - struct tty_driver *tty_modem; /* tty-device */ - struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */ - struct ktermios *modem_termios[ISDN_MAX_CHANNELS]; - struct ktermios *modem_termios_locked[ISDN_MAX_CHANNELS]; - modem_info info[ISDN_MAX_CHANNELS]; /* Private data */ -} isdn_modem_t; - -/*======================= End of ISDN-tty stuff ============================*/ - -/*======================== Start of V.110 stuff ============================*/ -#define V110_BUFSIZE 1024 - -typedef struct { - int nbytes; /* 1 Matrixbyte -> nbytes in stream */ - int nbits; /* Number of used bits in streambyte */ - unsigned char key; /* Bitmask in stream eg. 11 (nbits=2) */ - int decodelen; /* Amount of data in decodebuf */ - int SyncInit; /* Number of sync frames to send */ - unsigned char *OnlineFrame; /* Precalculated V110 idle frame */ - unsigned char *OfflineFrame; /* Precalculated V110 sync Frame */ - int framelen; /* Length of frames */ - int skbuser; /* Number of unacked userdata skbs */ - int skbidle; /* Number of unacked idle/sync skbs */ - int introducer; /* Local vars for decoder */ - int dbit; - unsigned char b; - int skbres; /* space to reserve in outgoing skb */ - int maxsize; /* maxbufsize of lowlevel driver */ - unsigned char *encodebuf; /* temporary buffer for encoding */ - unsigned char decodebuf[V110_BUFSIZE]; /* incomplete V110 matrices */ -} isdn_v110_stream; - -/*========================= End of V.110 stuff =============================*/ - -/*======================= Start of general stuff ===========================*/ - -typedef struct { - char *next; - char *private; -} infostruct; - -#define DRV_FLAG_RUNNING 1 -#define DRV_FLAG_REJBUS 2 -#define DRV_FLAG_LOADED 4 - -/* Description of hardware-level-driver */ -typedef struct _isdn_driver { - ulong online; /* Channel-Online flags */ - ulong flags; /* Misc driver Flags */ - int locks; /* Number of locks for this driver */ - int channels; /* Number of channels */ - wait_queue_head_t st_waitq; /* Wait-Queue for status-read's */ - int maxbufsize; /* Maximum Buffersize supported */ - unsigned long pktcount; /* Until now: unused */ - int stavail; /* Chars avail on Status-device */ - isdn_if *interface; /* Interface to driver */ - int *rcverr; /* Error-counters for B-Ch.-receive */ - int *rcvcount; /* Byte-counters for B-Ch.-receive */ -#ifdef CONFIG_ISDN_AUDIO - unsigned long DLEflag; /* Flags: Insert DLE at next read */ -#endif - struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */ - wait_queue_head_t *rcv_waitq; /* Wait-Queues for B-Channel-Reads */ - wait_queue_head_t *snd_waitq; /* Wait-Queue for B-Channel-Send's */ - char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */ -} isdn_driver_t; - -/* Main driver-data */ -typedef struct isdn_devt { - struct module *owner; - spinlock_t lock; - unsigned short flags; /* Bitmapped Flags: */ - int drivers; /* Current number of drivers */ - int channels; /* Current number of channels */ - int net_verbose; /* Verbose-Flag */ - int modempoll; /* Flag: tty-read active */ - spinlock_t timerlock; - int tflags; /* Timer-Flags: */ - /* see ISDN_TIMER_..defines */ - int global_flags; - infostruct *infochain; /* List of open info-devs. */ - wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */ - struct timer_list timer; /* Misc.-function Timer */ - int chanmap[ISDN_MAX_CHANNELS]; /* Map minor->device-channel */ - int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */ - int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */ - char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN]; - /* Remote number of active ch.*/ - int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */ - isdn_driver_t *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */ - isdn_net_dev *netdev; /* Linked list of net-if's */ - char drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID */ - struct task_struct *profd; /* For iprofd */ - isdn_modem_t mdm; /* tty-driver-data */ - isdn_net_dev *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers */ - isdn_net_dev *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers */ - ulong ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes */ - ulong obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes */ - int v110emu[ISDN_MAX_CHANNELS]; /* V.110 emulator-mode 0=none */ - atomic_t v110use[ISDN_MAX_CHANNELS]; /* Usage-Semaphore for stream */ - isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */ - struct mutex mtx; /* serialize list access*/ - unsigned long global_features; -} isdn_dev; - -extern isdn_dev *dev; - - -#endif /* __ISDN_H__ */ diff --git a/include/linux/isdn_divertif.h b/include/linux/isdn_divertif.h deleted file mode 100644 index 19ab361f9f07..000000000000 --- a/include/linux/isdn_divertif.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id: isdn_divertif.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $ - * - * Header for the diversion supplementary interface for i4l. - * - * Author Werner Cornelius (werner@titro.de) - * Copyright 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 _LINUX_ISDN_DIVERTIF_H -#define _LINUX_ISDN_DIVERTIF_H - -#include -#include -#include - -/***************************************************************/ -/* structure exchanging data between isdn hl and divert module */ -/***************************************************************/ -typedef struct - { ulong if_magic; /* magic info and version */ - int cmd; /* command */ - int (*stat_callback)(isdn_ctrl *); /* supplied by divert module when calling */ - int (*ll_cmd)(isdn_ctrl *); /* supplied by hl on return */ - char * (*drv_to_name)(int); /* map a driver id to name, supplied by hl */ - int (*name_to_drv)(char *); /* map a driver id to name, supplied by hl */ - } isdn_divert_if; - -/*********************/ -/* function register */ -/*********************/ -extern int DIVERT_REG_NAME(isdn_divert_if *); -#endif /* _LINUX_ISDN_DIVERTIF_H */ diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h deleted file mode 100644 index a0070c6dfaf8..000000000000 --- a/include/linux/isdn_ppp.h +++ /dev/null @@ -1,194 +0,0 @@ -/* Linux ISDN subsystem, sync PPP, interface to ipppd - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#ifndef _LINUX_ISDN_PPP_H -#define _LINUX_ISDN_PPP_H - - - - -#ifdef CONFIG_IPPP_FILTER -#include -#endif -#include - -#define DECOMP_ERR_NOMEM (-10) - -#define MP_END_FRAG 0x40 -#define MP_BEGIN_FRAG 0x80 - -#define MP_MAX_QUEUE_LEN 16 - -/* - * We need a way for the decompressor to influence the generation of CCP - * Reset-Requests in a variety of ways. The decompressor is already returning - * a lot of information (generated skb length, error conditions) so we use - * another parameter. This parameter is a pointer to a structure which is - * to be marked valid by the decompressor and only in this case is ever used. - * Furthermore, the only case where this data is used is when the decom- - * pressor returns DECOMP_ERROR. - * - * We use this same struct for the reset entry of the compressor to commu- - * nicate to its caller how to deal with sending of a Reset Ack. In this - * case, expra is not used, but other options still apply (suppressing - * sending with rsend, appending arbitrary data, etc). - */ - -#define IPPP_RESET_MAXDATABYTES 32 - -struct isdn_ppp_resetparams { - unsigned char valid:1; /* rw Is this structure filled at all ? */ - unsigned char rsend:1; /* rw Should we send one at all ? */ - unsigned char idval:1; /* rw Is the id field valid ? */ - unsigned char dtval:1; /* rw Is the data field valid ? */ - unsigned char expra:1; /* rw Is an Ack expected for this Req ? */ - unsigned char id; /* wo Send CCP ResetReq with this id */ - unsigned short maxdlen; /* ro Max bytes to be stored in data field */ - unsigned short dlen; /* rw Bytes stored in data field */ - unsigned char *data; /* wo Data for ResetReq info field */ -}; - -/* - * this is an 'old friend' from ppp-comp.h under a new name - * check the original include for more information - */ -struct isdn_ppp_compressor { - struct isdn_ppp_compressor *next, *prev; - struct module *owner; - int num; /* CCP compression protocol number */ - - void *(*alloc) (struct isdn_ppp_comp_data *); - void (*free) (void *state); - int (*init) (void *state, struct isdn_ppp_comp_data *, - int unit,int debug); - - /* The reset entry needs to get more exact information about the - ResetReq or ResetAck it was called with. The parameters are - obvious. If reset is called without a Req or Ack frame which - could be handed into it, code MUST be set to 0. Using rsparm, - the reset entry can control if and how a ResetAck is returned. */ - - void (*reset) (void *state, unsigned char code, unsigned char id, - unsigned char *data, unsigned len, - struct isdn_ppp_resetparams *rsparm); - - int (*compress) (void *state, struct sk_buff *in, - struct sk_buff *skb_out, int proto); - - int (*decompress) (void *state,struct sk_buff *in, - struct sk_buff *skb_out, - struct isdn_ppp_resetparams *rsparm); - - void (*incomp) (void *state, struct sk_buff *in,int proto); - void (*stat) (void *state, struct compstat *stats); -}; - -extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *); -extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *); -extern int isdn_ppp_dial_slave(char *); -extern int isdn_ppp_hangup_slave(char *); - -typedef struct { - unsigned long seqerrs; - unsigned long frame_drops; - unsigned long overflows; - unsigned long max_queue_len; -} isdn_mppp_stats; - -typedef struct { - int mp_mrru; /* unused */ - struct sk_buff * frags; /* fragments sl list -- use skb->next */ - long frames; /* number of frames in the frame list */ - unsigned int seq; /* last processed packet seq #: any packets - * with smaller seq # will be dropped - * unconditionally */ - spinlock_t lock; - int ref_ct; - /* statistics */ - isdn_mppp_stats stats; -} ippp_bundle; - -#define NUM_RCV_BUFFS 64 - -struct ippp_buf_queue { - struct ippp_buf_queue *next; - struct ippp_buf_queue *last; - char *buf; /* NULL here indicates end of queue */ - int len; -}; - -/* The data structure for one CCP reset transaction */ -enum ippp_ccp_reset_states { - CCPResetIdle, - CCPResetSentReq, - CCPResetRcvdReq, - CCPResetSentAck, - CCPResetRcvdAck -}; - -struct ippp_ccp_reset_state { - enum ippp_ccp_reset_states state; /* State of this transaction */ - struct ippp_struct *is; /* Backlink to device stuff */ - unsigned char id; /* Backlink id index */ - unsigned char ta:1; /* The timer is active (flag) */ - unsigned char expra:1; /* We expect a ResetAck at all */ - int dlen; /* Databytes stored in data */ - struct timer_list timer; /* For timeouts/retries */ - /* This is a hack but seems sufficient for the moment. We do not want - to have this be yet another allocation for some bytes, it is more - memory management overhead than the whole mess is worth. */ - unsigned char data[IPPP_RESET_MAXDATABYTES]; -}; - -/* The data structure keeping track of the currently outstanding CCP Reset - transactions. */ -struct ippp_ccp_reset { - struct ippp_ccp_reset_state *rs[256]; /* One per possible id */ - unsigned char lastid; /* Last id allocated by the engine */ -}; - -struct ippp_struct { - struct ippp_struct *next_link; - int state; - spinlock_t buflock; - struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */ - struct ippp_buf_queue *first; /* pointer to (current) first packet */ - struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */ - wait_queue_head_t wq; - struct task_struct *tk; - unsigned int mpppcfg; - unsigned int pppcfg; - unsigned int mru; - unsigned int mpmru; - unsigned int mpmtu; - unsigned int maxcid; - struct isdn_net_local_s *lp; - int unit; - int minor; - unsigned int last_link_seqno; - long mp_seqno; -#ifdef CONFIG_ISDN_PPP_VJ - unsigned char *cbuf; - struct slcompress *slcomp; -#endif -#ifdef CONFIG_IPPP_FILTER - struct bpf_prog *pass_filter; /* filter for packets to pass */ - struct bpf_prog *active_filter; /* filter for pkts to reset idle */ -#endif - unsigned long debug; - struct isdn_ppp_compressor *compressor,*decompressor; - struct isdn_ppp_compressor *link_compressor,*link_decompressor; - void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat; - struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */ - unsigned long compflags; -}; - -#endif /* _LINUX_ISDN_PPP_H */ diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h deleted file mode 100644 index 8d80fdc68647..000000000000 --- a/include/linux/isdnif.h +++ /dev/null @@ -1,505 +0,0 @@ -/* $Id: isdnif.h,v 1.43.2.2 2004/01/12 23:08:35 keil Exp $ - * - * Linux ISDN subsystem - * Definition of the interface between the subsystem and its low-level drivers. - * - * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#ifndef __ISDNIF_H__ -#define __ISDNIF_H__ - - -#include -#include - -/***************************************************************************/ -/* Extensions made by Werner Cornelius (werner@ikt.de) */ -/* */ -/* The proceed command holds a incoming call in a state to leave processes */ -/* enough time to check whether ist should be accepted. */ -/* The PROT_IO Command extends the interface to make protocol dependent */ -/* features available (call diversion, call waiting...). */ -/* */ -/* The PROT_IO Command is executed with the desired driver id and the arg */ -/* parameter coded as follows: */ -/* The lower 8 bits of arg contain the desired protocol from ISDN_PTYPE */ -/* definitions. The upper 24 bits represent the protocol specific cmd/stat.*/ -/* Any additional data is protocol and command specific. */ -/* This mechanism also applies to the statcallb callback STAT_PROT. */ -/* */ -/* This suggested extension permits an easy expansion of protocol specific */ -/* handling. Extensions may be added at any time without changing the HL */ -/* driver code and not getting conflicts without certifications. */ -/* The well known CAPI 2.0 interface handles such extensions in a similar */ -/* way. Perhaps a protocol specific module may be added and separately */ -/* loaded and linked to the basic isdn module for handling. */ -/***************************************************************************/ - -/*****************/ -/* DSS1 commands */ -/*****************/ -#define DSS1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_EURO) /* invoke a supplementary service */ -#define DSS1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_EURO) /* abort a invoke cmd */ - -/*******************************/ -/* DSS1 Status callback values */ -/*******************************/ -#define DSS1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_EURO) /* Result for invocation */ -#define DSS1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_EURO) /* Error Return for invocation */ -#define DSS1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_EURO) /* Deliver invoke broadcast info */ - - -/*********************************************************************/ -/* structures for DSS1 commands and callback */ -/* */ -/* An action is invoked by sending a DSS1_CMD_INVOKE. The ll_id, proc*/ -/* timeout, datalen and data fields must be set before calling. */ -/* */ -/* The return value is a positive hl_id value also delivered in the */ -/* hl_id field. A value of zero signals no more left hl_id capacitys.*/ -/* A negative return value signals errors in LL. So if the return */ -/* value is <= 0 no action in LL will be taken -> request ignored */ -/* */ -/* The timeout field must be filled with a positive value specifying */ -/* the amount of time the INVOKED process waits for a reaction from */ -/* the network. */ -/* If a response (either error or result) is received during this */ -/* intervall, a reporting callback is initiated and the process will */ -/* be deleted, the hl identifier will be freed. */ -/* If no response is received during the specified intervall, a error*/ -/* callback is initiated with timeout set to -1 and a datalen set */ -/* to 0. */ -/* If timeout is set to a value <= 0 during INVOCATION the process is*/ -/* immediately deleted after sending the data. No callback occurs ! */ -/* */ -/* A currently waiting process may be aborted with INVOKE_ABORT. No */ -/* callback will occur when a process has been aborted. */ -/* */ -/* Broadcast invoke frames from the network are reported via the */ -/* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */ -/* are supplied by the network and not by the HL. */ -/*********************************************************************/ - -/*****************/ -/* NI1 commands */ -/*****************/ -#define NI1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_NI1) /* invoke a supplementary service */ -#define NI1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_NI1) /* abort a invoke cmd */ - -/*******************************/ -/* NI1 Status callback values */ -/*******************************/ -#define NI1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_NI1) /* Result for invocation */ -#define NI1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_NI1) /* Error Return for invocation */ -#define NI1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_NI1) /* Deliver invoke broadcast info */ - -typedef struct - { ulong ll_id; /* ID supplied by LL when executing */ - /* a command and returned by HL for */ - /* INVOKE_RES and INVOKE_ERR */ - int hl_id; /* ID supplied by HL when called */ - /* for executing a cmd and delivered */ - /* for results and errors */ - /* must be supplied by LL when aborting*/ - int proc; /* invoke procedure used by CMD_INVOKE */ - /* returned by callback and broadcast */ - int timeout; /* timeout for INVOKE CMD in ms */ - /* -1 in stat callback when timed out */ - /* error value when error callback */ - int datalen; /* length of cmd or stat data */ - u_char *data;/* pointer to data delivered or send */ - } isdn_cmd_stat; - -/* - * Commands from linklevel to lowlevel - * - */ -#define ISDN_CMD_IOCTL 0 /* Perform ioctl */ -#define ISDN_CMD_DIAL 1 /* Dial out */ -#define ISDN_CMD_ACCEPTD 2 /* Accept an incoming call on D-Chan. */ -#define ISDN_CMD_ACCEPTB 3 /* Request B-Channel connect. */ -#define ISDN_CMD_HANGUP 4 /* Hangup */ -#define ISDN_CMD_CLREAZ 5 /* Clear EAZ(s) of channel */ -#define ISDN_CMD_SETEAZ 6 /* Set EAZ(s) of channel */ -#define ISDN_CMD_GETEAZ 7 /* Get EAZ(s) of channel */ -#define ISDN_CMD_SETSIL 8 /* Set Service-Indicator-List of channel */ -#define ISDN_CMD_GETSIL 9 /* Get Service-Indicator-List of channel */ -#define ISDN_CMD_SETL2 10 /* Set B-Chan. Layer2-Parameter */ -#define ISDN_CMD_GETL2 11 /* Get B-Chan. Layer2-Parameter */ -#define ISDN_CMD_SETL3 12 /* Set B-Chan. Layer3-Parameter */ -#define ISDN_CMD_GETL3 13 /* Get B-Chan. Layer3-Parameter */ -// #define ISDN_CMD_LOCK 14 /* Signal usage by upper levels */ -// #define ISDN_CMD_UNLOCK 15 /* Release usage-lock */ -#define ISDN_CMD_SUSPEND 16 /* Suspend connection */ -#define ISDN_CMD_RESUME 17 /* Resume connection */ -#define ISDN_CMD_PROCEED 18 /* Proceed with call establishment */ -#define ISDN_CMD_ALERT 19 /* Alert after Proceeding */ -#define ISDN_CMD_REDIR 20 /* Redir a incoming call */ -#define ISDN_CMD_PROT_IO 21 /* Protocol specific commands */ -#define CAPI_PUT_MESSAGE 22 /* CAPI message send down or up */ -#define ISDN_CMD_FAXCMD 23 /* FAX commands to HL-driver */ -#define ISDN_CMD_AUDIO 24 /* DSP, DTMF, ... settings */ - -/* - * Status-Values delivered from lowlevel to linklevel via - * statcallb(). - * - */ -#define ISDN_STAT_STAVAIL 256 /* Raw status-data available */ -#define ISDN_STAT_ICALL 257 /* Incoming call detected */ -#define ISDN_STAT_RUN 258 /* Signal protocol-code is running */ -#define ISDN_STAT_STOP 259 /* Signal halt of protocol-code */ -#define ISDN_STAT_DCONN 260 /* Signal D-Channel connect */ -#define ISDN_STAT_BCONN 261 /* Signal B-Channel connect */ -#define ISDN_STAT_DHUP 262 /* Signal D-Channel disconnect */ -#define ISDN_STAT_BHUP 263 /* Signal B-Channel disconnect */ -#define ISDN_STAT_CINF 264 /* Charge-Info */ -#define ISDN_STAT_LOAD 265 /* Signal new lowlevel-driver is loaded */ -#define ISDN_STAT_UNLOAD 266 /* Signal unload of lowlevel-driver */ -#define ISDN_STAT_BSENT 267 /* Signal packet sent */ -#define ISDN_STAT_NODCH 268 /* Signal no D-Channel */ -#define ISDN_STAT_ADDCH 269 /* Add more Channels */ -#define ISDN_STAT_CAUSE 270 /* Cause-Message */ -#define ISDN_STAT_ICALLW 271 /* Incoming call without B-chan waiting */ -#define ISDN_STAT_REDIR 272 /* Redir result */ -#define ISDN_STAT_PROT 273 /* protocol IO specific callback */ -#define ISDN_STAT_DISPLAY 274 /* deliver a received display message */ -#define ISDN_STAT_L1ERR 275 /* Signal Layer-1 Error */ -#define ISDN_STAT_FAXIND 276 /* FAX indications from HL-driver */ -#define ISDN_STAT_AUDIO 277 /* DTMF, DSP indications */ -#define ISDN_STAT_DISCH 278 /* Disable/Enable channel usage */ - -/* - * Audio commands - */ -#define ISDN_AUDIO_SETDD 0 /* Set DTMF detection */ -#define ISDN_AUDIO_DTMF 1 /* Rx/Tx DTMF */ - -/* - * Values for errcode field - */ -#define ISDN_STAT_L1ERR_SEND 1 -#define ISDN_STAT_L1ERR_RECV 2 - -/* - * Values for feature-field of interface-struct. - */ -/* Layer 2 */ -#define ISDN_FEATURE_L2_X75I (0x0001 << ISDN_PROTO_L2_X75I) -#define ISDN_FEATURE_L2_X75UI (0x0001 << ISDN_PROTO_L2_X75UI) -#define ISDN_FEATURE_L2_X75BUI (0x0001 << ISDN_PROTO_L2_X75BUI) -#define ISDN_FEATURE_L2_HDLC (0x0001 << ISDN_PROTO_L2_HDLC) -#define ISDN_FEATURE_L2_TRANS (0x0001 << ISDN_PROTO_L2_TRANS) -#define ISDN_FEATURE_L2_X25DTE (0x0001 << ISDN_PROTO_L2_X25DTE) -#define ISDN_FEATURE_L2_X25DCE (0x0001 << ISDN_PROTO_L2_X25DCE) -#define ISDN_FEATURE_L2_V11096 (0x0001 << ISDN_PROTO_L2_V11096) -#define ISDN_FEATURE_L2_V11019 (0x0001 << ISDN_PROTO_L2_V11019) -#define ISDN_FEATURE_L2_V11038 (0x0001 << ISDN_PROTO_L2_V11038) -#define ISDN_FEATURE_L2_MODEM (0x0001 << ISDN_PROTO_L2_MODEM) -#define ISDN_FEATURE_L2_FAX (0x0001 << ISDN_PROTO_L2_FAX) -#define ISDN_FEATURE_L2_HDLC_56K (0x0001 << ISDN_PROTO_L2_HDLC_56K) - -#define ISDN_FEATURE_L2_MASK (0x0FFFF) /* Max. 16 protocols */ -#define ISDN_FEATURE_L2_SHIFT (0) - -/* Layer 3 */ -#define ISDN_FEATURE_L3_TRANS (0x10000 << ISDN_PROTO_L3_TRANS) -#define ISDN_FEATURE_L3_TRANSDSP (0x10000 << ISDN_PROTO_L3_TRANSDSP) -#define ISDN_FEATURE_L3_FCLASS2 (0x10000 << ISDN_PROTO_L3_FCLASS2) -#define ISDN_FEATURE_L3_FCLASS1 (0x10000 << ISDN_PROTO_L3_FCLASS1) - -#define ISDN_FEATURE_L3_MASK (0x0FF0000) /* Max. 8 Protocols */ -#define ISDN_FEATURE_L3_SHIFT (16) - -/* Signaling */ -#define ISDN_FEATURE_P_UNKNOWN (0x1000000 << ISDN_PTYPE_UNKNOWN) -#define ISDN_FEATURE_P_1TR6 (0x1000000 << ISDN_PTYPE_1TR6) -#define ISDN_FEATURE_P_EURO (0x1000000 << ISDN_PTYPE_EURO) -#define ISDN_FEATURE_P_NI1 (0x1000000 << ISDN_PTYPE_NI1) - -#define ISDN_FEATURE_P_MASK (0x0FF000000) /* Max. 8 Protocols */ -#define ISDN_FEATURE_P_SHIFT (24) - -typedef struct setup_parm { - unsigned char phone[32]; /* Remote Phone-Number */ - unsigned char eazmsn[32]; /* Local EAZ or MSN */ - unsigned char si1; /* Service Indicator 1 */ - unsigned char si2; /* Service Indicator 2 */ - unsigned char plan; /* Numbering plan */ - unsigned char screen; /* Screening info */ -} setup_parm; - - -#ifdef CONFIG_ISDN_TTY_FAX -/* T.30 Fax G3 */ - -#define FAXIDLEN 21 - -typedef struct T30_s { - /* session parameters */ - __u8 resolution; - __u8 rate; - __u8 width; - __u8 length; - __u8 compression; - __u8 ecm; - __u8 binary; - __u8 scantime; - __u8 id[FAXIDLEN]; - /* additional parameters */ - __u8 phase; - __u8 direction; - __u8 code; - __u8 badlin; - __u8 badmul; - __u8 bor; - __u8 fet; - __u8 pollid[FAXIDLEN]; - __u8 cq; - __u8 cr; - __u8 ctcrty; - __u8 minsp; - __u8 phcto; - __u8 rel; - __u8 nbc; - /* remote station parameters */ - __u8 r_resolution; - __u8 r_rate; - __u8 r_width; - __u8 r_length; - __u8 r_compression; - __u8 r_ecm; - __u8 r_binary; - __u8 r_scantime; - __u8 r_id[FAXIDLEN]; - __u8 r_code; -} __packed T30_s; - -#define ISDN_TTY_FAX_CONN_IN 0 -#define ISDN_TTY_FAX_CONN_OUT 1 - -#define ISDN_TTY_FAX_FCON 0 -#define ISDN_TTY_FAX_DIS 1 -#define ISDN_TTY_FAX_FTT 2 -#define ISDN_TTY_FAX_MCF 3 -#define ISDN_TTY_FAX_DCS 4 -#define ISDN_TTY_FAX_TRAIN_OK 5 -#define ISDN_TTY_FAX_EOP 6 -#define ISDN_TTY_FAX_EOM 7 -#define ISDN_TTY_FAX_MPS 8 -#define ISDN_TTY_FAX_DTC 9 -#define ISDN_TTY_FAX_RID 10 -#define ISDN_TTY_FAX_HNG 11 -#define ISDN_TTY_FAX_DT 12 -#define ISDN_TTY_FAX_FCON_I 13 -#define ISDN_TTY_FAX_DR 14 -#define ISDN_TTY_FAX_ET 15 -#define ISDN_TTY_FAX_CFR 16 -#define ISDN_TTY_FAX_PTS 17 -#define ISDN_TTY_FAX_SENT 18 - -#define ISDN_FAX_PHASE_IDLE 0 -#define ISDN_FAX_PHASE_A 1 -#define ISDN_FAX_PHASE_B 2 -#define ISDN_FAX_PHASE_C 3 -#define ISDN_FAX_PHASE_D 4 -#define ISDN_FAX_PHASE_E 5 - -#endif /* TTY_FAX */ - -#define ISDN_FAX_CLASS1_FAE 0 -#define ISDN_FAX_CLASS1_FTS 1 -#define ISDN_FAX_CLASS1_FRS 2 -#define ISDN_FAX_CLASS1_FTM 3 -#define ISDN_FAX_CLASS1_FRM 4 -#define ISDN_FAX_CLASS1_FTH 5 -#define ISDN_FAX_CLASS1_FRH 6 -#define ISDN_FAX_CLASS1_CTRL 7 - -#define ISDN_FAX_CLASS1_OK 0 -#define ISDN_FAX_CLASS1_CONNECT 1 -#define ISDN_FAX_CLASS1_NOCARR 2 -#define ISDN_FAX_CLASS1_ERROR 3 -#define ISDN_FAX_CLASS1_FCERROR 4 -#define ISDN_FAX_CLASS1_QUERY 5 - -typedef struct { - __u8 cmd; - __u8 subcmd; - __u8 para[50]; -} aux_s; - -#define AT_COMMAND 0 -#define AT_EQ_VALUE 1 -#define AT_QUERY 2 -#define AT_EQ_QUERY 3 - -/* CAPI structs */ - -/* this is compatible to the old union size */ -#define MAX_CAPI_PARA_LEN 50 - -typedef struct { - /* Header */ - __u16 Length; - __u16 ApplId; - __u8 Command; - __u8 Subcommand; - __u16 Messagenumber; - - /* Parameter */ - union { - __u32 Controller; - __u32 PLCI; - __u32 NCCI; - } adr; - __u8 para[MAX_CAPI_PARA_LEN]; -} capi_msg; - -/* - * Structure for exchanging above infos - * - */ -typedef struct { - int driver; /* Lowlevel-Driver-ID */ - int command; /* Command or Status (see above) */ - ulong arg; /* Additional Data */ - union { - ulong errcode; /* Type of error with STAT_L1ERR */ - int length; /* Amount of bytes sent with STAT_BSENT */ - u_char num[50]; /* Additional Data */ - setup_parm setup;/* For SETUP msg */ - capi_msg cmsg; /* For CAPI like messages */ - char display[85];/* display message data */ - isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */ - aux_s aux; /* for modem commands/indications */ -#ifdef CONFIG_ISDN_TTY_FAX - T30_s *fax; /* Pointer to ttys fax struct */ -#endif - ulong userdata; /* User Data */ - } parm; -} isdn_ctrl; - -#define dss1_io isdn_io -#define ni1_io isdn_io - -/* - * The interface-struct itself (initialized at load-time of lowlevel-driver) - * - * See Documentation/isdn/INTERFACE for a description, how the communication - * between the ISDN subsystem and its drivers is done. - * - */ -typedef struct { - struct module *owner; - - /* Number of channels supported by this driver - */ - int channels; - - /* - * Maximum Size of transmit/receive-buffer this driver supports. - */ - int maxbufsize; - - /* Feature-Flags for this driver. - * See defines ISDN_FEATURE_... for Values - */ - unsigned long features; - - /* - * Needed for calculating - * dev->hard_header_len = linklayer header + hl_hdrlen; - * Drivers, not supporting sk_buff's should set this to 0. - */ - unsigned short hl_hdrlen; - - /* - * Receive-Callback using sk_buff's - * Parameters: - * int Driver-ID - * int local channel-number (0 ...) - * struct sk_buff *skb received Data - */ - void (*rcvcallb_skb)(int, int, struct sk_buff *); - - /* Status-Callback - * Parameters: - * isdn_ctrl* - * driver = Driver ID. - * command = One of above ISDN_STAT_... constants. - * arg = depending on status-type. - * num = depending on status-type. - */ - int (*statcallb)(isdn_ctrl*); - - /* Send command - * Parameters: - * isdn_ctrl* - * driver = Driver ID. - * command = One of above ISDN_CMD_... constants. - * arg = depending on command. - * num = depending on command. - */ - int (*command)(isdn_ctrl*); - - /* - * Send data using sk_buff's - * Parameters: - * int driverId - * int local channel-number (0...) - * int Flag: Need ACK for this packet. - * struct sk_buff *skb Data to send - */ - int (*writebuf_skb) (int, int, int, struct sk_buff *); - - /* Send raw D-Channel-Commands - * Parameters: - * u_char pointer data - * int length of data - * int driverId - * int local channel-number (0 ...) - */ - int (*writecmd)(const u_char __user *, int, int, int); - - /* Read raw Status replies - * u_char pointer data (volatile) - * int length of buffer - * int driverId - * int local channel-number (0 ...) - */ - int (*readstat)(u_char __user *, int, int, int); - - char id[20]; -} isdn_if; - -/* - * Function which must be called by lowlevel-driver at loadtime with - * the following fields of above struct set: - * - * channels Number of channels that will be supported. - * hl_hdrlen Space to preserve in sk_buff's when sending. Drivers, not - * supporting sk_buff's should set this to 0. - * command Address of Command-Handler. - * features Bitwise coded Features of this driver. (use ISDN_FEATURE_...) - * writebuf_skb Address of Skbuff-Send-Handler. - * writecmd " " D-Channel " which accepts raw D-Ch-Commands. - * readstat " " D-Channel " which delivers raw Status-Data. - * - * The linklevel-driver fills the following fields: - * - * channels Driver-ID assigned to this driver. (Must be used on all - * subsequent callbacks. - * rcvcallb_skb Address of handler for received Skbuff's. - * statcallb " " " for status-changes. - * - */ -extern int register_isdn(isdn_if*); -#include - -#endif /* __ISDNIF_H__ */ diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h deleted file mode 100644 index f6358558f9f5..000000000000 --- a/include/linux/wanrouter.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * wanrouter.h Legacy declarations kept around until X25 is removed - */ - -#ifndef _ROUTER_H -#define _ROUTER_H - -#include - -#endif /* _ROUTER_H */ diff --git a/include/uapi/linux/isdn.h b/include/uapi/linux/isdn.h deleted file mode 100644 index f371fd52ed75..000000000000 --- a/include/uapi/linux/isdn.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: isdn.h,v 1.125.2.3 2004/02/10 01:07:14 keil Exp $ - * - * Main header for the Linux ISDN subsystem (linklevel). - * - * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _UAPI__ISDN_H__ -#define _UAPI__ISDN_H__ - -#include -#include - -#define ISDN_MAX_DRIVERS 32 -#define ISDN_MAX_CHANNELS 64 - -/* New ioctl-codes */ -#define IIOCNETAIF _IO('I',1) -#define IIOCNETDIF _IO('I',2) -#define IIOCNETSCF _IO('I',3) -#define IIOCNETGCF _IO('I',4) -#define IIOCNETANM _IO('I',5) -#define IIOCNETDNM _IO('I',6) -#define IIOCNETGNM _IO('I',7) -#define IIOCGETSET _IO('I',8) /* no longer supported */ -#define IIOCSETSET _IO('I',9) /* no longer supported */ -#define IIOCSETVER _IO('I',10) -#define IIOCNETHUP _IO('I',11) -#define IIOCSETGST _IO('I',12) -#define IIOCSETBRJ _IO('I',13) -#define IIOCSIGPRF _IO('I',14) -#define IIOCGETPRF _IO('I',15) -#define IIOCSETPRF _IO('I',16) -#define IIOCGETMAP _IO('I',17) -#define IIOCSETMAP _IO('I',18) -#define IIOCNETASL _IO('I',19) -#define IIOCNETDIL _IO('I',20) -#define IIOCGETCPS _IO('I',21) -#define IIOCGETDVR _IO('I',22) -#define IIOCNETLCR _IO('I',23) /* dwabc ioctl for LCR from isdnlog */ -#define IIOCNETDWRSET _IO('I',24) /* dwabc ioctl to reset abc-values to default on a net-interface */ - -#define IIOCNETALN _IO('I',32) -#define IIOCNETDLN _IO('I',33) - -#define IIOCNETGPN _IO('I',34) - -#define IIOCDBGVAR _IO('I',127) - -#define IIOCDRVCTL _IO('I',128) - -/* cisco hdlck device private ioctls */ -#define SIOCGKEEPPERIOD (SIOCDEVPRIVATE + 0) -#define SIOCSKEEPPERIOD (SIOCDEVPRIVATE + 1) -#define SIOCGDEBSERINT (SIOCDEVPRIVATE + 2) -#define SIOCSDEBSERINT (SIOCDEVPRIVATE + 3) - -/* Packet encapsulations for net-interfaces */ -#define ISDN_NET_ENCAP_ETHER 0 -#define ISDN_NET_ENCAP_RAWIP 1 -#define ISDN_NET_ENCAP_IPTYP 2 -#define ISDN_NET_ENCAP_CISCOHDLC 3 /* Without SLARP and keepalive */ -#define ISDN_NET_ENCAP_SYNCPPP 4 -#define ISDN_NET_ENCAP_UIHDLC 5 -#define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */ -#define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt */ -#define ISDN_NET_ENCAP_MAX_ENCAP ISDN_NET_ENCAP_X25IFACE - -/* Facility which currently uses an ISDN-channel */ -#define ISDN_USAGE_NONE 0 -#define ISDN_USAGE_RAW 1 -#define ISDN_USAGE_MODEM 2 -#define ISDN_USAGE_NET 3 -#define ISDN_USAGE_VOICE 4 -#define ISDN_USAGE_FAX 5 -#define ISDN_USAGE_MASK 7 /* Mask to get plain usage */ -#define ISDN_USAGE_DISABLED 32 /* This bit is set, if channel is disabled */ -#define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */ -#define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */ - -#define ISDN_MODEM_NUMREG 24 /* Number of Modem-Registers */ -#define ISDN_LMSNLEN 255 /* Length of tty's Listen-MSN string */ -#define ISDN_CMSGLEN 50 /* Length of CONNECT-Message to add for Modem */ - -#define ISDN_MSNLEN 32 -#define NET_DV 0x06 /* Data version for isdn_net_ioctl_cfg */ -#define TTY_DV 0x06 /* Data version for iprofd etc. */ - -#define INF_DV 0x01 /* Data version for /dev/isdninfo */ - -typedef struct { - char drvid[25]; - unsigned long arg; -} isdn_ioctl_struct; - -typedef struct { - char name[10]; - char phone[ISDN_MSNLEN]; - int outgoing; -} isdn_net_ioctl_phone; - -typedef struct { - char name[10]; /* Name of interface */ - char master[10]; /* Name of Master for Bundling */ - char slave[10]; /* Name of Slave for Bundling */ - char eaz[256]; /* EAZ/MSN */ - char drvid[25]; /* DriverId for Bindings */ - int onhtime; /* Hangup-Timeout */ - int charge; /* Charge-Units */ - int l2_proto; /* Layer-2 protocol */ - int l3_proto; /* Layer-3 protocol */ - int p_encap; /* Encapsulation */ - int exclusive; /* Channel, if bound exclusive */ - int dialmax; /* Dial Retry-Counter */ - int slavedelay; /* Delay until slave starts up */ - int cbdelay; /* Delay before Callback */ - int chargehup; /* Flag: Charge-Hangup */ - int ihup; /* Flag: Hangup-Timeout on incoming line */ - int secure; /* Flag: Secure */ - int callback; /* Flag: Callback */ - int cbhup; /* Flag: Reject Call before Callback */ - int pppbind; /* ippp device for bindings */ - int chargeint; /* Use fixed charge interval length */ - int triggercps; /* BogoCPS needed for triggering slave */ - int dialtimeout; /* Dial-Timeout */ - int dialwait; /* Time to wait after failed dial */ - int dialmode; /* Flag: off / on / auto */ -} isdn_net_ioctl_cfg; - -#define ISDN_NET_DIALMODE_MASK 0xC0 /* bits for status */ -#define ISDN_NET_DM_OFF 0x00 /* this interface is stopped */ -#define ISDN_NET_DM_MANUAL 0x40 /* this interface is on (manual) */ -#define ISDN_NET_DM_AUTO 0x80 /* this interface is autodial */ -#define ISDN_NET_DIALMODE(x) ((&(x))->flags & ISDN_NET_DIALMODE_MASK) - - -#endif /* _UAPI__ISDN_H__ */ diff --git a/include/uapi/linux/isdn_divertif.h b/include/uapi/linux/isdn_divertif.h deleted file mode 100644 index 0a17bb1bcb1b..000000000000 --- a/include/uapi/linux/isdn_divertif.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: isdn_divertif.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $ - * - * Header for the diversion supplementary interface for i4l. - * - * Author Werner Cornelius (werner@titro.de) - * Copyright 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 _UAPI_LINUX_ISDN_DIVERTIF_H -#define _UAPI_LINUX_ISDN_DIVERTIF_H - -/***********************************************************/ -/* magic value is also used to control version information */ -/***********************************************************/ -#define DIVERT_IF_MAGIC 0x25873401 -#define DIVERT_CMD_REG 0x00 /* register command */ -#define DIVERT_CMD_REL 0x01 /* release command */ -#define DIVERT_NO_ERR 0x00 /* return value no error */ -#define DIVERT_CMD_ERR 0x01 /* invalid cmd */ -#define DIVERT_VER_ERR 0x02 /* magic/version invalid */ -#define DIVERT_REG_ERR 0x03 /* module already registered */ -#define DIVERT_REL_ERR 0x04 /* module not registered */ -#define DIVERT_REG_NAME isdn_register_divert - - -#endif /* _UAPI_LINUX_ISDN_DIVERTIF_H */ diff --git a/include/uapi/linux/isdn_ppp.h b/include/uapi/linux/isdn_ppp.h deleted file mode 100644 index 0bdc4efaacb2..000000000000 --- a/include/uapi/linux/isdn_ppp.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */ -/* Linux ISDN subsystem, sync PPP, interface to ipppd - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _UAPI_LINUX_ISDN_PPP_H -#define _UAPI_LINUX_ISDN_PPP_H - -#define CALLTYPE_INCOMING 0x1 -#define CALLTYPE_OUTGOING 0x2 -#define CALLTYPE_CALLBACK 0x4 - -#define IPPP_VERSION "2.2.0" - -struct pppcallinfo -{ - int calltype; - unsigned char local_num[64]; - unsigned char remote_num[64]; - int charge_units; -}; - -#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo) -#define PPPIOCBUNDLE _IOW('t',129,int) -#define PPPIOCGMPFLAGS _IOR('t',130,int) -#define PPPIOCSMPFLAGS _IOW('t',131,int) -#define PPPIOCSMPMTU _IOW('t',132,int) -#define PPPIOCSMPMRU _IOW('t',133,int) -#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8]) -#define PPPIOCSCOMPRESSOR _IOW('t',135,int) -#define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] ) - - -#define SC_MP_PROT 0x00000200 -#define SC_REJ_MP_PROT 0x00000400 -#define SC_OUT_SHORT_SEQ 0x00000800 -#define SC_IN_SHORT_SEQ 0x00004000 - -#define SC_DECOMP_ON 0x01 -#define SC_COMP_ON 0x02 -#define SC_DECOMP_DISCARD 0x04 -#define SC_COMP_DISCARD 0x08 -#define SC_LINK_DECOMP_ON 0x10 -#define SC_LINK_COMP_ON 0x20 -#define SC_LINK_DECOMP_DISCARD 0x40 -#define SC_LINK_COMP_DISCARD 0x80 - -#define ISDN_PPP_COMP_MAX_OPTIONS 16 - -#define IPPP_COMP_FLAG_XMIT 0x1 -#define IPPP_COMP_FLAG_LINK 0x2 - -struct isdn_ppp_comp_data { - int num; - unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS]; - int optlen; - int flags; -}; - -#endif /* _UAPI_LINUX_ISDN_PPP_H */ diff --git a/include/uapi/linux/isdnif.h b/include/uapi/linux/isdnif.h deleted file mode 100644 index 611a69196738..000000000000 --- a/include/uapi/linux/isdnif.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */ -/* $Id: isdnif.h,v 1.43.2.2 2004/01/12 23:08:35 keil Exp $ - * - * Linux ISDN subsystem - * Definition of the interface between the subsystem and its low-level drivers. - * - * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _UAPI__ISDNIF_H__ -#define _UAPI__ISDNIF_H__ - - -/* - * Values for general protocol-selection - */ -#define ISDN_PTYPE_UNKNOWN 0 /* Protocol undefined */ -#define ISDN_PTYPE_1TR6 1 /* german 1TR6-protocol */ -#define ISDN_PTYPE_EURO 2 /* EDSS1-protocol */ -#define ISDN_PTYPE_LEASED 3 /* for leased lines */ -#define ISDN_PTYPE_NI1 4 /* US NI-1 protocol */ -#define ISDN_PTYPE_MAX 7 /* Max. 8 Protocols */ - -/* - * Values for Layer-2-protocol-selection - */ -#define ISDN_PROTO_L2_X75I 0 /* X75/LAPB with I-Frames */ -#define ISDN_PROTO_L2_X75UI 1 /* X75/LAPB with UI-Frames */ -#define ISDN_PROTO_L2_X75BUI 2 /* X75/LAPB with UI-Frames */ -#define ISDN_PROTO_L2_HDLC 3 /* HDLC */ -#define ISDN_PROTO_L2_TRANS 4 /* Transparent (Voice) */ -#define ISDN_PROTO_L2_X25DTE 5 /* X25/LAPB DTE mode */ -#define ISDN_PROTO_L2_X25DCE 6 /* X25/LAPB DCE mode */ -#define ISDN_PROTO_L2_V11096 7 /* V.110 bitrate adaption 9600 Baud */ -#define ISDN_PROTO_L2_V11019 8 /* V.110 bitrate adaption 19200 Baud */ -#define ISDN_PROTO_L2_V11038 9 /* V.110 bitrate adaption 38400 Baud */ -#define ISDN_PROTO_L2_MODEM 10 /* Analog Modem on Board */ -#define ISDN_PROTO_L2_FAX 11 /* Fax Group 2/3 */ -#define ISDN_PROTO_L2_HDLC_56K 12 /* HDLC 56k */ -#define ISDN_PROTO_L2_MAX 15 /* Max. 16 Protocols */ - -/* - * Values for Layer-3-protocol-selection - */ -#define ISDN_PROTO_L3_TRANS 0 /* Transparent */ -#define ISDN_PROTO_L3_TRANSDSP 1 /* Transparent with DSP */ -#define ISDN_PROTO_L3_FCLASS2 2 /* Fax Group 2/3 CLASS 2 */ -#define ISDN_PROTO_L3_FCLASS1 3 /* Fax Group 2/3 CLASS 1 */ -#define ISDN_PROTO_L3_MAX 7 /* Max. 8 Protocols */ - - -#endif /* _UAPI__ISDNIF_H__ */ diff --git a/include/uapi/linux/wanrouter.h b/include/uapi/linux/wanrouter.h deleted file mode 100644 index 2f1216d00caa..000000000000 --- a/include/uapi/linux/wanrouter.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * wanrouter.h Legacy declarations kept around until X25 is removed - */ - -#ifndef _UAPI_ROUTER_H -#define _UAPI_ROUTER_H - -/* 'state' defines */ -enum wan_states -{ - WAN_UNCONFIGURED, /* link/channel is not configured */ - WAN_DISCONNECTED, /* link/channel is disconnected */ - WAN_CONNECTING, /* connection is in progress */ - WAN_CONNECTED /* link/channel is operational */ -}; - -#endif /* _UAPI_ROUTER_H */ -- cgit v1.2.3 From 99c2aa151a7182c58f9477a376304c538d9cc5ab Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Apr 2019 22:57:08 +0200 Subject: isdn: hdlc: move into mISDN The last remnant of the isdn4linux interface is now the isdnhdlc support, used by the netjet driver. Move it next to that driver. Signed-off-by: Arnd Bergmann --- drivers/isdn/Makefile | 1 - drivers/isdn/hardware/mISDN/Kconfig | 7 +- drivers/isdn/hardware/mISDN/Makefile | 2 + drivers/isdn/hardware/mISDN/isdnhdlc.c | 630 +++++++++++++++++++++++++++++++++ drivers/isdn/hardware/mISDN/isdnhdlc.h | 82 +++++ drivers/isdn/hardware/mISDN/netjet.c | 2 +- drivers/isdn/i4l/Makefile | 6 - drivers/isdn/i4l/isdnhdlc.c | 630 --------------------------------- include/linux/isdn/hdlc.h | 82 ----- 9 files changed, 720 insertions(+), 722 deletions(-) create mode 100644 drivers/isdn/hardware/mISDN/isdnhdlc.c create mode 100644 drivers/isdn/hardware/mISDN/isdnhdlc.h delete mode 100644 drivers/isdn/i4l/Makefile delete mode 100644 drivers/isdn/i4l/isdnhdlc.c delete mode 100644 include/linux/isdn/hdlc.h (limited to 'drivers/isdn') diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 379b4a03c321..f2a529c5a511 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -3,7 +3,6 @@ # Object files in subdirectories -obj-$(CONFIG_ISDN_I4L) += i4l/ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_MISDN) += mISDN/ obj-$(CONFIG_ISDN) += hardware/ diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index a7a34a85b970..304f50c08da2 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -79,11 +79,14 @@ config MISDN_NETJET depends on PCI depends on TTY select MISDN_IPAC - select ISDN_HDLC - select ISDN_I4L + select MISDN_HDLC help Enable support for Traverse Technologies NETJet PCI cards. +config MISDN_HDLC + tristate + select CRC_CCITT + select BITREVERSE config MISDN_IPAC tristate diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 422f9fd8ab9a..3f50f8c4753f 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_MISDN_NETJET) += netjet.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o + +obj-$(CONFIG_MISDN_HDLC) += isdnhdlc.o diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.c b/drivers/isdn/hardware/mISDN/isdnhdlc.c new file mode 100644 index 000000000000..3a8b562e63b1 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/isdnhdlc.c @@ -0,0 +1,630 @@ +/* + * isdnhdlc.c -- General purpose ISDN HDLC decoder. + * + * Copyright (C) + * 2009 Karsten Keil + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include "isdnhdlc.h" + +/*-------------------------------------------------------------------*/ + +MODULE_AUTHOR("Wolfgang Mües , " + "Frode Isaksen , " + "Kai Germaschewski "); +MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); +MODULE_LICENSE("GPL"); + +/*-------------------------------------------------------------------*/ + +enum { + HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, + HDLC_GET_DATA, HDLC_FAST_FLAG +}; + +enum { + HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, + HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, + HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE +}; + +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) +{ + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); + hdlc->state = HDLC_GET_DATA; + if (features & HDLC_56KBIT) + hdlc->do_adapt56 = 1; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; +} +EXPORT_SYMBOL(isdnhdlc_out_init); + +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) +{ + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); + if (features & HDLC_DCHANNEL) { + hdlc->dchannel = 1; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + hdlc->dchannel = 0; + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->ffvalue = 0x7e; + } + hdlc->cbin = 0x7e; + if (features & HDLC_56KBIT) { + hdlc->do_adapt56 = 1; + hdlc->state = HDLC_SENDFLAG_B0; + } else + hdlc->data_bits = 8; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; +} +EXPORT_SYMBOL(isdnhdlc_rcv_init); + +static int +check_frame(struct isdnhdlc_vars *hdlc) +{ + int status; + + if (hdlc->dstpos < 2) /* too small - framing error */ + status = -HDLC_FRAMING_ERROR; + else if (hdlc->crc != 0xf0b8) /* crc error */ + status = -HDLC_CRC_ERROR; + else { + /* remove CRC */ + hdlc->dstpos -= 2; + /* good frame */ + status = hdlc->dstpos; + } + return status; +} + +/* + isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. + + The source buffer is scanned for valid HDLC frames looking for + flags (01111110) to indicate the start of a frame. If the start of + the frame is found, the bit stuffing is removed (0 after 5 1's). + When a new flag is found, the complete frame has been received + and the CRC is checked. + If a valid frame is found, the function returns the frame length + excluding the CRC with the bit HDLC_END_OF_FRAME set. + If the beginning of a valid frame is found, the function returns + the length. + If a framing error is found (too many 1s and not a flag) the function + returns the length with the bit HDLC_FRAMING_ERROR set. + If a CRC error is found the function returns the length with the + bit HDLC_CRC_ERROR set. + If the frame length exceeds the destination buffer size, the function + returns the length with the bit HDLC_LENGTH_ERROR set. + + src - source buffer + slen - source buffer length + count - number of bytes removed (decoded) from the source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of decoded bytes in the destination buffer and status + flag. +*/ +int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, + int *count, u8 *dst, int dsize) +{ + int status = 0; + + static const unsigned char fast_flag[] = { + 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f + }; + + static const unsigned char fast_flag_value[] = { + 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f + }; + + static const unsigned char fast_abort[] = { + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff + }; + +#define handle_fast_flag(h) \ + do { \ + if (h->cbin == fast_flag[h->bit_shift]) { \ + h->ffvalue = fast_flag_value[h->bit_shift]; \ + h->state = HDLC_FAST_FLAG; \ + h->ffbit_shift = h->bit_shift; \ + h->bit_shift = 1; \ + } else { \ + h->state = HDLC_GET_DATA; \ + h->data_received = 0; \ + } \ + } while (0) + +#define handle_abort(h) \ + do { \ + h->shift_reg = fast_abort[h->ffbit_shift - 1]; \ + h->hdlc_bits1 = h->ffbit_shift - 2; \ + if (h->hdlc_bits1 < 0) \ + h->hdlc_bits1 = 0; \ + h->data_bits = h->ffbit_shift - 1; \ + h->state = HDLC_GET_DATA; \ + h->data_received = 0; \ + } while (0) + + *count = slen; + + while (slen > 0) { + if (hdlc->bit_shift == 0) { + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + hdlc->cbin = bitrev8(*src++); + else + hdlc->cbin = *src++; + slen--; + hdlc->bit_shift = 8; + if (hdlc->do_adapt56) + hdlc->bit_shift--; + } + + switch (hdlc->state) { + case STOPPED: + return 0; + case HDLC_FAST_IDLE: + if (hdlc->cbin == 0xff) { + hdlc->bit_shift = 0; + break; + } + hdlc->state = HDLC_GET_FLAG_B0; + hdlc->hdlc_bits1 = 0; + hdlc->bit_shift = 8; + break; + case HDLC_GET_FLAG_B0: + if (!(hdlc->cbin & 0x80)) { + hdlc->state = HDLC_GETFLAG_B1A6; + hdlc->hdlc_bits1 = 0; + } else { + if ((!hdlc->do_adapt56) && + (++hdlc->hdlc_bits1 >= 8) && + (hdlc->bit_shift == 1)) + hdlc->state = HDLC_FAST_IDLE; + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_GETFLAG_B1A6: + if (hdlc->cbin & 0x80) { + hdlc->hdlc_bits1++; + if (hdlc->hdlc_bits1 == 6) + hdlc->state = HDLC_GETFLAG_B7; + } else + hdlc->hdlc_bits1 = 0; + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_GETFLAG_B7: + if (hdlc->cbin & 0x80) { + hdlc->state = HDLC_GET_FLAG_B0; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->data_received = 0; + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_GET_DATA: + if (hdlc->cbin & 0x80) { + hdlc->hdlc_bits1++; + switch (hdlc->hdlc_bits1) { + case 6: + break; + case 7: + if (hdlc->data_received) + /* bad frame */ + status = -HDLC_FRAMING_ERROR; + if (!hdlc->do_adapt56) { + if (hdlc->cbin == fast_abort + [hdlc->bit_shift + 1]) { + hdlc->state = + HDLC_FAST_IDLE; + hdlc->bit_shift = 1; + break; + } + } else + hdlc->state = HDLC_GET_FLAG_B0; + break; + default: + hdlc->shift_reg >>= 1; + hdlc->shift_reg |= 0x80; + hdlc->data_bits++; + break; + } + } else { + switch (hdlc->hdlc_bits1) { + case 5: + break; + case 6: + if (hdlc->data_received) + status = check_frame(hdlc); + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->data_bits = 0; + if (!hdlc->do_adapt56) + handle_fast_flag(hdlc); + else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + break; + default: + hdlc->shift_reg >>= 1; + hdlc->data_bits++; + break; + } + hdlc->hdlc_bits1 = 0; + } + if (status) { + hdlc->dstpos = 0; + *count -= slen; + hdlc->cbin <<= 1; + hdlc->bit_shift--; + return status; + } + if (hdlc->data_bits == 8) { + hdlc->data_bits = 0; + hdlc->data_received = 1; + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); + + /* good byte received */ + if (hdlc->dstpos < dsize) + dst[hdlc->dstpos++] = hdlc->shift_reg; + else { + /* frame too long */ + status = -HDLC_LENGTH_ERROR; + hdlc->dstpos = 0; + } + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_FAST_FLAG: + if (hdlc->cbin == hdlc->ffvalue) { + hdlc->bit_shift = 0; + break; + } else { + if (hdlc->cbin == 0xff) { + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift = 0; + } else if (hdlc->ffbit_shift == 8) { + hdlc->state = HDLC_GETFLAG_B7; + break; + } else + handle_abort(hdlc); + } + break; + default: + break; + } + } + *count -= slen; + return 0; +} +EXPORT_SYMBOL(isdnhdlc_decode); +/* + isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. + + The bit stream starts with a beginning flag (01111110). After + that each byte is added to the bit stream with bit stuffing added + (0 after 5 1's). + When the last byte has been removed from the source buffer, the + CRC (2 bytes is added) and the frame terminates with the ending flag. + For the dchannel, the idle character (all 1's) is also added at the end. + If this function is called with empty source buffer (slen=0), flags or + idle character will be generated. + + src - source buffer + slen - source buffer length + count - number of bytes removed (encoded) from source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of encoded bytes in the destination buffer +*/ +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, + int *count, u8 *dst, int dsize) +{ + static const unsigned char xfast_flag_value[] = { + 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e + }; + + int len = 0; + + *count = slen; + + /* special handling for one byte frames */ + if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) + hdlc->state = HDLC_SENDFLAG_ONE; + while (dsize > 0) { + if (hdlc->bit_shift == 0) { + if (slen && !hdlc->do_closing) { + hdlc->shift_reg = *src++; + slen--; + if (slen == 0) + /* closing sequence, CRC + flag(s) */ + hdlc->do_closing = 1; + hdlc->bit_shift = 8; + } else { + if (hdlc->state == HDLC_SEND_DATA) { + if (hdlc->data_received) { + hdlc->state = HDLC_SEND_CRC1; + hdlc->crc ^= 0xffff; + hdlc->bit_shift = 8; + hdlc->shift_reg = + hdlc->crc & 0xff; + } else if (!hdlc->do_adapt56) + hdlc->state = + HDLC_SEND_FAST_FLAG; + else + hdlc->state = + HDLC_SENDFLAG_B0; + } + + } + } + + switch (hdlc->state) { + case STOPPED: + while (dsize--) + *dst++ = 0xff; + return dsize; + case HDLC_SEND_FAST_FLAG: + hdlc->do_closing = 0; + if (slen == 0) { + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->ffvalue); + else + *dst++ = hdlc->ffvalue; + len++; + dsize--; + break; + } + /* fall through */ + case HDLC_SENDFLAG_ONE: + if (hdlc->bit_shift == 8) { + hdlc->cbin = hdlc->ffvalue >> + (8 - hdlc->data_bits); + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SENDFLAG_B0: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->hdlc_bits1 = 0; + hdlc->state = HDLC_SENDFLAG_B1A6; + break; + case HDLC_SENDFLAG_B1A6: + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->cbin++; + if (++hdlc->hdlc_bits1 == 6) + hdlc->state = HDLC_SENDFLAG_B7; + break; + case HDLC_SENDFLAG_B7: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if (slen == 0) { + hdlc->state = HDLC_SENDFLAG_B0; + break; + } + if (hdlc->bit_shift == 8) { + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SEND_FIRST_FLAG: + hdlc->data_received = 1; + if (hdlc->data_bits == 8) { + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + break; + } + hdlc->cbin <<= 1; + hdlc->data_bits++; + if (hdlc->shift_reg & 0x01) + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if (hdlc->bit_shift == 0) { + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + } + break; + case HDLC_SEND_DATA: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if (hdlc->hdlc_bits1 == 5) { + hdlc->hdlc_bits1 = 0; + break; + } + if (hdlc->bit_shift == 8) + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); + if (hdlc->shift_reg & 0x01) { + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + break; + case HDLC_SEND_CRC1: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if (hdlc->hdlc_bits1 == 5) { + hdlc->hdlc_bits1 = 0; + break; + } + if (hdlc->shift_reg & 0x01) { + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if (hdlc->bit_shift == 0) { + hdlc->shift_reg = (hdlc->crc >> 8); + hdlc->state = HDLC_SEND_CRC2; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CRC2: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if (hdlc->hdlc_bits1 == 5) { + hdlc->hdlc_bits1 = 0; + break; + } + if (hdlc->shift_reg & 0x01) { + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if (hdlc->bit_shift == 0) { + hdlc->shift_reg = 0x7e; + hdlc->state = HDLC_SEND_CLOSING_FLAG; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CLOSING_FLAG: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if (hdlc->hdlc_bits1 == 5) { + hdlc->hdlc_bits1 = 0; + break; + } + if (hdlc->shift_reg & 0x01) + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if (hdlc->bit_shift == 0) { + hdlc->ffvalue = + xfast_flag_value[hdlc->data_bits]; + if (hdlc->dchannel) { + hdlc->ffvalue = 0x7e; + hdlc->state = HDLC_SEND_IDLE1; + hdlc->bit_shift = 8-hdlc->data_bits; + if (hdlc->bit_shift == 0) + hdlc->state = + HDLC_SEND_FAST_IDLE; + } else { + if (!hdlc->do_adapt56) { + hdlc->state = + HDLC_SEND_FAST_FLAG; + hdlc->data_received = 0; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + hdlc->data_received = 0; + } + /* Finished this frame, send flags */ + if (dsize > 1) + dsize = 1; + } + } + break; + case HDLC_SEND_IDLE1: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + hdlc->bit_shift--; + if (hdlc->bit_shift == 0) { + hdlc->state = HDLC_SEND_FAST_IDLE; + hdlc->bit_shift = 0; + } + break; + case HDLC_SEND_FAST_IDLE: + hdlc->do_closing = 0; + hdlc->cbin = 0xff; + hdlc->data_bits = 8; + if (hdlc->bit_shift == 8) { + hdlc->cbin = 0x7e; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; + hdlc->bit_shift = 0; + hdlc->data_bits = 0; + len++; + dsize = 0; + } + break; + default: + break; + } + if (hdlc->do_adapt56) { + if (hdlc->data_bits == 7) { + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + } + } + if (hdlc->data_bits == 8) { + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; + hdlc->data_bits = 0; + len++; + dsize--; + } + } + *count -= slen; + + return len; +} +EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.h b/drivers/isdn/hardware/mISDN/isdnhdlc.h new file mode 100644 index 000000000000..96521370c782 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/isdnhdlc.h @@ -0,0 +1,82 @@ +/* + * hdlc.h -- General purpose ISDN HDLC decoder. + * + * Implementation of a HDLC decoder/encoder in software. + * Necessary because some ISDN devices don't have HDLC + * controllers. + * + * Copyright (C) + * 2009 Karsten Keil + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ISDNHDLC_H__ +#define __ISDNHDLC_H__ + +struct isdnhdlc_vars { + int bit_shift; + int hdlc_bits1; + int data_bits; + int ffbit_shift; /* encoding only */ + int state; + int dstpos; + + u16 crc; + + u8 cbin; + u8 shift_reg; + u8 ffvalue; + + /* set if transferring data */ + u32 data_received:1; + /* set if D channel (send idle instead of flags) */ + u32 dchannel:1; + /* set if 56K adaptation */ + u32 do_adapt56:1; + /* set if in closing phase (need to send CRC + flag) */ + u32 do_closing:1; + /* set if data is bitreverse */ + u32 do_bitreverse:1; +}; + +/* Feature Flags */ +#define HDLC_56KBIT 0x01 +#define HDLC_DCHANNEL 0x02 +#define HDLC_BITREVERSE 0x04 + +/* + The return value from isdnhdlc_decode is + the frame length, 0 if no complete frame was decoded, + or a negative error number +*/ +#define HDLC_FRAMING_ERROR 1 +#define HDLC_CRC_ERROR 2 +#define HDLC_LENGTH_ERROR 3 + +extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features); + +extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, + int slen, int *count, u8 *dst, int dsize); + +extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features); + +extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, + u16 slen, int *count, u8 *dst, int dsize); + +#endif /* __ISDNHDLC_H__ */ diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 2b317cb63d06..93a2d361eda5 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -29,7 +29,7 @@ #include "ipac.h" #include "iohelper.h" #include "netjet.h" -#include +#include "isdnhdlc.h" #define NETJET_REV "2.0" diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile deleted file mode 100644 index 11fe697739d5..000000000000 --- a/drivers/isdn/i4l/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the kernel ISDN subsystem and device drivers. - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c deleted file mode 100644 index 027d1c590679..000000000000 --- a/drivers/isdn/i4l/isdnhdlc.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * isdnhdlc.c -- General purpose ISDN HDLC decoder. - * - * Copyright (C) - * 2009 Karsten Keil - * 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -/*-------------------------------------------------------------------*/ - -MODULE_AUTHOR("Wolfgang Mües , " - "Frode Isaksen , " - "Kai Germaschewski "); -MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); -MODULE_LICENSE("GPL"); - -/*-------------------------------------------------------------------*/ - -enum { - HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, - HDLC_GET_DATA, HDLC_FAST_FLAG -}; - -enum { - HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE -}; - -void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) -{ - memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); - hdlc->state = HDLC_GET_DATA; - if (features & HDLC_56KBIT) - hdlc->do_adapt56 = 1; - if (features & HDLC_BITREVERSE) - hdlc->do_bitreverse = 1; -} -EXPORT_SYMBOL(isdnhdlc_out_init); - -void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) -{ - memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); - if (features & HDLC_DCHANNEL) { - hdlc->dchannel = 1; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - hdlc->dchannel = 0; - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->ffvalue = 0x7e; - } - hdlc->cbin = 0x7e; - if (features & HDLC_56KBIT) { - hdlc->do_adapt56 = 1; - hdlc->state = HDLC_SENDFLAG_B0; - } else - hdlc->data_bits = 8; - if (features & HDLC_BITREVERSE) - hdlc->do_bitreverse = 1; -} -EXPORT_SYMBOL(isdnhdlc_rcv_init); - -static int -check_frame(struct isdnhdlc_vars *hdlc) -{ - int status; - - if (hdlc->dstpos < 2) /* too small - framing error */ - status = -HDLC_FRAMING_ERROR; - else if (hdlc->crc != 0xf0b8) /* crc error */ - status = -HDLC_CRC_ERROR; - else { - /* remove CRC */ - hdlc->dstpos -= 2; - /* good frame */ - status = hdlc->dstpos; - } - return status; -} - -/* - isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. - - The source buffer is scanned for valid HDLC frames looking for - flags (01111110) to indicate the start of a frame. If the start of - the frame is found, the bit stuffing is removed (0 after 5 1's). - When a new flag is found, the complete frame has been received - and the CRC is checked. - If a valid frame is found, the function returns the frame length - excluding the CRC with the bit HDLC_END_OF_FRAME set. - If the beginning of a valid frame is found, the function returns - the length. - If a framing error is found (too many 1s and not a flag) the function - returns the length with the bit HDLC_FRAMING_ERROR set. - If a CRC error is found the function returns the length with the - bit HDLC_CRC_ERROR set. - If the frame length exceeds the destination buffer size, the function - returns the length with the bit HDLC_LENGTH_ERROR set. - - src - source buffer - slen - source buffer length - count - number of bytes removed (decoded) from the source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of decoded bytes in the destination buffer and status - flag. -*/ -int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, - int *count, u8 *dst, int dsize) -{ - int status = 0; - - static const unsigned char fast_flag[] = { - 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f - }; - - static const unsigned char fast_flag_value[] = { - 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f - }; - - static const unsigned char fast_abort[] = { - 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff - }; - -#define handle_fast_flag(h) \ - do { \ - if (h->cbin == fast_flag[h->bit_shift]) { \ - h->ffvalue = fast_flag_value[h->bit_shift]; \ - h->state = HDLC_FAST_FLAG; \ - h->ffbit_shift = h->bit_shift; \ - h->bit_shift = 1; \ - } else { \ - h->state = HDLC_GET_DATA; \ - h->data_received = 0; \ - } \ - } while (0) - -#define handle_abort(h) \ - do { \ - h->shift_reg = fast_abort[h->ffbit_shift - 1]; \ - h->hdlc_bits1 = h->ffbit_shift - 2; \ - if (h->hdlc_bits1 < 0) \ - h->hdlc_bits1 = 0; \ - h->data_bits = h->ffbit_shift - 1; \ - h->state = HDLC_GET_DATA; \ - h->data_received = 0; \ - } while (0) - - *count = slen; - - while (slen > 0) { - if (hdlc->bit_shift == 0) { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - hdlc->cbin = bitrev8(*src++); - else - hdlc->cbin = *src++; - slen--; - hdlc->bit_shift = 8; - if (hdlc->do_adapt56) - hdlc->bit_shift--; - } - - switch (hdlc->state) { - case STOPPED: - return 0; - case HDLC_FAST_IDLE: - if (hdlc->cbin == 0xff) { - hdlc->bit_shift = 0; - break; - } - hdlc->state = HDLC_GET_FLAG_B0; - hdlc->hdlc_bits1 = 0; - hdlc->bit_shift = 8; - break; - case HDLC_GET_FLAG_B0: - if (!(hdlc->cbin & 0x80)) { - hdlc->state = HDLC_GETFLAG_B1A6; - hdlc->hdlc_bits1 = 0; - } else { - if ((!hdlc->do_adapt56) && - (++hdlc->hdlc_bits1 >= 8) && - (hdlc->bit_shift == 1)) - hdlc->state = HDLC_FAST_IDLE; - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_GETFLAG_B1A6: - if (hdlc->cbin & 0x80) { - hdlc->hdlc_bits1++; - if (hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_GETFLAG_B7; - } else - hdlc->hdlc_bits1 = 0; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_GETFLAG_B7: - if (hdlc->cbin & 0x80) { - hdlc->state = HDLC_GET_FLAG_B0; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->data_received = 0; - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_GET_DATA: - if (hdlc->cbin & 0x80) { - hdlc->hdlc_bits1++; - switch (hdlc->hdlc_bits1) { - case 6: - break; - case 7: - if (hdlc->data_received) - /* bad frame */ - status = -HDLC_FRAMING_ERROR; - if (!hdlc->do_adapt56) { - if (hdlc->cbin == fast_abort - [hdlc->bit_shift + 1]) { - hdlc->state = - HDLC_FAST_IDLE; - hdlc->bit_shift = 1; - break; - } - } else - hdlc->state = HDLC_GET_FLAG_B0; - break; - default: - hdlc->shift_reg >>= 1; - hdlc->shift_reg |= 0x80; - hdlc->data_bits++; - break; - } - } else { - switch (hdlc->hdlc_bits1) { - case 5: - break; - case 6: - if (hdlc->data_received) - status = check_frame(hdlc); - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->data_bits = 0; - if (!hdlc->do_adapt56) - handle_fast_flag(hdlc); - else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - break; - default: - hdlc->shift_reg >>= 1; - hdlc->data_bits++; - break; - } - hdlc->hdlc_bits1 = 0; - } - if (status) { - hdlc->dstpos = 0; - *count -= slen; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - return status; - } - if (hdlc->data_bits == 8) { - hdlc->data_bits = 0; - hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, - hdlc->shift_reg); - - /* good byte received */ - if (hdlc->dstpos < dsize) - dst[hdlc->dstpos++] = hdlc->shift_reg; - else { - /* frame too long */ - status = -HDLC_LENGTH_ERROR; - hdlc->dstpos = 0; - } - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_FAST_FLAG: - if (hdlc->cbin == hdlc->ffvalue) { - hdlc->bit_shift = 0; - break; - } else { - if (hdlc->cbin == 0xff) { - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift = 0; - } else if (hdlc->ffbit_shift == 8) { - hdlc->state = HDLC_GETFLAG_B7; - break; - } else - handle_abort(hdlc); - } - break; - default: - break; - } - } - *count -= slen; - return 0; -} -EXPORT_SYMBOL(isdnhdlc_decode); -/* - isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. - - The bit stream starts with a beginning flag (01111110). After - that each byte is added to the bit stream with bit stuffing added - (0 after 5 1's). - When the last byte has been removed from the source buffer, the - CRC (2 bytes is added) and the frame terminates with the ending flag. - For the dchannel, the idle character (all 1's) is also added at the end. - If this function is called with empty source buffer (slen=0), flags or - idle character will be generated. - - src - source buffer - slen - source buffer length - count - number of bytes removed (encoded) from source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of encoded bytes in the destination buffer -*/ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, - int *count, u8 *dst, int dsize) -{ - static const unsigned char xfast_flag_value[] = { - 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e - }; - - int len = 0; - - *count = slen; - - /* special handling for one byte frames */ - if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) - hdlc->state = HDLC_SENDFLAG_ONE; - while (dsize > 0) { - if (hdlc->bit_shift == 0) { - if (slen && !hdlc->do_closing) { - hdlc->shift_reg = *src++; - slen--; - if (slen == 0) - /* closing sequence, CRC + flag(s) */ - hdlc->do_closing = 1; - hdlc->bit_shift = 8; - } else { - if (hdlc->state == HDLC_SEND_DATA) { - if (hdlc->data_received) { - hdlc->state = HDLC_SEND_CRC1; - hdlc->crc ^= 0xffff; - hdlc->bit_shift = 8; - hdlc->shift_reg = - hdlc->crc & 0xff; - } else if (!hdlc->do_adapt56) - hdlc->state = - HDLC_SEND_FAST_FLAG; - else - hdlc->state = - HDLC_SENDFLAG_B0; - } - - } - } - - switch (hdlc->state) { - case STOPPED: - while (dsize--) - *dst++ = 0xff; - return dsize; - case HDLC_SEND_FAST_FLAG: - hdlc->do_closing = 0; - if (slen == 0) { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - *dst++ = bitrev8(hdlc->ffvalue); - else - *dst++ = hdlc->ffvalue; - len++; - dsize--; - break; - } - /* fall through */ - case HDLC_SENDFLAG_ONE: - if (hdlc->bit_shift == 8) { - hdlc->cbin = hdlc->ffvalue >> - (8 - hdlc->data_bits); - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SENDFLAG_B0: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->hdlc_bits1 = 0; - hdlc->state = HDLC_SENDFLAG_B1A6; - break; - case HDLC_SENDFLAG_B1A6: - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->cbin++; - if (++hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_SENDFLAG_B7; - break; - case HDLC_SENDFLAG_B7: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (slen == 0) { - hdlc->state = HDLC_SENDFLAG_B0; - break; - } - if (hdlc->bit_shift == 8) { - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SEND_FIRST_FLAG: - hdlc->data_received = 1; - if (hdlc->data_bits == 8) { - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - break; - } - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if (hdlc->bit_shift == 0) { - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - } - break; - case HDLC_SEND_DATA: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->bit_shift == 8) - hdlc->crc = crc_ccitt_byte(hdlc->crc, - hdlc->shift_reg); - if (hdlc->shift_reg & 0x01) { - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - break; - case HDLC_SEND_CRC1: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->shift_reg & 0x01) { - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if (hdlc->bit_shift == 0) { - hdlc->shift_reg = (hdlc->crc >> 8); - hdlc->state = HDLC_SEND_CRC2; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CRC2: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->shift_reg & 0x01) { - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if (hdlc->bit_shift == 0) { - hdlc->shift_reg = 0x7e; - hdlc->state = HDLC_SEND_CLOSING_FLAG; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CLOSING_FLAG: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if (hdlc->hdlc_bits1 == 5) { - hdlc->hdlc_bits1 = 0; - break; - } - if (hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if (hdlc->bit_shift == 0) { - hdlc->ffvalue = - xfast_flag_value[hdlc->data_bits]; - if (hdlc->dchannel) { - hdlc->ffvalue = 0x7e; - hdlc->state = HDLC_SEND_IDLE1; - hdlc->bit_shift = 8-hdlc->data_bits; - if (hdlc->bit_shift == 0) - hdlc->state = - HDLC_SEND_FAST_IDLE; - } else { - if (!hdlc->do_adapt56) { - hdlc->state = - HDLC_SEND_FAST_FLAG; - hdlc->data_received = 0; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - hdlc->data_received = 0; - } - /* Finished this frame, send flags */ - if (dsize > 1) - dsize = 1; - } - } - break; - case HDLC_SEND_IDLE1: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - hdlc->bit_shift--; - if (hdlc->bit_shift == 0) { - hdlc->state = HDLC_SEND_FAST_IDLE; - hdlc->bit_shift = 0; - } - break; - case HDLC_SEND_FAST_IDLE: - hdlc->do_closing = 0; - hdlc->cbin = 0xff; - hdlc->data_bits = 8; - if (hdlc->bit_shift == 8) { - hdlc->cbin = 0x7e; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - *dst++ = bitrev8(hdlc->cbin); - else - *dst++ = hdlc->cbin; - hdlc->bit_shift = 0; - hdlc->data_bits = 0; - len++; - dsize = 0; - } - break; - default: - break; - } - if (hdlc->do_adapt56) { - if (hdlc->data_bits == 7) { - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - } - } - if (hdlc->data_bits == 8) { - /* the code is for bitreverse streams */ - if (hdlc->do_bitreverse == 0) - *dst++ = bitrev8(hdlc->cbin); - else - *dst++ = hdlc->cbin; - hdlc->data_bits = 0; - len++; - dsize--; - } - } - *count -= slen; - - return len; -} -EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h deleted file mode 100644 index 96521370c782..000000000000 --- a/include/linux/isdn/hdlc.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * hdlc.h -- General purpose ISDN HDLC decoder. - * - * Implementation of a HDLC decoder/encoder in software. - * Necessary because some ISDN devices don't have HDLC - * controllers. - * - * Copyright (C) - * 2009 Karsten Keil - * 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ISDNHDLC_H__ -#define __ISDNHDLC_H__ - -struct isdnhdlc_vars { - int bit_shift; - int hdlc_bits1; - int data_bits; - int ffbit_shift; /* encoding only */ - int state; - int dstpos; - - u16 crc; - - u8 cbin; - u8 shift_reg; - u8 ffvalue; - - /* set if transferring data */ - u32 data_received:1; - /* set if D channel (send idle instead of flags) */ - u32 dchannel:1; - /* set if 56K adaptation */ - u32 do_adapt56:1; - /* set if in closing phase (need to send CRC + flag) */ - u32 do_closing:1; - /* set if data is bitreverse */ - u32 do_bitreverse:1; -}; - -/* Feature Flags */ -#define HDLC_56KBIT 0x01 -#define HDLC_DCHANNEL 0x02 -#define HDLC_BITREVERSE 0x04 - -/* - The return value from isdnhdlc_decode is - the frame length, 0 if no complete frame was decoded, - or a negative error number -*/ -#define HDLC_FRAMING_ERROR 1 -#define HDLC_CRC_ERROR 2 -#define HDLC_LENGTH_ERROR 3 - -extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features); - -extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, - int slen, int *count, u8 *dst, int dsize); - -extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features); - -extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, - u16 slen, int *count, u8 *dst, int dsize); - -#endif /* __ISDNHDLC_H__ */ -- cgit v1.2.3 From 6d97985072dc270032dc7a08631080bfd6253e82 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 20 Apr 2019 22:28:45 +0200 Subject: isdn: move capi drivers to staging I tried to find any indication of whether the capi drivers are still in use, and have not found anything from a long time ago. With public ISDN networks almost completely shut down over the past 12 months, there is very little you can actually do with this hardware. The main remaining use case would be to connect ISDN voice phones to an in-house installation with Asterisk or LCR, but anyone trying this in turn seems to be using either the mISDN driver stack, or out-of-tree drivers from the hardware vendors. I may of course have missed something, so I would suggest moving these three drivers (avm, hysdn, gigaset) into drivers/staging/ just in case someone still uses them. If nobody complains, we can remove them entirely in six months, or otherwise move the core code and any drivers that are still needed back into drivers/isdn. As Paul Bolle notes, he is still testing the gigaset driver as long as he can, but the Dutch ISDN network will be shut down in September 2019, which puts an end to that. Marcel Holtmann still maintains the Bluetooth CMTP profile and wants to keep that alive, so the actual CAPI subsystem code remains in place for now, after all other drivers are gone, CMTP and CAPI can be merged into a single driver directory. Cc: Marcel Holtmann Cc: Paul Bolle Signed-off-by: Arnd Bergmann --- MAINTAINERS | 20 +- drivers/isdn/Kconfig | 25 - drivers/isdn/Makefile | 2 - drivers/isdn/capi/Kconfig | 20 + drivers/isdn/capi/Makefile | 2 + drivers/isdn/gigaset/Kconfig | 62 - drivers/isdn/gigaset/Makefile | 17 - drivers/isdn/gigaset/asyncdata.c | 609 ------ drivers/isdn/gigaset/bas-gigaset.c | 2675 --------------------------- drivers/isdn/gigaset/capi.c | 2520 ------------------------- drivers/isdn/gigaset/common.c | 1156 ------------ drivers/isdn/gigaset/dummyll.c | 77 - drivers/isdn/gigaset/ev-layer.c | 1913 ------------------- drivers/isdn/gigaset/gigaset.h | 830 --------- drivers/isdn/gigaset/interface.c | 616 ------ drivers/isdn/gigaset/isocdata.c | 1009 ---------- drivers/isdn/gigaset/proc.c | 80 - drivers/isdn/gigaset/ser-gigaset.c | 799 -------- drivers/isdn/gigaset/usb-gigaset.c | 949 ---------- drivers/isdn/hardware/Kconfig | 8 - drivers/isdn/hardware/Makefile | 1 - drivers/isdn/hardware/avm/Kconfig | 65 - drivers/isdn/hardware/avm/Makefile | 12 - drivers/isdn/hardware/avm/avm_cs.c | 166 -- drivers/isdn/hardware/avm/avmcard.h | 581 ------ drivers/isdn/hardware/avm/b1.c | 804 -------- drivers/isdn/hardware/avm/b1dma.c | 981 ---------- drivers/isdn/hardware/avm/b1isa.c | 243 --- drivers/isdn/hardware/avm/b1pci.c | 416 ----- drivers/isdn/hardware/avm/b1pcmcia.c | 224 --- drivers/isdn/hardware/avm/c4.c | 1317 ------------- drivers/isdn/hardware/avm/t1isa.c | 594 ------ drivers/isdn/hardware/avm/t1pci.c | 259 --- drivers/isdn/hysdn/Kconfig | 15 - drivers/isdn/hysdn/Makefile | 12 - drivers/isdn/hysdn/boardergo.c | 445 ----- drivers/isdn/hysdn/boardergo.h | 100 - drivers/isdn/hysdn/hycapi.c | 785 -------- drivers/isdn/hysdn/hysdn_boot.c | 400 ---- drivers/isdn/hysdn/hysdn_defs.h | 282 --- drivers/isdn/hysdn/hysdn_init.c | 213 --- drivers/isdn/hysdn/hysdn_net.c | 326 ---- drivers/isdn/hysdn/hysdn_pof.h | 78 - drivers/isdn/hysdn/hysdn_procconf.c | 411 ---- drivers/isdn/hysdn/hysdn_proclog.c | 357 ---- drivers/isdn/hysdn/hysdn_sched.c | 197 -- drivers/isdn/hysdn/ince1pc.h | 134 -- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/isdn/Kconfig | 12 + drivers/staging/isdn/Makefile | 8 + drivers/staging/isdn/TODO | 22 + drivers/staging/isdn/avm/Kconfig | 65 + drivers/staging/isdn/avm/Makefile | 12 + drivers/staging/isdn/avm/avm_cs.c | 166 ++ drivers/staging/isdn/avm/avmcard.h | 581 ++++++ drivers/staging/isdn/avm/b1.c | 804 ++++++++ drivers/staging/isdn/avm/b1dma.c | 981 ++++++++++ drivers/staging/isdn/avm/b1isa.c | 243 +++ drivers/staging/isdn/avm/b1pci.c | 416 +++++ drivers/staging/isdn/avm/b1pcmcia.c | 224 +++ drivers/staging/isdn/avm/c4.c | 1317 +++++++++++++ drivers/staging/isdn/avm/t1isa.c | 594 ++++++ drivers/staging/isdn/avm/t1pci.c | 259 +++ drivers/staging/isdn/gigaset/Kconfig | 62 + drivers/staging/isdn/gigaset/Makefile | 17 + drivers/staging/isdn/gigaset/asyncdata.c | 609 ++++++ drivers/staging/isdn/gigaset/bas-gigaset.c | 2675 +++++++++++++++++++++++++++ drivers/staging/isdn/gigaset/capi.c | 2520 +++++++++++++++++++++++++ drivers/staging/isdn/gigaset/common.c | 1156 ++++++++++++ drivers/staging/isdn/gigaset/dummyll.c | 77 + drivers/staging/isdn/gigaset/ev-layer.c | 1913 +++++++++++++++++++ drivers/staging/isdn/gigaset/gigaset.h | 830 +++++++++ drivers/staging/isdn/gigaset/interface.c | 616 ++++++ drivers/staging/isdn/gigaset/isocdata.c | 1009 ++++++++++ drivers/staging/isdn/gigaset/proc.c | 80 + drivers/staging/isdn/gigaset/ser-gigaset.c | 799 ++++++++ drivers/staging/isdn/gigaset/usb-gigaset.c | 949 ++++++++++ drivers/staging/isdn/hysdn/Kconfig | 15 + drivers/staging/isdn/hysdn/Makefile | 12 + drivers/staging/isdn/hysdn/boardergo.c | 445 +++++ drivers/staging/isdn/hysdn/boardergo.h | 100 + drivers/staging/isdn/hysdn/hycapi.c | 785 ++++++++ drivers/staging/isdn/hysdn/hysdn_boot.c | 400 ++++ drivers/staging/isdn/hysdn/hysdn_defs.h | 282 +++ drivers/staging/isdn/hysdn/hysdn_init.c | 213 +++ drivers/staging/isdn/hysdn/hysdn_net.c | 326 ++++ drivers/staging/isdn/hysdn/hysdn_pof.h | 78 + drivers/staging/isdn/hysdn/hysdn_procconf.c | 411 ++++ drivers/staging/isdn/hysdn/hysdn_proclog.c | 357 ++++ drivers/staging/isdn/hysdn/hysdn_sched.c | 197 ++ drivers/staging/isdn/hysdn/ince1pc.h | 134 ++ 92 files changed, 22810 insertions(+), 22771 deletions(-) delete mode 100644 drivers/isdn/gigaset/Kconfig delete mode 100644 drivers/isdn/gigaset/Makefile delete mode 100644 drivers/isdn/gigaset/asyncdata.c delete mode 100644 drivers/isdn/gigaset/bas-gigaset.c delete mode 100644 drivers/isdn/gigaset/capi.c delete mode 100644 drivers/isdn/gigaset/common.c delete mode 100644 drivers/isdn/gigaset/dummyll.c delete mode 100644 drivers/isdn/gigaset/ev-layer.c delete mode 100644 drivers/isdn/gigaset/gigaset.h delete mode 100644 drivers/isdn/gigaset/interface.c delete mode 100644 drivers/isdn/gigaset/isocdata.c delete mode 100644 drivers/isdn/gigaset/proc.c delete mode 100644 drivers/isdn/gigaset/ser-gigaset.c delete mode 100644 drivers/isdn/gigaset/usb-gigaset.c delete mode 100644 drivers/isdn/hardware/Kconfig delete mode 100644 drivers/isdn/hardware/avm/Kconfig delete mode 100644 drivers/isdn/hardware/avm/Makefile delete mode 100644 drivers/isdn/hardware/avm/avm_cs.c delete mode 100644 drivers/isdn/hardware/avm/avmcard.h delete mode 100644 drivers/isdn/hardware/avm/b1.c delete mode 100644 drivers/isdn/hardware/avm/b1dma.c delete mode 100644 drivers/isdn/hardware/avm/b1isa.c delete mode 100644 drivers/isdn/hardware/avm/b1pci.c delete mode 100644 drivers/isdn/hardware/avm/b1pcmcia.c delete mode 100644 drivers/isdn/hardware/avm/c4.c delete mode 100644 drivers/isdn/hardware/avm/t1isa.c delete mode 100644 drivers/isdn/hardware/avm/t1pci.c delete mode 100644 drivers/isdn/hysdn/Kconfig delete mode 100644 drivers/isdn/hysdn/Makefile delete mode 100644 drivers/isdn/hysdn/boardergo.c delete mode 100644 drivers/isdn/hysdn/boardergo.h delete mode 100644 drivers/isdn/hysdn/hycapi.c delete mode 100644 drivers/isdn/hysdn/hysdn_boot.c delete mode 100644 drivers/isdn/hysdn/hysdn_defs.h delete mode 100644 drivers/isdn/hysdn/hysdn_init.c delete mode 100644 drivers/isdn/hysdn/hysdn_net.c delete mode 100644 drivers/isdn/hysdn/hysdn_pof.h delete mode 100644 drivers/isdn/hysdn/hysdn_procconf.c delete mode 100644 drivers/isdn/hysdn/hysdn_proclog.c delete mode 100644 drivers/isdn/hysdn/hysdn_sched.c delete mode 100644 drivers/isdn/hysdn/ince1pc.h create mode 100644 drivers/staging/isdn/Kconfig create mode 100644 drivers/staging/isdn/Makefile create mode 100644 drivers/staging/isdn/TODO create mode 100644 drivers/staging/isdn/avm/Kconfig create mode 100644 drivers/staging/isdn/avm/Makefile create mode 100644 drivers/staging/isdn/avm/avm_cs.c create mode 100644 drivers/staging/isdn/avm/avmcard.h create mode 100644 drivers/staging/isdn/avm/b1.c create mode 100644 drivers/staging/isdn/avm/b1dma.c create mode 100644 drivers/staging/isdn/avm/b1isa.c create mode 100644 drivers/staging/isdn/avm/b1pci.c create mode 100644 drivers/staging/isdn/avm/b1pcmcia.c create mode 100644 drivers/staging/isdn/avm/c4.c create mode 100644 drivers/staging/isdn/avm/t1isa.c create mode 100644 drivers/staging/isdn/avm/t1pci.c create mode 100644 drivers/staging/isdn/gigaset/Kconfig create mode 100644 drivers/staging/isdn/gigaset/Makefile create mode 100644 drivers/staging/isdn/gigaset/asyncdata.c create mode 100644 drivers/staging/isdn/gigaset/bas-gigaset.c create mode 100644 drivers/staging/isdn/gigaset/capi.c create mode 100644 drivers/staging/isdn/gigaset/common.c create mode 100644 drivers/staging/isdn/gigaset/dummyll.c create mode 100644 drivers/staging/isdn/gigaset/ev-layer.c create mode 100644 drivers/staging/isdn/gigaset/gigaset.h create mode 100644 drivers/staging/isdn/gigaset/interface.c create mode 100644 drivers/staging/isdn/gigaset/isocdata.c create mode 100644 drivers/staging/isdn/gigaset/proc.c create mode 100644 drivers/staging/isdn/gigaset/ser-gigaset.c create mode 100644 drivers/staging/isdn/gigaset/usb-gigaset.c create mode 100644 drivers/staging/isdn/hysdn/Kconfig create mode 100644 drivers/staging/isdn/hysdn/Makefile create mode 100644 drivers/staging/isdn/hysdn/boardergo.c create mode 100644 drivers/staging/isdn/hysdn/boardergo.h create mode 100644 drivers/staging/isdn/hysdn/hycapi.c create mode 100644 drivers/staging/isdn/hysdn/hysdn_boot.c create mode 100644 drivers/staging/isdn/hysdn/hysdn_defs.h create mode 100644 drivers/staging/isdn/hysdn/hysdn_init.c create mode 100644 drivers/staging/isdn/hysdn/hysdn_net.c create mode 100644 drivers/staging/isdn/hysdn/hysdn_pof.h create mode 100644 drivers/staging/isdn/hysdn/hysdn_procconf.c create mode 100644 drivers/staging/isdn/hysdn/hysdn_proclog.c create mode 100644 drivers/staging/isdn/hysdn/hysdn_sched.c create mode 100644 drivers/staging/isdn/hysdn/ince1pc.h (limited to 'drivers/isdn') diff --git a/MAINTAINERS b/MAINTAINERS index 3a761e680296..2be31b13d295 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6679,9 +6679,7 @@ M: Paul Bolle L: gigaset307x-common@lists.sourceforge.net W: http://gigaset307x.sourceforge.net/ S: Odd Fixes -F: Documentation/isdn/README.gigaset -F: drivers/isdn/gigaset/ -F: include/uapi/linux/gigaset_dev.h +F: drivers/staging/isdn/gigaset/ GNSS SUBSYSTEM M: Johan Hovold @@ -8362,15 +8360,25 @@ S: Supported W: http://www.linux-iscsi.org F: drivers/infiniband/ulp/isert -ISDN SUBSYSTEM +ISDN/mISDN SUBSYSTEM M: Karsten Keil L: isdn4linux@listserv.isdn4linux.de (subscribers-only) L: netdev@vger.kernel.org W: http://www.isdn4linux.de -T: git git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/isdn-2.6.git S: Maintained +F: drivers/isdn/mISDN +F: drivers/isdn/hardware + +ISDN/CAPI SUBSYSTEM +M: Karsten Keil +L: isdn4linux@listserv.isdn4linux.de (subscribers-only) +L: netdev@vger.kernel.org +W: http://www.isdn4linux.de +S: Odd Fixes F: Documentation/isdn/ -F: drivers/isdn/ +F: drivers/isdn/capi/ +F: drivers/staging/isdn/ +F: net/bluetooth/cmtp/ F: include/linux/isdn/ F: include/uapi/linux/isdn/ 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 - .) 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 + .) 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 , - * Hansjoerg Lipp , - * 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 -#include -#include - -/* 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. */ - 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 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 . without 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 not in DLE mode\n"); - break; /* quoted byte left in buffer */ - default: - dev_notice(cs->dev, "received <%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 , - * Tilman Schmidt , - * 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 -#include -#include - -/* Version Information */ -#define DRIVER_AUTHOR "Tilman Schmidt , Hansjoerg Lipp , 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 . - * - * ===================================================================== - * 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 -#include -#include -#include -#include -#include -#include - -/* 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 , - * Tilman Schmidt . - * - * ===================================================================== - * 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 -#include - -/* Version Information */ -#define DRIVER_AUTHOR "Hansjoerg Lipp , Tilman Schmidt , 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 . - * - * ===================================================================== - * 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 -#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 , - * Tilman Schmidt . - * - * ===================================================================== - * 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 -#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 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 - * - * ===================================================================== - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 ( 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 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: - * : "X" "." - * : 0x10 - * : ((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 - * - * ===================================================================== - * 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 -#include -#include - -/*** 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 , - * Hansjoerg Lipp . - * - * ===================================================================== - * 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 -#include - -/* 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 , - * Tilman Schmidt . - * - * ===================================================================== - * 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 -#include -#include -#include - -/* 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 . - * - * This driver was derived from the USB skeleton driver by - * Greg Kroah-Hartman - * - * ===================================================================== - * 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 -#include -#include - -/* Version Information */ -#define DRIVER_AUTHOR "Hansjoerg Lipp , 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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -/*====================================================================*/ - -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 - * - * 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 -#include -#include - -#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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "avmcard.h" -#include -#include - -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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "avmcard.h" -#include -#include - -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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 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 -#include -#include -#include -#include -#include -#include - -#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 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 -#include -#include -#include -#include -#include -#include -#include - -#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 - -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 -#include -#include - -#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 -#include -#include -#include - -#include "ince1pc.h" - -#ifdef CONFIG_HYSDN_CAPI -#include -#include -#include -#include - -/***************************/ -/* 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 -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include - -#include "hysdn_defs.h" - -/*****************************************************************************/ -/* hysdn_sched_rx is called from the cards handler to announce new data is */ -/* available from the card. The routine has to handle the data and return */ -/* with a nonzero code if the data could be worked (or even thrown away), if */ -/* no room to buffer the data is available a zero return tells the card */ -/* to keep the data until later. */ -/*****************************************************************************/ -int -hysdn_sched_rx(hysdn_card *card, unsigned char *buf, unsigned short len, - unsigned short chan) -{ - - switch (chan) { - case CHAN_NDIS_DATA: - if (hynet_enable & (1 << card->myid)) { - /* give packet to network handler */ - hysdn_rx_netpkt(card, buf, len); - } - break; - - case CHAN_ERRLOG: - hysdn_card_errlog(card, (tErrLogEntry *) buf, len); - if (card->err_log_state == ERRLOG_STATE_ON) - card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ - break; -#ifdef CONFIG_HYSDN_CAPI - case CHAN_CAPI: -/* give packet to CAPI handler */ - if (hycapi_enable & (1 << card->myid)) { - hycapi_rx_capipkt(card, buf, len); - } - break; -#endif /* CONFIG_HYSDN_CAPI */ - default: - printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); - break; - - } /* switch rx channel */ - - return (1); /* always handled */ -} /* hysdn_sched_rx */ - -/*****************************************************************************/ -/* hysdn_sched_tx is called from the cards handler to announce that there is */ -/* room in the tx-buffer to the card and data may be sent if needed. */ -/* If the routine wants to send data it must fill buf, len and chan with the */ -/* appropriate data and return a nonzero value. With a zero return no new */ -/* data to send is assumed. maxlen specifies the buffer size available for */ -/* sending. */ -/*****************************************************************************/ -int -hysdn_sched_tx(hysdn_card *card, unsigned char *buf, - unsigned short volatile *len, unsigned short volatile *chan, - unsigned short maxlen) -{ - struct sk_buff *skb; - - if (card->net_tx_busy) { - card->net_tx_busy = 0; /* reset flag */ - hysdn_tx_netack(card); /* acknowledge packet send */ - } /* a network packet has completely been transferred */ - /* first of all async requests are handled */ - if (card->async_busy) { - if (card->async_len <= maxlen) { - memcpy(buf, card->async_data, card->async_len); - *len = card->async_len; - *chan = card->async_channel; - card->async_busy = 0; /* reset request */ - return (1); - } - card->async_busy = 0; /* in case of length error */ - } /* async request */ - if ((card->err_log_state == ERRLOG_STATE_START) && - (maxlen >= ERRLOG_CMD_REQ_SIZE)) { - strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */ - *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */ - *chan = CHAN_ERRLOG; /* and channel */ - card->err_log_state = ERRLOG_STATE_ON; /* new state is on */ - return (1); /* tell that data should be send */ - } /* error log start and able to send */ - if ((card->err_log_state == ERRLOG_STATE_STOP) && - (maxlen >= ERRLOG_CMD_STOP_SIZE)) { - strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */ - *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */ - *chan = CHAN_ERRLOG; /* and channel */ - card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */ - return (1); /* tell that data should be send */ - } /* error log start and able to send */ - /* now handle network interface packets */ - if ((hynet_enable & (1 << card->myid)) && - (skb = hysdn_tx_netget(card)) != NULL) - { - if (skb->len <= maxlen) { - /* copy the packet to the buffer */ - skb_copy_from_linear_data(skb, buf, skb->len); - *len = skb->len; - *chan = CHAN_NDIS_DATA; - card->net_tx_busy = 1; /* we are busy sending network data */ - return (1); /* go and send the data */ - } else - hysdn_tx_netack(card); /* aknowledge packet -> throw away */ - } /* send a network packet if available */ -#ifdef CONFIG_HYSDN_CAPI - if (((hycapi_enable & (1 << card->myid))) && - ((skb = hycapi_tx_capiget(card)) != NULL)) - { - if (skb->len <= maxlen) { - skb_copy_from_linear_data(skb, buf, skb->len); - *len = skb->len; - *chan = CHAN_CAPI; - hycapi_tx_capiack(card); - return (1); /* go and send the data */ - } - } -#endif /* CONFIG_HYSDN_CAPI */ - return (0); /* nothing to send */ -} /* hysdn_sched_tx */ - - -/*****************************************************************************/ -/* send one config line to the card and return 0 if successful, otherwise a */ -/* negative error code. */ -/* The function works with timeouts perhaps not giving the greatest speed */ -/* sending the line, but this should be meaningless because only some lines */ -/* are to be sent and this happens very seldom. */ -/*****************************************************************************/ -int -hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) -{ - int cnt = 50; /* timeout intervalls */ - unsigned long flags; - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); - - while (card->async_busy) { - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg delayed"); - - msleep_interruptible(20); /* Timeout 20ms */ - if (!--cnt) - return (-ERR_ASYNC_TIME); /* timed out */ - } /* wait for buffer to become free */ - - spin_lock_irqsave(&card->hysdn_lock, flags); - strcpy(card->async_data, line); - card->async_len = strlen(line) + 1; - card->async_channel = chan; - card->async_busy = 1; /* request transfer */ - - /* now queue the task */ - schedule_work(&card->irq_queue); - spin_unlock_irqrestore(&card->hysdn_lock, flags); - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg data queued"); - - cnt++; /* short delay */ - - while (card->async_busy) { - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg waiting for tx-ready"); - - msleep_interruptible(20); /* Timeout 20ms */ - if (!--cnt) - return (-ERR_ASYNC_TIME); /* timed out */ - } /* wait for buffer to become free again */ - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg data send"); - - return (0); /* line send correctly */ -} /* hysdn_tx_cfgline */ diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h deleted file mode 100644 index cab68361de65..000000000000 --- a/drivers/isdn/hysdn/ince1pc.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Linux driver for HYSDN cards - * common definitions for both sides of the bus: - * - conventions both spoolers must know - * - channel numbers agreed upon - * - * Author M. Steinkopf - * Copyright 1999 by M. Steinkopf - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __INCE1PC_H__ -#define __INCE1PC_H__ - -/* basic scalar definitions have same meanning, - * but their declaration location depends on environment - */ - -/*--------------------------------------channel numbers---------------------*/ -#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ -#define CHAN_ERRLOG 0x0005 /* error logger */ -#define CHAN_CAPI 0x0064 /* CAPI interface */ -#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ - -/*--------------------------------------POF ready msg-----------------------*/ -/* NOTE: after booting POF sends system ready message to PC: */ -#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ -#define RDY_MAGIC_SIZE 4 /* size in bytes */ - -#define MAX_N_TOK_BYTES 255 - -#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE -#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE + MAX_N_TOK_BYTES) - -#define SYSR_TOK_END 0 -#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ -#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ -#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ -#define SYSR_TOK_ESC 255 /* undefined data size yet */ -/* default values, if not corrected by token: */ -#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ -#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ - -/* syntax of new SYSR token stream: - * channel: CHAN_SYSTEM - * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE - * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) - * msg : 0 1 2 3 {4 5 6 ..} - * S Y S R MAX_N_TOK_BYTES bytes of TokenStream - * - * TokenStream := empty - * | {NonEndTokenChunk} EndToken RotlCRC - * NonEndTokenChunk:= NonEndTokenId DataLen [Data] - * NonEndTokenId := 0x01 .. 0xFE 1 BYTE - * DataLen := 0x00 .. 0xFF 1 BYTE - * Data := DataLen bytes - * EndToken := 0x00 - * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes - * s. RotlCRC algorithm - * - * RotlCRC algorithm: - * ucSum= 0 1 unsigned char - * for all NonEndTokenChunk bytes: - * ROTL(ucSum,1) rotate left by 1 - * ucSum += Char; add current byte with swap around - * RotlCRC= ~ucSum; invert all bits for result - * - * note: - * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! - */ - -/*--------------------------------------error logger------------------------*/ -/* note: pof needs final 0 ! */ -#define ERRLOG_CMD_REQ "ERRLOG ON" -#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ -#define ERRLOG_CMD_STOP "ERRLOG OFF" -#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ - -#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ - /* remaining text size = 55 */ -#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE - 2 * 4 - 1) - -typedef struct ErrLogEntry_tag { - - /*00 */ unsigned long ulErrType; - - /*04 */ unsigned long ulErrSubtype; - - /*08 */ unsigned char ucTextSize; - - /*09 */ unsigned char ucText[ERRLOG_TEXT_SIZE]; - /* ASCIIZ of len ucTextSize-1 */ - -/*40 */ -} tErrLogEntry; - - -#if defined(__TURBOC__) -#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE -#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE -#endif /* */ -#endif /* */ - -/*--------------------------------------DPRAM boot spooler------------------*/ -/* this is the struture used between pc and - * hyperstone to exchange boot data - */ -#define DPRAM_SPOOLER_DATA_SIZE 0x20 -typedef struct DpramBootSpooler_tag { - - /*00 */ unsigned char Len; - - /*01 */ volatile unsigned char RdPtr; - - /*02 */ unsigned char WrPtr; - - /*03 */ unsigned char Data[DPRAM_SPOOLER_DATA_SIZE]; - -/*23 */ -} tDpramBootSpooler; - - -#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ -#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ - -/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ -/* at DPRAM offset 0x1C00: */ -#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ - - -#endif /* __INCE1PC_H__ */ diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index d5f771fafc21..7c96a01eef6c 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -118,4 +118,6 @@ source "drivers/staging/fieldbus/Kconfig" source "drivers/staging/kpc2000/Kconfig" +source "drivers/staging/isdn/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 0da0d3f0b5e4..fcaac9693b83 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ obj-$(CONFIG_EROFS_FS) += erofs/ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ obj-$(CONFIG_KPC2000) += kpc2000/ +obj-$(CONFIG_ISDN_CAPI) += isdn/ diff --git a/drivers/staging/isdn/Kconfig b/drivers/staging/isdn/Kconfig new file mode 100644 index 000000000000..faaf63887094 --- /dev/null +++ b/drivers/staging/isdn/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "ISDN CAPI drivers" + depends on ISDN_CAPI + +source "drivers/staging/isdn/avm/Kconfig" + +source "drivers/staging/isdn/gigaset/Kconfig" + +source "drivers/staging/isdn/hysdn/Kconfig" + +endmenu + diff --git a/drivers/staging/isdn/Makefile b/drivers/staging/isdn/Makefile new file mode 100644 index 000000000000..025504bae5df --- /dev/null +++ b/drivers/staging/isdn/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for the kernel ISDN subsystem and device drivers. + +# Object files in subdirectories + +obj-$(CONFIG_CAPI_AVM) += avm/ +obj-$(CONFIG_HYSDN) += hysdn/ +obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/ diff --git a/drivers/staging/isdn/TODO b/drivers/staging/isdn/TODO new file mode 100644 index 000000000000..9210d11eb68b --- /dev/null +++ b/drivers/staging/isdn/TODO @@ -0,0 +1,22 @@ +TODO: Remove in late 2019 unless there are users + + +I tried to find any indication of whether the capi drivers are +still in use, and have not found anything from a long time ago. + +With public ISDN networks almost completely shut down over the past 12 +months, there is very little you can actually do with this hardware. The +main remaining use case would be to connect ISDN voice phones to an +in-house installation with Asterisk or LCR, but anyone trying this in +turn seems to be using either the mISDN driver stack, or out-of-tree +drivers from the hardware vendors. + +I may of course have missed something, so I would suggest moving +these into drivers/staging/ just in case someone still uses one +of the three remaining in-kernel drivers (avm, hysdn, gigaset). + +If nobody complains, we can remove them entirely in six months, +or otherwise move the core code and any drivers that are still +needed back into drivers/isdn. + + Arnd Bergmann diff --git a/drivers/staging/isdn/avm/Kconfig b/drivers/staging/isdn/avm/Kconfig new file mode 100644 index 000000000000..81483db067bb --- /dev/null +++ b/drivers/staging/isdn/avm/Kconfig @@ -0,0 +1,65 @@ +# 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/staging/isdn/avm/Makefile b/drivers/staging/isdn/avm/Makefile new file mode 100644 index 000000000000..3830a0573fcc --- /dev/null +++ b/drivers/staging/isdn/avm/Makefile @@ -0,0 +1,12 @@ +# 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/staging/isdn/avm/avm_cs.c b/drivers/staging/isdn/avm/avm_cs.c new file mode 100644 index 000000000000..62b8030ee331 --- /dev/null +++ b/drivers/staging/isdn/avm/avm_cs.c @@ -0,0 +1,166 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/*====================================================================*/ + +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/staging/isdn/avm/avmcard.h b/drivers/staging/isdn/avm/avmcard.h new file mode 100644 index 000000000000..cdfa89c71997 --- /dev/null +++ b/drivers/staging/isdn/avm/avmcard.h @@ -0,0 +1,581 @@ +/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ + * + * Copyright 1999 by Carsten Paeth + * + * 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 +#include +#include + +#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/staging/isdn/avm/b1.c b/drivers/staging/isdn/avm/b1.c new file mode 100644 index 000000000000..40ca1e8fa09f --- /dev/null +++ b/drivers/staging/isdn/avm/b1.c @@ -0,0 +1,804 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "avmcard.h" +#include +#include + +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/staging/isdn/avm/b1dma.c b/drivers/staging/isdn/avm/b1dma.c new file mode 100644 index 000000000000..6a3dc9937ce5 --- /dev/null +++ b/drivers/staging/isdn/avm/b1dma.c @@ -0,0 +1,981 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "avmcard.h" +#include +#include + +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/staging/isdn/avm/b1isa.c b/drivers/staging/isdn/avm/b1isa.c new file mode 100644 index 000000000000..cdfea72e0ef6 --- /dev/null +++ b/drivers/staging/isdn/avm/b1isa.c @@ -0,0 +1,243 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/staging/isdn/avm/b1pci.c b/drivers/staging/isdn/avm/b1pci.c new file mode 100644 index 000000000000..b76b57a82c02 --- /dev/null +++ b/drivers/staging/isdn/avm/b1pci.c @@ -0,0 +1,416 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/staging/isdn/avm/b1pcmcia.c b/drivers/staging/isdn/avm/b1pcmcia.c new file mode 100644 index 000000000000..3aca16e62902 --- /dev/null +++ b/drivers/staging/isdn/avm/b1pcmcia.c @@ -0,0 +1,224 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/staging/isdn/avm/c4.c b/drivers/staging/isdn/avm/c4.c new file mode 100644 index 000000000000..ac72cd204c4d --- /dev/null +++ b/drivers/staging/isdn/avm/c4.c @@ -0,0 +1,1317 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/staging/isdn/avm/t1isa.c b/drivers/staging/isdn/avm/t1isa.c new file mode 100644 index 000000000000..2153619c5b31 --- /dev/null +++ b/drivers/staging/isdn/avm/t1isa.c @@ -0,0 +1,594 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/staging/isdn/avm/t1pci.c b/drivers/staging/isdn/avm/t1pci.c new file mode 100644 index 000000000000..f5ed1d5004c9 --- /dev/null +++ b/drivers/staging/isdn/avm/t1pci.c @@ -0,0 +1,259 @@ +/* $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 + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/staging/isdn/gigaset/Kconfig b/drivers/staging/isdn/gigaset/Kconfig new file mode 100644 index 000000000000..c593105b3600 --- /dev/null +++ b/drivers/staging/isdn/gigaset/Kconfig @@ -0,0 +1,62 @@ +# 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/staging/isdn/gigaset/Makefile b/drivers/staging/isdn/gigaset/Makefile new file mode 100644 index 000000000000..9c010891dcd7 --- /dev/null +++ b/drivers/staging/isdn/gigaset/Makefile @@ -0,0 +1,17 @@ +# 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/staging/isdn/gigaset/asyncdata.c b/drivers/staging/isdn/gigaset/asyncdata.c new file mode 100644 index 000000000000..c0cbee06bc21 --- /dev/null +++ b/drivers/staging/isdn/gigaset/asyncdata.c @@ -0,0 +1,609 @@ +/* + * Common data handling layer for ser_gigaset and usb_gigaset + * + * Copyright (c) 2005 by Tilman Schmidt , + * Hansjoerg Lipp , + * 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 +#include +#include + +/* 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. */ + 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 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 . without 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 not in DLE mode\n"); + break; /* quoted byte left in buffer */ + default: + dev_notice(cs->dev, "received <%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/staging/isdn/gigaset/bas-gigaset.c b/drivers/staging/isdn/gigaset/bas-gigaset.c new file mode 100644 index 000000000000..149b1aca52a2 --- /dev/null +++ b/drivers/staging/isdn/gigaset/bas-gigaset.c @@ -0,0 +1,2675 @@ +/* + * USB driver for Gigaset 307x base via direct USB connection. + * + * Copyright (c) 2001 by Hansjoerg Lipp , + * Tilman Schmidt , + * 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 +#include +#include + +/* Version Information */ +#define DRIVER_AUTHOR "Tilman Schmidt , Hansjoerg Lipp , 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/staging/isdn/gigaset/capi.c b/drivers/staging/isdn/gigaset/capi.c new file mode 100644 index 000000000000..9cb2ab57fa4a --- /dev/null +++ b/drivers/staging/isdn/gigaset/capi.c @@ -0,0 +1,2520 @@ +/* + * Kernel CAPI interface for the Gigaset driver + * + * Copyright (c) 2009 by Tilman Schmidt . + * + * ===================================================================== + * 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 +#include +#include +#include +#include +#include +#include + +/* 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/staging/isdn/gigaset/common.c b/drivers/staging/isdn/gigaset/common.c new file mode 100644 index 000000000000..76b5407b5277 --- /dev/null +++ b/drivers/staging/isdn/gigaset/common.c @@ -0,0 +1,1156 @@ +/* + * Stuff used by all variants of the driver + * + * Copyright (c) 2001 by Stefan Eilers, + * Hansjoerg Lipp , + * Tilman Schmidt . + * + * ===================================================================== + * 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 +#include + +/* Version Information */ +#define DRIVER_AUTHOR "Hansjoerg Lipp , Tilman Schmidt , 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/staging/isdn/gigaset/dummyll.c b/drivers/staging/isdn/gigaset/dummyll.c new file mode 100644 index 000000000000..570c2d53b84e --- /dev/null +++ b/drivers/staging/isdn/gigaset/dummyll.c @@ -0,0 +1,77 @@ +/* + * Dummy LL interface for the Gigaset driver + * + * Copyright (c) 2009 by Tilman Schmidt . + * + * ===================================================================== + * 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 +#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/staging/isdn/gigaset/ev-layer.c b/drivers/staging/isdn/gigaset/ev-layer.c new file mode 100644 index 000000000000..182826e9d07c --- /dev/null +++ b/drivers/staging/isdn/gigaset/ev-layer.c @@ -0,0 +1,1913 @@ +/* + * Stuff used by all variants of the driver + * + * Copyright (c) 2001 by Stefan Eilers, + * Hansjoerg Lipp , + * Tilman Schmidt . + * + * ===================================================================== + * 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 +#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 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/staging/isdn/gigaset/gigaset.h b/drivers/staging/isdn/gigaset/gigaset.h new file mode 100644 index 000000000000..166537e2dfca --- /dev/null +++ b/drivers/staging/isdn/gigaset/gigaset.h @@ -0,0 +1,830 @@ +/* + * Siemens Gigaset 307x driver + * Common header file for all connection variants + * + * Written by Stefan Eilers + * and Hansjoerg Lipp + * + * ===================================================================== + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ( 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 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: + * : "X" "." + * : 0x10 + * : ((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/staging/isdn/gigaset/interface.c b/drivers/staging/isdn/gigaset/interface.c new file mode 100644 index 000000000000..d9a578ac32cd --- /dev/null +++ b/drivers/staging/isdn/gigaset/interface.c @@ -0,0 +1,616 @@ +/* + * interface to user space for the gigaset driver + * + * Copyright (c) 2004 by Hansjoerg Lipp + * + * ===================================================================== + * 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 +#include +#include + +/*** 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/staging/isdn/gigaset/isocdata.c b/drivers/staging/isdn/gigaset/isocdata.c new file mode 100644 index 000000000000..f9264ba0fe77 --- /dev/null +++ b/drivers/staging/isdn/gigaset/isocdata.c @@ -0,0 +1,1009 @@ +/* + * Common data handling layer for bas_gigaset + * + * Copyright (c) 2005 by Tilman Schmidt , + * Hansjoerg Lipp . + * + * ===================================================================== + * 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 +#include + +/* 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/staging/isdn/gigaset/proc.c b/drivers/staging/isdn/gigaset/proc.c new file mode 100644 index 000000000000..e3f9d0f089fa --- /dev/null +++ b/drivers/staging/isdn/gigaset/proc.c @@ -0,0 +1,80 @@ +/* + * Stuff used by all variants of the driver + * + * Copyright (c) 2001 by Stefan Eilers, + * Hansjoerg Lipp , + * Tilman Schmidt . + * + * ===================================================================== + * 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/staging/isdn/gigaset/ser-gigaset.c b/drivers/staging/isdn/gigaset/ser-gigaset.c new file mode 100644 index 000000000000..e1de8b1a1001 --- /dev/null +++ b/drivers/staging/isdn/gigaset/ser-gigaset.c @@ -0,0 +1,799 @@ +/* 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 +#include +#include +#include + +/* 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/staging/isdn/gigaset/usb-gigaset.c b/drivers/staging/isdn/gigaset/usb-gigaset.c new file mode 100644 index 000000000000..eade36dafa34 --- /dev/null +++ b/drivers/staging/isdn/gigaset/usb-gigaset.c @@ -0,0 +1,949 @@ +/* + * USB driver for Gigaset 307x directly or using M105 Data. + * + * Copyright (c) 2001 by Stefan Eilers + * and Hansjoerg Lipp . + * + * This driver was derived from the USB skeleton driver by + * Greg Kroah-Hartman + * + * ===================================================================== + * 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 +#include +#include + +/* Version Information */ +#define DRIVER_AUTHOR "Hansjoerg Lipp , 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/staging/isdn/hysdn/Kconfig b/drivers/staging/isdn/hysdn/Kconfig new file mode 100644 index 000000000000..1971ef850c9a --- /dev/null +++ b/drivers/staging/isdn/hysdn/Kconfig @@ -0,0 +1,15 @@ +# 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 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/staging/isdn/hysdn/Makefile b/drivers/staging/isdn/hysdn/Makefile new file mode 100644 index 000000000000..e01f17f22ebb --- /dev/null +++ b/drivers/staging/isdn/hysdn/Makefile @@ -0,0 +1,12 @@ +# 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/staging/isdn/hysdn/boardergo.c b/drivers/staging/isdn/hysdn/boardergo.c new file mode 100644 index 000000000000..2aa2a0e08247 --- /dev/null +++ b/drivers/staging/isdn/hysdn/boardergo.c @@ -0,0 +1,445 @@ +/* $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 +#include +#include +#include +#include +#include +#include + +#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/staging/isdn/hysdn/boardergo.h b/drivers/staging/isdn/hysdn/boardergo.h new file mode 100644 index 000000000000..e99bd81c4034 --- /dev/null +++ b/drivers/staging/isdn/hysdn/boardergo.h @@ -0,0 +1,100 @@ +/* $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/staging/isdn/hysdn/hycapi.c b/drivers/staging/isdn/hysdn/hycapi.c new file mode 100644 index 000000000000..a2c15cd7bf67 --- /dev/null +++ b/drivers/staging/isdn/hysdn/hycapi.c @@ -0,0 +1,785 @@ +/* $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 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + +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/staging/isdn/hysdn/hysdn_boot.c b/drivers/staging/isdn/hysdn/hysdn_boot.c new file mode 100644 index 000000000000..ba177c3a621b --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_boot.c @@ -0,0 +1,400 @@ +/* $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 +#include +#include + +#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/staging/isdn/hysdn/hysdn_defs.h b/drivers/staging/isdn/hysdn/hysdn_defs.h new file mode 100644 index 000000000000..cdac46a21692 --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_defs.h @@ -0,0 +1,282 @@ +/* $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 +#include +#include +#include + +#include "ince1pc.h" + +#ifdef CONFIG_HYSDN_CAPI +#include +#include +#include +#include + +/***************************/ +/* 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/staging/isdn/hysdn/hysdn_init.c b/drivers/staging/isdn/hysdn/hysdn_init.c new file mode 100644 index 000000000000..0db2f7506250 --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_init.c @@ -0,0 +1,213 @@ +/* $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 +#include +#include +#include +#include +#include + +#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/staging/isdn/hysdn/hysdn_net.c b/drivers/staging/isdn/hysdn/hysdn_net.c new file mode 100644 index 000000000000..8e9c34f33d86 --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_net.c @@ -0,0 +1,326 @@ +/* $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 +#include +#include +#include +#include +#include +#include + +#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/staging/isdn/hysdn/hysdn_pof.h b/drivers/staging/isdn/hysdn/hysdn_pof.h new file mode 100644 index 000000000000..f63f5fa59d7e --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_pof.h @@ -0,0 +1,78 @@ +/* $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/staging/isdn/hysdn/hysdn_procconf.c b/drivers/staging/isdn/hysdn/hysdn_procconf.c new file mode 100644 index 000000000000..73079213ec94 --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_procconf.c @@ -0,0 +1,411 @@ +/* $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 +#include +#include +#include +#include +#include +#include +#include + +#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/staging/isdn/hysdn/hysdn_proclog.c b/drivers/staging/isdn/hysdn/hysdn_proclog.c new file mode 100644 index 000000000000..6e898b90e86e --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_proclog.c @@ -0,0 +1,357 @@ +/* $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 +#include +#include +#include +#include +#include +#include + +#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/staging/isdn/hysdn/hysdn_sched.c b/drivers/staging/isdn/hysdn/hysdn_sched.c new file mode 100644 index 000000000000..31d7c1415543 --- /dev/null +++ b/drivers/staging/isdn/hysdn/hysdn_sched.c @@ -0,0 +1,197 @@ +/* $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 +#include +#include +#include +#include +#include + +#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/staging/isdn/hysdn/ince1pc.h b/drivers/staging/isdn/hysdn/ince1pc.h new file mode 100644 index 000000000000..cab68361de65 --- /dev/null +++ b/drivers/staging/isdn/hysdn/ince1pc.h @@ -0,0 +1,134 @@ +/* + * 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__ */ -- cgit v1.2.3