mISDN/drivers/isdn/hardware/mISDN/hfc_pci.c

2506 lines
72 KiB
C
Raw Normal View History

2001-08-02 14:55:45 +00:00
/* $Id$
2001-11-14 10:41:26 +00:00
* hfc_pci.c low level driver for CCD's hfc-pci based cards
2001-08-02 14:55:45 +00:00
*
* Author Werner Cornelius (werner@isdn4linux.de)
* based on existing driver for CCD hfc ISA cards
* type approval valid for HFC-S PCI A based card
*
* Copyright 1999 by Werner Cornelius (werner@isdn-development.de)
2001-11-14 10:41:26 +00:00
* Copyright 2001 by Karsten Keil (keil@isdn4linux.de)
2001-08-02 14:55:45 +00:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
2003-07-21 12:00:05 +00:00
#include "mISDN_dch.h"
#include "mISDN_bch.h"
2001-08-02 14:55:45 +00:00
#include "hfc_pci.h"
2003-07-21 12:00:05 +00:00
#include "mISDNl1.h"
2001-08-02 14:55:45 +00:00
#include "helper.h"
#include "debug.h"
#include <linux/isdn_compat.h>
2001-08-02 14:55:45 +00:00
#define SPIN_DEBUG
#define LOCK_STATISTIC
#include "hw_lock.h"
#define HFC_INFO(txt) printk(KERN_DEBUG txt)
2001-08-02 14:55:45 +00:00
extern const char *CardType[];
static const char *hfcpci_revision = "$Revision$";
2001-08-02 14:55:45 +00:00
/* 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 */
2001-09-30 17:09:23 +00:00
#ifndef PCI_VENDOR_ID_CCD
2001-08-02 14:55:45 +00:00
#define PCI_VENDOR_ID_CCD 0x1397
#define PCI_DEVICE_ID_CCD_2BD0 0x2BD0
#define PCI_DEVICE_ID_CCD_B000 0xB000
#define PCI_DEVICE_ID_CCD_B006 0xB006
#define PCI_DEVICE_ID_CCD_B007 0xB007
#define PCI_DEVICE_ID_CCD_B008 0xB008
#define PCI_DEVICE_ID_CCD_B009 0xB009
#define PCI_DEVICE_ID_CCD_B00A 0xB00A
#define PCI_DEVICE_ID_CCD_B00B 0xB00B
#define PCI_DEVICE_ID_CCD_B00C 0xB00C
#define PCI_DEVICE_ID_CCD_B100 0xB100
#define PCI_VENDOR_ID_ASUSTEK 0x1043
#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675
#define PCI_VENDOR_ID_BERKOM 0x0871
#define PCI_DEVICE_ID_BERKOM_A1T 0xFFA1
#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xFFA2
#define PCI_VENDOR_ID_ANIGMA 0x1051
#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100
#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2BD0
#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070
#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073
#define PCI_VENDOR_ID_ABOCOM 0x13D1
#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1
2001-09-30 17:09:23 +00:00
#endif
2001-08-02 14:55:45 +00:00
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_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)"},
{0, 0, NULL, NULL},
};
struct hfcPCI_hw {
2001-11-14 10:41:26 +00:00
unsigned char cirm;
unsigned char ctmt;
unsigned char clkdel;
unsigned char states;
unsigned char conn;
unsigned char mst_m;
unsigned char int_m1;
unsigned char int_m2;
unsigned char sctrl;
unsigned char sctrl_r;
unsigned char sctrl_e;
unsigned char trm;
unsigned char fifo_en;
unsigned char bswapped;
unsigned char nt_mode;
int nt_timer;
unsigned char pci_bus;
unsigned char pci_device_fn;
unsigned char *pci_io; /* start of PCI IO memory */
void *share_start; /* shared memory for Fifos start */
void *fifos; /* FIFO memory */
int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
timer_t timer;
2001-08-02 14:55:45 +00:00
};
2001-11-14 10:41:26 +00:00
typedef struct hfcPCI_hw hfcPCI_hw_t;
2001-09-29 20:05:01 +00:00
#define SPIN_DEBUG
2001-11-14 10:41:26 +00:00
#define HFC_CFG_MASTER 1
#define HFC_CFG_SLAVE 2
#define HFC_CFG_PCM 3
#define HFC_CFG_2HFC 4
#define HFC_CFG_SLAVEHFC 5
#define HFC_CFG_NEG_F0 6
#define HFC_CFG_SW_DD_DU 7
2001-09-29 20:05:01 +00:00
2001-08-02 14:55:45 +00:00
typedef struct _hfc_pci {
2001-11-14 10:41:26 +00:00
struct _hfc_pci *prev;
struct _hfc_pci *next;
u_char subtyp;
u_char chanlimit;
u_int cfg;
u_int irq;
hfcPCI_hw_t hw;
2003-07-21 12:00:05 +00:00
mISDN_HWlock_t lock;
2001-11-14 10:41:26 +00:00
dchannel_t dch;
bchannel_t bch[2];
2001-08-02 14:55:45 +00:00
} hfc_pci_t;
2003-06-22 12:03:36 +00:00
static int lock_dev(void *data, int nowait)
2001-08-02 14:55:45 +00:00
{
2003-07-21 12:00:05 +00:00
register mISDN_HWlock_t *lock = &((hfc_pci_t *)data)->lock;
2003-06-22 12:03:36 +00:00
return(lock_HW(lock, nowait));
2001-08-02 14:55:45 +00:00
}
static void unlock_dev(void *data)
{
2003-07-21 12:00:05 +00:00
register mISDN_HWlock_t *lock = &((hfc_pci_t *)data)->lock;
2001-08-02 14:55:45 +00:00
unlock_HW(lock);
2001-08-02 14:55:45 +00:00
}
/* Interface functions */
/******************************************/
/* free hardware resources used by driver */
/******************************************/
void
release_io_hfcpci(hfc_pci_t *hc)
{
hc->hw.int_m2 = 0; /* interrupt output off ! */
Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
Write_hfc(hc, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
hc->hw.cirm = 0; /* Reset Off */
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
pcibios_write_config_word(hc->hw.pci_bus, hc->hw.pci_device_fn, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */
del_timer(&hc->hw.timer);
kfree(hc->hw.share_start);
hc->hw.share_start = NULL;
2002-09-17 12:17:21 +00:00
iounmap((void *)hc->hw.pci_io);
2001-08-02 14:55:45 +00:00
}
/********************************************************************************/
/* function called to reset the HFC PCI chip. A complete software reset of chip */
/* and fifos is done. */
/********************************************************************************/
static void
reset_hfcpci(hfc_pci_t *hc)
{
2001-11-16 01:49:21 +00:00
u_char val;
2002-04-29 23:26:30 +00:00
int cnt = 0;
2001-08-02 14:55:45 +00:00
HFC_INFO("reset_hfcpci: entered\n");
2002-04-29 23:26:30 +00:00
val = Read_hfc(hc, HFCPCI_CHIP_ID);
printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val);
2001-08-02 14:55:45 +00:00
pcibios_write_config_word(hc->hw.pci_bus, hc->hw.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
hc->hw.int_m2 = 0; /* interrupt output off ! */
Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
pcibios_write_config_word(hc->hw.pci_bus, hc->hw.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */
2002-04-29 23:26:30 +00:00
val = Read_hfc(hc, HFCPCI_STATUS);
printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val);
2001-08-02 14:55:45 +00:00
hc->hw.cirm = HFCPCI_RESET; /* Reset On */
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
hc->hw.cirm = 0; /* Reset Off */
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
2001-11-19 14:54:00 +00:00
val = Read_hfc(hc, HFCPCI_STATUS);
2002-04-29 23:26:30 +00:00
printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val);
while (cnt < 50000) { /* max 50000 us */
udelay(5);
cnt += 5;
val = Read_hfc(hc, HFCPCI_STATUS);
if (!(val & 2))
break;
}
printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt);
2001-08-02 14:55:45 +00:00
hc->hw.fifo_en = 0x30; /* only D fifos enabled */
hc->hw.bswapped = 0; /* no exchange */
hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
hc->hw.sctrl_r = 0;
hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */
hc->hw.mst_m = 0;
2001-11-14 10:41:26 +00:00
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */
if (test_bit(HFC_CFG_NEG_F0, &hc->cfg))
hc->hw.mst_m |= HFCPCI_F0_NEGATIV;
2001-08-02 14:55:45 +00:00
if (hc->hw.nt_mode) {
hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */
hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */
hc->hw.states = 1; /* G1 */
} else {
hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */
hc->hw.states = 2; /* F2 */
}
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel);
Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* Clear already pending ints */
if (Read_hfc(hc, HFCPCI_INT_S1));
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states);
udelay(10);
Write_hfc(hc, HFCPCI_STATES, hc->hw.states);
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.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 -> continous 1s */
/* The IOM slots are always enabled */
if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
/* set data flow directions: connect B1,B2: HFC to/from PCM */
hc->hw.conn = 0x09;
} else {
hc->hw.conn = 0x36; /* set data flow directions */
if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
2002-07-08 12:53:57 +00:00
Write_hfc(hc, HFCPCI_B1_SSL, 0xC0);
Write_hfc(hc, HFCPCI_B2_SSL, 0xC1);
Write_hfc(hc, HFCPCI_B1_RSL, 0xC0);
Write_hfc(hc, HFCPCI_B2_RSL, 0xC1);
} else {
Write_hfc(hc, HFCPCI_B1_SSL, 0x80);
Write_hfc(hc, HFCPCI_B2_SSL, 0x81);
Write_hfc(hc, HFCPCI_B1_RSL, 0x80);
Write_hfc(hc, HFCPCI_B2_RSL, 0x81);
}
}
2001-08-02 14:55:45 +00:00
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
2001-11-16 01:49:21 +00:00
val = Read_hfc(hc, HFCPCI_INT_S2);
2001-08-02 14:55:45 +00:00
}
/***************************************************/
/* Timer function called when kernel timer expires */
/***************************************************/
static void
hfcpci_Timer(hfc_pci_t *hc)
{
hc->hw.timer.expires = jiffies + 75;
/* WD RESET */
/* WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80);
add_timer(&hc->hw.timer);
*/
}
/************************************************/
/* select a b-channel entry matching and active */
/************************************************/
static
bchannel_t *
Sel_BCS(hfc_pci_t *hc, int channel)
{
2001-11-14 10:41:26 +00:00
if (hc->bch[0].protocol && (hc->bch[0].channel & channel))
2001-08-02 14:55:45 +00:00
return (&hc->bch[0]);
2001-11-14 10:41:26 +00:00
else if (hc->bch[1].protocol && (hc->bch[1].channel & channel))
2001-08-02 14:55:45 +00:00
return (&hc->bch[1]);
else
return (NULL);
}
/***************************************/
/* clear the desired B-channel rx fifo */
/***************************************/
static void hfcpci_clear_fifo_rx(hfc_pci_t *hc, int fifo)
{ u_char fifo_state;
bzfifo_type *bzr;
if (fifo) {
bzr = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2;
fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX;
} else {
bzr = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b1;
fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX;
}
if (fifo_state)
hc->hw.fifo_en ^= fifo_state;
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
hc->hw.last_bfifo_cnt[fifo] = 0;
bzr->f1 = MAX_B_FRAMES;
bzr->f2 = bzr->f1; /* init F pointers to remain constant */
2001-09-29 20:05:01 +00:00
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;
2001-08-02 14:55:45 +00:00
if (fifo_state)
hc->hw.fifo_en |= fifo_state;
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
}
/***************************************/
/* clear the desired B-channel tx fifo */
/***************************************/
static void hfcpci_clear_fifo_tx(hfc_pci_t *hc, int fifo)
{ u_char fifo_state;
bzfifo_type *bzt;
if (fifo) {
bzt = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b2;
fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX;
} else {
bzt = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b1;
fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX;
}
if (fifo_state)
hc->hw.fifo_en ^= fifo_state;
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
2001-09-29 20:05:01 +00:00
if (hc->bch[fifo].debug & L1_DEB_HSCX)
debugprint(&hc->bch[fifo].inst, "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x) state(%x)",
fifo, bzt->f1, bzt->f2, bzt->za[MAX_B_FRAMES].z1, bzt->za[MAX_B_FRAMES].z2, fifo_state);
bzt->f2 = MAX_B_FRAMES;
2002-09-16 22:03:51 +00:00
bzt->f1 = bzt->f2; /* init F pointers to remain constant */
2001-08-02 14:55:45 +00:00
bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
2001-09-29 20:05:01 +00:00
bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1 - 1;
2001-08-02 14:55:45 +00:00
if (fifo_state)
hc->hw.fifo_en |= fifo_state;
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
2001-09-29 20:05:01 +00:00
if (hc->bch[fifo].debug & L1_DEB_HSCX)
debugprint(&hc->bch[fifo].inst, "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)",
fifo, bzt->f1, bzt->f2, bzt->za[MAX_B_FRAMES].z1, bzt->za[MAX_B_FRAMES].z2);
2001-08-02 14:55:45 +00:00
}
/*********************************************/
/* read a complete B-frame out of the buffer */
/*********************************************/
static struct sk_buff
*
hfcpci_empty_fifo(bchannel_t *bch, bzfifo_type * bz, u_char * bdata, int count)
{
u_char *ptr, *ptr1, new_f2;
struct sk_buff *skb;
2001-11-02 23:28:21 +00:00
int total, maxlen, new_z2;
2001-08-02 14:55:45 +00:00
z_type *zp;
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
debugprint(&bch->inst, "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 > MAX_DATA_SIZE + 3) || (count < 4) ||
(*(bdata + (zp->z1 - B_SUB_VAL)))) {
if (bch->debug & L1_DEB_WARN)
debugprint(&bch->inst, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
#ifdef ERROR_STATISTIC
bch->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)))
2001-08-02 14:55:45 +00:00
printk(KERN_WARNING "HFCPCI: receive out of memory\n");
else {
total = count;
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(hfc_pci_t *hc)
{
struct sk_buff *skb;
dchannel_t *dch = &hc->dch;
int maxlen;
int rcnt, total;
int count = 5;
u_char *ptr, *ptr1;
dfifo_type *df;
z_type *zp;
df = &((fifo_area *) (hc->hw.fifos))->d_chan.d_rx;
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 (dch->debug & L1_DEB_ISAC)
debugprint(&dch->inst, "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 (dch->debug & L1_DEB_WARN)
debugprint(&dch->inst, "empty_fifo hfcpci paket 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 = alloc_uplinkD_skb(rcnt - 3))) {
2001-08-02 14:55:45 +00:00
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);
if (dch->debug & L1_DEB_ISAC_FIFO) {
char *t = dch->dlog;
count = skb->len;
ptr = skb->data;
t += sprintf(t, "hfcD_empty_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugprint(&dch->inst, dch->dlog);
}
skb_queue_tail(&dch->rqueue, skb);
dchannel_sched_event(dch, D_RCVBUFREADY);
2001-08-02 14:55:45 +00:00
} else
printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
}
return (1);
}
/*******************************************************************************/
/* check for transparent receive data and read max one threshold size if avail */
/*******************************************************************************/
int
hfcpci_empty_fifo_trans(bchannel_t *bch, 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)))
2001-08-02 14:55:45 +00:00
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(&bch->rqueue, skb);
bch_sched_event(bch, B_RCVBUFREADY);
2001-08-02 14:55:45 +00:00
}
*z2r = new_z2; /* new position */
return (1);
} /* hfcpci_empty_fifo_trans */
/**********************************/
/* B-channel main receive routine */
/**********************************/
void
main_rec_hfcpci(bchannel_t *bch)
{
hfc_pci_t *hc = bch->inst.data;
int rcnt, real_fifo;
int receive, count = 5;
struct sk_buff *skb;
bzfifo_type *bz;
u_char *bdata;
z_type *zp;
2001-11-14 10:41:26 +00:00
if ((bch->channel & 2) && (!hc->hw.bswapped)) {
2001-08-02 14:55:45 +00:00
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b2;
real_fifo = 1;
} else {
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b1;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b1;
real_fifo = 0;
}
Begin:
count--;
if (bz->f1 != bz->f2) {
if (bch->debug & L1_DEB_HSCX)
2001-11-14 10:41:26 +00:00
debugprint(&bch->inst, "hfcpci rec ch(%x) f1(%d) f2(%d)",
2001-08-02 14:55:45 +00:00
bch->channel, bz->f1, bz->f2);
zp = &bz->za[bz->f2];
rcnt = zp->z1 - zp->z2;
if (rcnt < 0)
rcnt += B_FIFO_SIZE;
rcnt++;
if (bch->debug & L1_DEB_HSCX)
2001-11-14 10:41:26 +00:00
debugprint(&bch->inst, "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)",
2001-08-02 14:55:45 +00:00
bch->channel, zp->z1, zp->z2, rcnt);
if ((skb = hfcpci_empty_fifo(bch, bz, bdata, rcnt))) {
skb_queue_tail(&bch->rqueue, skb);
bch_sched_event(bch, B_RCVBUFREADY);
2001-08-02 14:55:45 +00:00
}
rcnt = bz->f1 - bz->f2;
if (rcnt < 0)
rcnt += MAX_B_FRAMES + 1;
if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
rcnt = 0;
hfcpci_clear_fifo_rx(hc, real_fifo);
}
hc->hw.last_bfifo_cnt[real_fifo] = rcnt;
if (rcnt > 1)
receive = 1;
else
receive = 0;
} else if (bch->protocol == ISDN_PID_L1_B_64TRANS)
receive = hfcpci_empty_fifo_trans(bch, bz, bdata);
else
receive = 0;
if (count && receive)
goto Begin;
return;
}
/**************************/
/* D-channel send routine */
/**************************/
static void
hfcpci_fill_dfifo(hfc_pci_t *hc)
{
dchannel_t *dch = &hc->dch;
int fcnt;
int count, new_z1, maxlen;
dfifo_type *df;
u_char *src, *dst, new_f1;
if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
debugprint(&dch->inst, "hfcpci_fill_dfifo");
count = dch->tx_len - dch->tx_idx;
if (count <= 0)
return;
df = &((fifo_area *) (hc->hw.fifos))->d_chan.d_tx;
if (dch->debug & L1_DEB_ISAC_FIFO)
debugprint(&dch->inst, "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 (dch->debug & L1_DEB_ISAC)
debugprint(&dch->inst, "hfcpci_fill_Dfifo more as 14 frames");
#ifdef ERROR_STATISTIC
cs->err_tx++;
#endif
return;
}
/* now determine free bytes in FIFO buffer */
maxlen = df->za[df->f1 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1;
if (maxlen <= 0)
maxlen += D_FIFO_SIZE; /* count now contains available bytes */
if (dch->debug & L1_DEB_ISAC)
debugprint(&dch->inst, "hfcpci_fill_Dfifo count(%ld/%d)",
count, maxlen);
if (count > maxlen) {
if (dch->debug & L1_DEB_ISAC)
debugprint(&dch->inst, "hfcpci_fill_Dfifo no fifo mem");
return;
}
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 = dch->tx_buf + dch->tx_idx; /* 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 */
if (dch->debug & L1_DEB_ISAC_FIFO) {
char *t = dch->dlog;
count = dch->tx_len - dch->tx_idx;
src = dch->tx_buf + dch->tx_idx;
t += sprintf(t, "hfcD_fill_fifo cnt %d", count);
QuickHex(t, src, count);
debugprint(&dch->inst, dch->dlog);
}
dch->tx_idx = dch->tx_len;
return;
}
/**************************/
/* B-channel send routine */
/**************************/
static void
hfcpci_fill_fifo(bchannel_t *bch)
{
hfc_pci_t *hc = bch->inst.data;
int maxlen, fcnt;
2001-08-02 14:55:45 +00:00
int count, new_z1;
bzfifo_type *bz;
u_char *bdata;
u_char new_f1, *src, *dst;
unsigned short *z1t, *z2t;
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
debugprint(&bch->inst, __FUNCTION__);
count = bch->tx_len - bch->tx_idx;
if (bch->tx_len <= 0)
return;
2001-09-29 20:05:01 +00:00
2001-11-14 10:41:26 +00:00
if ((bch->channel & 2) && (!hc->hw.bswapped)) {
2001-08-02 14:55:45 +00:00
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b2;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b2;
} else {
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b1;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b1;
}
if (bch->protocol == ISDN_PID_L1_B_64TRANS) {
z1t = &bz->za[MAX_B_FRAMES].z1;
z2t = z1t + 1;
if (bch->debug & L1_DEB_HSCX)
2001-11-14 10:41:26 +00:00
debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) cnt(%d) z1(%x) z2(%x)",
2001-08-02 14:55:45 +00:00
bch->channel, count, *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 */
next_t_frame:
if (fcnt < (2 * HFCPCI_BTRANS_THRESHOLD)) {
count = bch->tx_len - bch->tx_idx;
if (count < B_FIFO_SIZE - fcnt) {
/* data is suitable for fifo */
new_z1 = *z1t + count; /* new buffer Position */
if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
new_z1 -= B_FIFO_SIZE; /* buffer wrap */
src = bch->tx_buf; /* source pointer */
dst = bdata + (*z1t - B_SUB_VAL);
maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
if (bch->debug & L1_DEB_HSCX_FIFO)
debugprint(&bch->inst, "hfcpci_FFt fcnt(%d) maxl(%d) nz1(%x) dst(%p)",
fcnt, maxlen, new_z1, dst);
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);
}
fcnt += bch->tx_len;
*z1t = new_z1; /* now send data */
} else if (bch->debug & L1_DEB_HSCX)
2001-11-14 10:41:26 +00:00
debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) frame length %d discarded",
2001-08-02 14:55:45 +00:00
bch->channel, bch->tx_len);
if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) {
2001-08-02 14:55:45 +00:00
if (bch->next_skb) {
bch->tx_idx = 0;
bch->tx_len = bch->next_skb->len;
memcpy(bch->tx_buf,
bch->next_skb->data,
bch->tx_len);
bch_sched_event(bch, B_XMTBUFREADY);
2001-08-02 14:55:45 +00:00
goto next_t_frame;
} else
printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
}
bch->tx_len = 0;
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
2001-08-02 14:55:45 +00:00
bch->tx_idx = bch->tx_len;
}
return;
}
if (bch->debug & L1_DEB_HSCX)
2002-09-16 23:49:38 +00:00
debugprint(&bch->inst, "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)",
__FUNCTION__, bch->channel, bz->f1, bz->f2, bz->za[bz->f1].z1);
2001-08-02 14:55:45 +00:00
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 (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci_fill_Bfifo more as 14 frames");
return;
}
/* now determine free bytes in FIFO buffer */
maxlen = bz->za[bz->f1].z2 - bz->za[bz->f1].z1;
if (maxlen <= 0)
maxlen += B_FIFO_SIZE; /* count now contains available bytes */
if (bch->debug & L1_DEB_HSCX)
2001-11-14 10:41:26 +00:00
debugprint(&bch->inst, "hfcpci_fill_fifo ch(%x) count(%ld/%d),%lx",
2001-08-02 14:55:45 +00:00
bch->channel, count,
maxlen, current->state);
if (maxlen < count) {
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci_fill_fifo no fifo mem");
return;
}
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 = bch->tx_buf + bch->tx_idx; /* 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);
}
bz->za[new_f1].z1 = new_z1; /* for next buffer */
bz->f1 = new_f1; /* next frame */
bch->tx_idx = bch->tx_len;
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
2001-08-02 14:55:45 +00:00
return;
}
2001-09-30 17:10:25 +00:00
2001-08-02 14:55:45 +00:00
#if 0
/**********************************************/
/* D-channel l1 state call for leased NT-mode */
/**********************************************/
static void
dch_nt_l2l1(struct PStack *st, int pr, void *arg)
{
hfc_pci_t *hc = (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(hc, "PH_TEST_LOOP B1");
if (2 & (long) arg)
debugl1(hc, "PH_TEST_LOOP B2");
if (!(3 & (long) arg))
debugl1(hc, "PH_TEST_LOOP DISABLED");
st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
break;
default:
if (hc->debug)
debugl1(hc, "dch_nt_l2l1 msg %04X unhandled", pr);
break;
}
}
/***********************/
/* set/reset echo mode */
/***********************/
static int
hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic)
{
int i = *(unsigned int *) ic->parm.num;
if ((ic->arg == 98) &&
(!(hc->hw.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */
Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */
udelay(10);
hc->hw.sctrl |= SCTRL_MODE_NT;
Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); /* set NT-mode */
udelay(10);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* HFC ST G1 */
udelay(10);
Write_hfc(hc, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
cs->dc.hfcpci.ph_state = 1;
hc->hw.nt_mode = 1;
hc->hw.nt_timer = 0;
cs->stlist->l2.l2l1 = dch_nt_l2l1;
debugl1(hc, "NT mode activated");
return (0);
}
if ((hc->chanlimit > 1) || (hc->hw.bswapped) ||
(hc->hw.nt_mode) || (ic->arg != 12))
return (-EINVAL);
if (i) {
cs->logecho = 1;
hc->hw.trm |= 0x20; /* enable echo chan */
hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
} else {
cs->logecho = 0;
hc->hw.trm &= ~0x20; /* disable echo chan */
hc->hw.int_m1 &= ~HFCPCI_INTS_B2REC;
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
}
hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
hc->hw.sctrl &= ~SCTRL_B2_ENA;
hc->hw.conn |= 0x10; /* B2-IOM -> B2-ST */
hc->hw.ctmt &= ~2;
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
return (0);
} /* hfcpci_auxcmd */
/*****************************/
/* E-channel receive routine */
/*****************************/
static void
receive_emsg(hfc_pci_t *hc)
{
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 *) (hc->hw.fifos))->b_chans.rxbz_b2;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b2;
Begin:
count--;
if (bz->f1 != bz->f2) {
if (hc->debug & L1_DEB_ISAC)
debugl1(hc, "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 (hc->debug & L1_DEB_ISAC)
debugl1(hc, "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 (hc->debug & L1_DEB_WARN)
debugl1(hc, "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 (hc->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;
2003-07-21 12:00:05 +00:00
mISDN_putstatus(hc, NULL, cs->dlog);
2001-08-02 14:55:45 +00:00
} else
2003-07-21 12:00:05 +00:00
mISDN_putstatus(hc, "LogEcho: ", "warning Frame too big (%d)", total - 3);
2001-08-02 14:55:45 +00:00
}
}
rcnt = bz->f1 - bz->f2;
if (rcnt < 0)
rcnt += MAX_B_FRAMES + 1;
if (rcnt > 1)
receive = 1;
else
receive = 0;
} else
receive = 0;
if (count && receive)
goto Begin;
return;
} /* receive_emsg */
#endif
/*********************/
/* Interrupt handler */
/*********************/
static void
hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
hfc_pci_t *hc = dev_id;
u_char exval;
bchannel_t *bch;
long flags;
u_char val, stat;
spin_lock_irqsave(&hc->lock.lock, flags);
#ifdef SPIN_DEBUG
hc->lock.spin_adr = (void *)0x3001;
#endif
if (!(hc->hw.int_m2 & 0x08)) {
#ifdef SPIN_DEBUG
hc->lock.spin_adr = NULL;
#endif
spin_unlock_irqrestore(&hc->lock.lock, flags);
2001-08-02 14:55:45 +00:00
return; /* not initialised */
}
2001-08-02 14:55:45 +00:00
if (HFCPCI_ANYINT & (stat = Read_hfc(hc, HFCPCI_STATUS))) {
val = Read_hfc(hc, HFCPCI_INT_S1);
if (hc->dch.debug & L1_DEB_ISAC)
2001-11-19 14:54:00 +00:00
debugprint(&hc->dch.inst, "HFC-PCI: stat(%02x) s1(%02x)",
stat, val);
} else {
/* shared */
#ifdef SPIN_DEBUG
hc->lock.spin_adr = NULL;
#endif
spin_unlock_irqrestore(&hc->lock.lock, flags);
2001-08-02 14:55:45 +00:00
return;
}
if (test_and_set_bit(STATE_FLAG_BUSY, &hc->lock.state)) {
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%x\n",
__FUNCTION__, hc->lock.state);
#ifdef SPIN_DEBUG
printk(KERN_ERR "%s: previous lock:%p\n",
__FUNCTION__, hc->lock.busy_adr);
#endif
#ifdef LOCK_STATISTIC
hc->lock.irq_fail++;
#endif
} else {
#ifdef LOCK_STATISTIC
hc->lock.irq_ok++;
#endif
#ifdef SPIN_DEBUG
hc->lock.busy_adr = hfcpci_interrupt;
#endif
}
test_and_set_bit(STATE_FLAG_INIRQ, &hc->lock.state);
#ifdef SPIN_DEBUG
hc->lock.spin_adr= NULL;
#endif
spin_unlock_irqrestore(&hc->lock.lock, flags);
2001-08-02 14:55:45 +00:00
if (hc->dch.debug & L1_DEB_ISAC)
debugprint(&hc->dch.inst, "HFC-PCI irq %x", val);
2001-08-02 14:55:45 +00:00
val &= hc->hw.int_m1;
if (val & 0x40) { /* state machine irq */
exval = Read_hfc(hc, HFCPCI_STATES) & 0xf;
if (hc->dch.debug & L1_DEB_ISAC)
debugprint(&hc->dch.inst, "ph_state chg %d->%d",
hc->dch.ph_state, exval);
hc->dch.ph_state = exval;
dchannel_sched_event(&hc->dch, D_L1STATECHANGE);
2001-08-02 14:55:45 +00:00
val &= ~0x40;
}
if (val & 0x80) { /* timer irq */
if (hc->hw.nt_mode) {
if ((--hc->hw.nt_timer) < 0)
dchannel_sched_event(&hc->dch, D_L1STATECHANGE);
2001-08-02 14:55:45 +00:00
}
val &= ~0x80;
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
}
if (val & 0x08) {
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x08 IRQ");
} else
main_rec_hfcpci(bch);
}
if (val & 0x10) {
// if (hc->logecho)
// receive_emsg(hc);
// else
if (!(bch = Sel_BCS(hc, 2))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x10 IRQ");
} else
main_rec_hfcpci(bch);
}
if (val & 0x01) {
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x01 IRQ");
} else {
if (bch->tx_idx < bch->tx_len) {
hfcpci_fill_fifo(bch);
2001-08-02 14:55:45 +00:00
} else {
bch->tx_idx = 0;
if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) {
if (bch->next_skb) {
bch->tx_len = bch->next_skb->len;
memcpy(bch->tx_buf,
bch->next_skb->data,
bch->tx_len);
hfcpci_fill_fifo(bch);
bch_sched_event(bch, B_XMTBUFREADY);
2001-08-02 14:55:45 +00:00
} else {
printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
2001-09-29 20:05:01 +00:00
bch->tx_len = 0;
2001-08-02 14:55:45 +00:00
}
} else {
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
bch_sched_event(bch, B_XMTBUFREADY);
bch->tx_len = 0;
2001-08-02 14:55:45 +00:00
}
}
}
}
if (val & 0x02) {
if (!(bch = Sel_BCS(hc, 2))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x02 IRQ");
} else {
if (bch->tx_idx < bch->tx_len) {
hfcpci_fill_fifo(bch);
2001-08-02 14:55:45 +00:00
} else {
bch->tx_idx = 0;
if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) {
if (bch->next_skb) {
bch->tx_len = bch->next_skb->len;
memcpy(bch->tx_buf,
bch->next_skb->data,
bch->tx_len);
hfcpci_fill_fifo(bch);
bch_sched_event(bch, B_XMTBUFREADY);
2001-08-02 14:55:45 +00:00
} else {
printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
2001-09-29 20:05:01 +00:00
bch->tx_len = 0;
2001-08-02 14:55:45 +00:00
}
} else {
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
bch_sched_event(bch, B_XMTBUFREADY);
bch->tx_len = 0;
2001-08-02 14:55:45 +00:00
}
}
}
}
if (val & 0x20) { /* receive dframe */
receive_dmsg(hc);
}
if (val & 0x04) { /* dframe transmitted */
if (test_and_clear_bit(FLG_DBUSY_TIMER, &hc->dch.DFlags))
del_timer(&hc->dch.dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &hc->dch.DFlags))
dchannel_sched_event(&hc->dch, D_CLEARBUSY);
if (hc->dch.tx_idx < hc->dch.tx_len) {
hfcpci_fill_dfifo(hc);
} else {
if (test_and_clear_bit(FLG_TX_NEXT, &hc->dch.DFlags)) {
if (hc->dch.next_skb) {
hc->dch.tx_len = hc->dch.next_skb->len;
memcpy(hc->dch.tx_buf,
hc->dch.next_skb->data,
hc->dch.tx_len);
hc->dch.tx_idx = 0;
hfcpci_fill_dfifo(hc);
dchannel_sched_event(&hc->dch, D_XMTBUFREADY);
} else {
printk(KERN_WARNING "hfcd tx irq TX_NEXT without skb\n");
2001-08-02 14:55:45 +00:00
test_and_clear_bit(FLG_TX_BUSY, &hc->dch.DFlags);
}
} else
test_and_clear_bit(FLG_TX_BUSY, &hc->dch.DFlags);
2001-08-02 14:55:45 +00:00
}
}
spin_lock_irqsave(&hc->lock.lock, flags);
#ifdef SPIN_DEBUG
hc->lock.spin_adr = (void *)0x3002;
#endif
if (!test_and_clear_bit(STATE_FLAG_INIRQ, &hc->lock.state)) {
}
if (!test_and_clear_bit(STATE_FLAG_BUSY, &hc->lock.state)) {
printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%x)\n",
__FUNCTION__, hc->lock.state);
}
#ifdef SPIN_DEBUG
hc->lock.busy_adr = NULL;
hc->lock.spin_adr = NULL;
#endif
spin_unlock_irqrestore(&hc->lock.lock, flags);
2001-08-02 14:55:45 +00:00
}
/********************************************************************/
/* timer callback for D-chan busy resolution. Currently no function */
/********************************************************************/
static void
hfcpci_dbusy_timer(hfc_pci_t *hc)
{
}
/*************************************/
/* Layer 1 D-channel hardware access */
/*************************************/
static int
2003-07-21 12:00:05 +00:00
HFCD_l1hw(mISDNif_t *hif, struct sk_buff *skb)
2001-08-02 14:55:45 +00:00
{
dchannel_t *dch;
hfc_pci_t *hc;
int ret = -EINVAL;
2003-07-21 12:00:05 +00:00
mISDN_head_t *hh;
2001-08-02 14:55:45 +00:00
if (!hif || !skb)
return(ret);
2003-07-21 12:00:05 +00:00
hh = mISDN_HEAD_P(skb);
2001-08-02 14:55:45 +00:00
dch = hif->fdata;
hc = dch->inst.data;
ret = 0;
if (hh->prim == PH_DATA_REQ) {
if (dch->next_skb) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: next_skb exist ERROR", __FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-EBUSY);
}
2003-06-22 12:03:36 +00:00
dch->inst.lock(dch->inst.data, 0);
2001-08-02 14:55:45 +00:00
if (test_and_set_bit(FLG_TX_BUSY, &dch->DFlags)) {
test_and_set_bit(FLG_TX_NEXT, &dch->DFlags);
dch->next_skb = skb;
dch->inst.unlock(dch->inst.data);
return(0);
} else {
dch->tx_len = skb->len;
memcpy(dch->tx_buf, skb->data, dch->tx_len);
dch->tx_idx = 0;
hfcpci_fill_dfifo(dch->inst.data);
2001-08-02 14:55:45 +00:00
dch->inst.unlock(dch->inst.data);
2002-05-01 01:00:40 +00:00
skb_trim(skb, 0);
return(if_newhead(&dch->inst.up, PH_DATA_CNF,
2001-09-29 20:05:01 +00:00
hh->dinfo, skb));
2001-08-02 14:55:45 +00:00
}
} else if (hh->prim == (PH_SIGNAL | REQUEST)) {
2003-06-22 12:03:36 +00:00
dch->inst.lock(dch->inst.data, 0);
2001-08-02 14:55:45 +00:00
if ((hh->dinfo == INFO3_P8) || (hh->dinfo == INFO3_P10)) {
2001-11-14 10:41:26 +00:00
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER;
2001-08-02 14:55:45 +00:00
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
} else
ret = -EINVAL;
dch->inst.unlock(dch->inst.data);
} else if (hh->prim == (PH_CONTROL | REQUEST)) {
2003-06-22 12:03:36 +00:00
dch->inst.lock(dch->inst.data, 0);
2001-08-02 14:55:45 +00:00
if (hh->dinfo == HW_RESET) {
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */
udelay(6);
Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */
2001-11-14 10:41:26 +00:00
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER;
2001-08-02 14:55:45 +00:00
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
// l1_msg(hc, HW_POWERUP | CONFIRM, NULL);
} else if (hh->dinfo == HW_DEACTIVATE) {
hc->hw.mst_m &= ~HFCPCI_MASTER;
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
discard_queue(&dch->rqueue);
if (dch->next_skb) {
dev_kfree_skb(dch->next_skb);
dch->next_skb = NULL;
}
test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags);
test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
del_timer(&dch->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
dchannel_sched_event(&hc->dch, D_CLEARBUSY);
2001-08-02 14:55:45 +00:00
} else if (hh->dinfo == HW_POWERUP) {
Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION);
} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
u_char slot;
2001-08-02 14:55:45 +00:00
if (1 & hh->dinfo) {
if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
slot = 0xC0;
else
slot = 0x80;
2002-09-16 23:49:38 +00:00
printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
__FUNCTION__, slot);
Write_hfc(hc, HFCPCI_B1_SSL, slot);
Write_hfc(hc, HFCPCI_B1_RSL, slot);
2001-08-02 14:55:45 +00:00
hc->hw.conn = (hc->hw.conn & ~7) | 1;
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
}
if (2 & hh->dinfo) {
if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
slot = 0xC1;
else
slot = 0x81;
2002-09-16 23:49:38 +00:00
printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
__FUNCTION__, slot);
Write_hfc(hc, HFCPCI_B2_SSL, slot);
Write_hfc(hc, HFCPCI_B2_RSL, slot);
2001-08-02 14:55:45 +00:00
hc->hw.conn = (hc->hw.conn & ~0x38) | 0x08;
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
}
if (3 & hh->dinfo)
hc->hw.trm |= 0x80; /* enable IOM-loop */
else
hc->hw.trm &= 0x7f; /* disable IOM-loop */
Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
} else {
if (dch->debug & L1_DEB_WARN)
2002-09-16 23:49:38 +00:00
debugprint(&dch->inst, "%s: unknown ctrl %x",
__FUNCTION__, hh->dinfo);
2001-08-02 14:55:45 +00:00
ret = -EINVAL;
}
dch->inst.unlock(dch->inst.data);
2001-09-29 20:05:01 +00:00
} else if (hh->prim == (PH_ACTIVATE | REQUEST)) {
if (hc->hw.nt_mode) {
2003-06-22 12:03:36 +00:00
dch->inst.lock(dch->inst.data, 0);
2001-09-29 20:05:01 +00:00
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* G0 */
udelay(6);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* G1 */
udelay(6);
2001-11-14 10:41:26 +00:00
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER;
2001-09-29 20:05:01 +00:00
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
udelay(6);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION | 1);
dch->inst.unlock(dch->inst.data);
} else {
if (dch->debug & L1_DEB_WARN)
2002-09-16 23:49:38 +00:00
debugprint(&dch->inst, "%s: PH_ACTIVATE none NT mode",
__FUNCTION__);
2001-09-29 20:05:01 +00:00
ret = -EINVAL;
}
} else if (hh->prim == (PH_DEACTIVATE | REQUEST)) {
if (hc->hw.nt_mode) {
2003-06-22 12:03:36 +00:00
dch->inst.lock(dch->inst.data, 0);
2001-09-29 20:05:01 +00:00
hc->hw.mst_m &= ~HFCPCI_MASTER;
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
discard_queue(&dch->rqueue);
if (dch->next_skb) {
dev_kfree_skb(dch->next_skb);
dch->next_skb = NULL;
}
test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags);
test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
del_timer(&dch->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
dchannel_sched_event(&hc->dch, D_CLEARBUSY);
2001-09-29 20:05:01 +00:00
dch->inst.unlock(dch->inst.data);
} else {
if (dch->debug & L1_DEB_WARN)
2002-09-16 23:49:38 +00:00
debugprint(&dch->inst, "%s: PH_DEACTIVATE none NT mode",
__FUNCTION__);
2001-09-29 20:05:01 +00:00
ret = -EINVAL;
}
2001-08-02 14:55:45 +00:00
} else {
if (dch->debug & L1_DEB_WARN)
2002-09-16 23:49:38 +00:00
debugprint(&dch->inst, "%s: unknown prim %x",
__FUNCTION__, hh->prim);
2001-08-02 14:55:45 +00:00
ret = -EINVAL;
}
if (!ret)
dev_kfree_skb(skb);
return(ret);
}
/***************************************************************/
/* activate/deactivate hardware for selected channels and mode */
/***************************************************************/
static int
mode_hfcpci(bchannel_t *bch, int bc, int protocol)
{
hfc_pci_t *hc = bch->inst.data;
int fifo2;
2001-11-14 10:41:26 +00:00
u_char rx_slot = 0, tx_slot = 0, pcm_mode;
2001-08-02 14:55:45 +00:00
if (bch->debug & L1_DEB_HSCX)
2001-11-14 10:41:26 +00:00
debugprint(&bch->inst, "HFCPCI bchannel protocol %x-->%x ch %x-->%x",
bch->protocol, protocol, bch->channel, bc);
2001-08-02 14:55:45 +00:00
fifo2 = bc;
2001-11-14 10:41:26 +00:00
pcm_mode = (bc>>24) & 0xff;
if (pcm_mode) { /* PCM SLOT USE */
if (!test_bit(HFC_CFG_PCM, &hc->cfg))
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: pcm channel id without HFC_CFG_PCM\n",
__FUNCTION__);
2001-11-14 10:41:26 +00:00
rx_slot = (bc>>8) & 0xff;
tx_slot = (bc>>16) & 0xff;
bc = bc & 0xff;
} else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_PID_NONE))
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
__FUNCTION__);
2001-08-02 14:55:45 +00:00
if (hc->chanlimit > 1) {
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
hc->hw.sctrl_e &= ~0x80;
} else {
2001-11-14 10:41:26 +00:00
if (bc & 2) {
2001-08-02 14:55:45 +00:00
if (protocol != ISDN_PID_NONE) {
hc->hw.bswapped = 1; /* B1 and B2 exchanged */
hc->hw.sctrl_e |= 0x80;
} else {
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
hc->hw.sctrl_e &= ~0x80;
}
2001-11-14 10:41:26 +00:00
fifo2 = 1;
2001-08-02 14:55:45 +00:00
} else {
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
hc->hw.sctrl_e &= ~0x80;
}
}
switch (protocol) {
case (-1): /* used for init */
bch->protocol = -1;
bch->channel = bc;
case (ISDN_PID_NONE):
if (bch->protocol == ISDN_PID_NONE) {
return(0);
}
2001-11-14 10:41:26 +00:00
if (bc & 2) {
2001-08-02 14:55:45 +00:00
hc->hw.sctrl &= ~SCTRL_B2_ENA;
hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
} else {
hc->hw.sctrl &= ~SCTRL_B1_ENA;
hc->hw.sctrl_r &= ~SCTRL_B1_ENA;
}
2001-11-14 10:41:26 +00:00
if (fifo2 & 2) {
2001-08-02 14:55:45 +00:00
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
} else {
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
}
2001-11-14 10:41:26 +00:00
if (bch->channel & 2)
2001-08-02 14:55:45 +00:00
hc->hw.cirm &= 0x7f;
else
hc->hw.cirm &= 0xbf;
bch->protocol = ISDN_PID_NONE;
bch->channel = bc;
break;
case (ISDN_PID_L1_B_64TRANS):
bch->protocol = protocol;
bch->channel = bc;
2001-11-26 17:19:26 +00:00
hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
2001-11-14 10:41:26 +00:00
if (bc & 2) {
2001-08-02 14:55:45 +00:00
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
hc->hw.cirm |= 0x80;
} else {
hc->hw.sctrl |= SCTRL_B1_ENA;
hc->hw.sctrl_r |= SCTRL_B1_ENA;
hc->hw.cirm |= 0x40;
}
2001-11-14 10:41:26 +00:00
if (fifo2 & 2) {
2001-08-02 14:55:45 +00:00
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
hc->hw.ctmt |= 2;
hc->hw.conn &= ~0x18;
} else {
hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
hc->hw.ctmt |= 1;
hc->hw.conn &= ~0x03;
}
break;
case (ISDN_PID_L1_B_64HDLC):
bch->protocol = protocol;
bch->channel = bc;
2001-11-26 17:19:26 +00:00
hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
2001-11-14 10:41:26 +00:00
if (bc & 2) {
2001-08-02 14:55:45 +00:00
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
} else {
hc->hw.sctrl |= SCTRL_B1_ENA;
hc->hw.sctrl_r |= SCTRL_B1_ENA;
}
2001-11-14 10:41:26 +00:00
if (fifo2 & 2) {
2001-08-02 14:55:45 +00:00
hc->hw.last_bfifo_cnt[1] = 0;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
hc->hw.ctmt &= ~2;
hc->hw.conn &= ~0x18;
} else {
hc->hw.last_bfifo_cnt[0] = 0;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
hc->hw.ctmt &= ~1;
hc->hw.conn &= ~0x03;
}
break;
#if 0
case (L1_MODE_EXTRN):
if (bc) {
hc->hw.conn |= 0x10;
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
} else {
hc->hw.conn |= 0x02;
hc->hw.sctrl |= SCTRL_B1_ENA;
hc->hw.sctrl_r |= SCTRL_B1_ENA;
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
}
break;
#endif
default:
debugprint(&bch->inst, "prot not known %x", protocol);
return(-ENOPROTOOPT);
}
if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
2002-07-08 12:33:04 +00:00
if ((protocol == ISDN_PID_NONE) ||
(protocol == -1)) { /* init case */
2001-11-14 10:41:26 +00:00
rx_slot = 0;
tx_slot = 0;
} else {
if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
rx_slot |= 0xC0;
tx_slot |= 0xC0;
} else {
rx_slot |= 0x80;
tx_slot |= 0x80;
}
2001-11-14 10:41:26 +00:00
}
if (bc & 2) {
hc->hw.conn &= 0xc7;
hc->hw.conn |= 0x08;
2002-09-16 23:49:38 +00:00
printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n",
__FUNCTION__, tx_slot);
printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n",
__FUNCTION__, rx_slot);
2001-11-14 10:41:26 +00:00
Write_hfc(hc, HFCPCI_B2_SSL, tx_slot);
Write_hfc(hc, HFCPCI_B2_RSL, rx_slot);
} else {
hc->hw.conn &= 0xf8;
hc->hw.conn |= 0x01;
2002-09-16 23:49:38 +00:00
printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n",
__FUNCTION__, tx_slot);
printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n",
__FUNCTION__, rx_slot);
2001-11-14 10:41:26 +00:00
Write_hfc(hc, HFCPCI_B1_SSL, tx_slot);
Write_hfc(hc, HFCPCI_B1_RSL, rx_slot);
}
}
2001-08-02 14:55:45 +00:00
Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
if (bch->protocol)
bch_sched_event(bch, B_XMTBUFREADY);
2001-08-02 14:55:45 +00:00
return(0);
}
/******************************/
/* Layer2 -> Layer 1 Transfer */
/******************************/
static int
2003-07-21 12:00:05 +00:00
hfcpci_l2l1(mISDNif_t *hif, struct sk_buff *skb)
2001-08-02 14:55:45 +00:00
{
bchannel_t *bch;
int ret = -EINVAL;
2003-07-21 12:00:05 +00:00
mISDN_head_t *hh;
2001-08-02 14:55:45 +00:00
if (!hif || !skb)
return(ret);
2003-07-21 12:00:05 +00:00
hh = mISDN_HEAD_P(skb);
2001-08-02 14:55:45 +00:00
bch = hif->fdata;
if ((hh->prim == PH_DATA_REQ) ||
(hh->prim == (DL_DATA | REQUEST))) {
if (bch->next_skb) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: next_skb exist ERROR",
__FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-EBUSY);
}
2003-06-22 12:03:36 +00:00
bch->inst.lock(bch->inst.data, 0);
if (test_and_set_bit(BC_FLG_TX_BUSY, &bch->Flag)) {
test_and_set_bit(BC_FLG_TX_NEXT, &bch->Flag);
2001-08-02 14:55:45 +00:00
bch->next_skb = skb;
bch->inst.unlock(bch->inst.data);
return(0);
} else {
bch->tx_len = skb->len;
memcpy(bch->tx_buf, skb->data, bch->tx_len);
bch->tx_idx = 0;
hfcpci_fill_fifo(bch);
2001-08-02 14:55:45 +00:00
bch->inst.unlock(bch->inst.data);
2001-09-29 20:05:01 +00:00
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
&& bch->dev)
hif = &bch->dev->rport.pif;
else
hif = &bch->inst.up;
2002-05-01 01:00:40 +00:00
skb_trim(skb, 0);
return(if_newhead(hif, hh->prim | CONFIRM,
2001-09-29 20:05:01 +00:00
hh->dinfo, skb));
2001-08-02 14:55:45 +00:00
}
} else if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
(hh->prim == (DL_ESTABLISH | REQUEST))) {
if (test_and_set_bit(BC_FLG_ACTIV, &bch->Flag))
ret = 0;
else {
2003-06-22 12:03:36 +00:00
bch->inst.lock(bch->inst.data, 0);
2001-08-02 14:55:45 +00:00
ret = mode_hfcpci(bch, bch->channel,
bch->inst.pid.protocol[1]);
bch->inst.unlock(bch->inst.data);
}
2001-09-29 20:05:01 +00:00
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
if (bch->dev)
if_link(&bch->dev->rport.pif,
hh->prim | CONFIRM, 0, 0, NULL, 0);
2002-05-01 01:00:40 +00:00
skb_trim(skb, 0);
2001-08-02 14:55:45 +00:00
return(if_newhead(&bch->inst.up, hh->prim | CONFIRM, ret, skb));
} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
(hh->prim == (DL_RELEASE | REQUEST)) ||
(hh->prim == (MGR_DISCONNECT | REQUEST))) {
2003-06-22 12:03:36 +00:00
bch->inst.lock(bch->inst.data, 0);
if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) {
2001-08-02 14:55:45 +00:00
dev_kfree_skb(bch->next_skb);
bch->next_skb = NULL;
}
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
mode_hfcpci(bch, bch->channel, ISDN_PID_NONE);
2001-08-02 14:55:45 +00:00
test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag);
bch->inst.unlock(bch->inst.data);
2002-05-01 01:00:40 +00:00
skb_trim(skb, 0);
2001-09-29 20:05:01 +00:00
if (hh->prim != (MGR_DISCONNECT | REQUEST)) {
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
if (bch->dev)
if_link(&bch->dev->rport.pif,
hh->prim | CONFIRM, 0, 0, NULL, 0);
2001-08-02 14:55:45 +00:00
if (!if_newhead(&bch->inst.up, hh->prim | CONFIRM, 0, skb))
return(0);
2001-09-29 20:05:01 +00:00
}
2001-08-02 14:55:45 +00:00
ret = 0;
} else {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: unknown prim(%x)\n",
__FUNCTION__, hh->prim);
2001-08-02 14:55:45 +00:00
ret = -EINVAL;
}
if (!ret)
dev_kfree_skb(skb);
return(ret);
}
/***************************/
/* handle L1 state changes */
/***************************/
2001-08-02 14:55:45 +00:00
static void
HW_hfcD_bh(dchannel_t *dch)
2001-08-02 14:55:45 +00:00
{
hfc_pci_t *hc = dch->inst.data;
u_int prim = PH_SIGNAL | INDICATION;
u_int para = 0;
2003-07-21 12:00:05 +00:00
mISDNif_t *upif = &dch->inst.up;
2001-08-02 14:55:45 +00:00
if (test_and_clear_bit(D_L1STATECHANGE, &dch->event)) {
if (!hc->hw.nt_mode) {
if (dch->debug)
printk(KERN_DEBUG "%s: TE newstate %x\n",
__FUNCTION__, dch->ph_state);
switch (dch->ph_state) {
case (0):
prim = PH_CONTROL | INDICATION;
para = HW_RESET;
break;
case (3):
prim = PH_CONTROL | INDICATION;
para = HW_DEACTIVATE;
break;
case (5):
case (8):
para = ANYSIGNAL;
break;
case (6):
para = INFO2;
break;
case (7):
para = INFO4_P8;
break;
default:
return;
}
} else {
if (dch->debug)
printk(KERN_DEBUG "%s: NT newstate %x\n",
__FUNCTION__, dch->ph_state);
2003-06-22 12:03:36 +00:00
dch->inst.lock(dch->inst.data, 0);
switch (dch->ph_state) {
case (2):
if (hc->hw.nt_timer < 0) {
hc->hw.nt_timer = 0;
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* Clear already pending ints */
if (Read_hfc(hc, HFCPCI_INT_S1));
Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
udelay(10);
Write_hfc(hc, HFCPCI_STATES, 4);
dch->ph_state = 4;
} else {
hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
hc->hw.ctmt |= HFCPCI_TIM3_125;
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
hc->hw.nt_timer = NT_T1_COUNT;
Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */
}
upif = NULL;
break;
case (1):
prim = PH_DEACTIVATE | INDICATION;
para = 0;
2001-08-02 14:55:45 +00:00
hc->hw.nt_timer = 0;
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
break;
case (4):
hc->hw.nt_timer = 0;
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
2001-08-02 14:55:45 +00:00
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
upif = NULL;
break;
case (3):
prim = PH_ACTIVATE | INDICATION;
para = 0;
hc->hw.nt_timer = 0;
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
break;
default:
break;
2001-08-02 14:55:45 +00:00
}
dch->inst.unlock(dch->inst.data);
}
while(upif) {
if_link(upif, prim, para, 0, NULL, 0);
upif = upif->next;
2001-08-02 14:55:45 +00:00
}
}
}
/********************************/
/* called for card init message */
/********************************/
void
inithfcpci(hfc_pci_t *hc)
{
HFC_INFO("inithfcpci: entered\n");
2003-06-21 22:25:56 +00:00
hc->dch.hw_bh = HW_hfcD_bh;
2001-08-02 14:55:45 +00:00
hc->dch.dbusytimer.function = (void *) hfcpci_dbusy_timer;
hc->dch.dbusytimer.data = (long) &hc->dch;
init_timer(&hc->dch.dbusytimer);
2001-09-29 20:05:01 +00:00
hc->chanlimit = 2;
2001-11-14 10:41:26 +00:00
mode_hfcpci(&hc->bch[0], 1, -1);
mode_hfcpci(&hc->bch[1], 2, -1);
2001-08-02 14:55:45 +00:00
}
#if 0
/*******************************************/
/* handle card messages from control layer */
/*******************************************/
static int
hfcpci_card_msg(hfc_pci_t *hc, int mt, void *arg)
{
long flags;
if (hc->debug & L1_DEB_ISAC)
debugl1(hc, "HFCPCI: card_msg %x", mt);
switch (mt) {
case CARD_RESET:
HFC_INFO("hfcpci_card_msg: CARD_RESET\n");
2001-08-02 14:55:45 +00:00
reset_hfcpci(hc);
return (0);
case CARD_RELEASE:
HFC_INFO("hfcpci_card_msg: CARD_RELEASE\n");
2001-08-02 14:55:45 +00:00
release_io_hfcpci(hc);
return (0);
case CARD_INIT:
HFC_INFO("hfcpci_card_msg: CARD_INIT\n");
2001-08-02 14:55:45 +00:00
inithfcpci(hc);
save_flags(flags);
sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */
/* now switch timer interrupt off */
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* reinit mode reg */
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
restore_flags(flags);
return (0);
case CARD_TEST:
HFC_INFO("hfcpci_card_msg: CARD_TEST\n");
2001-08-02 14:55:45 +00:00
return (0);
}
return (0);
}
#endif
static int init_card(hfc_pci_t *hc)
{
int irq_cnt, cnt = 3;
HFC_INFO("init_card: entered\n");
2001-08-02 14:55:45 +00:00
irq_cnt = kstat_irqs(hc->irq);
printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", hc->irq, irq_cnt);
2003-06-22 12:03:36 +00:00
lock_dev(hc, 0);
2001-08-02 14:55:45 +00:00
if (request_irq(hc->irq, hfcpci_interrupt, SA_SHIRQ, "HFC PCI", hc)) {
2003-07-21 12:00:05 +00:00
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
2001-08-02 14:55:45 +00:00
hc->irq);
unlock_dev(hc);
return(-EIO);
}
while (cnt) {
inithfcpci(hc);
unlock_dev(hc);
2001-11-16 01:49:21 +00:00
/* Finally enable IRQ output
* this is only allowed, if an IRQ routine is allready
* established for this HFC, so don't do that earlier
*/
hc->hw.int_m2 = HFCPCI_IRQ_ENABLE;
Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
2001-08-02 14:55:45 +00:00
/* Timeout 80ms */
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((80*HZ)/1000);
printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
hc->irq, kstat_irqs(hc->irq));
/* now switch timer interrupt off */
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* reinit mode reg */
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
if (kstat_irqs(hc->irq) == irq_cnt) {
printk(KERN_WARNING
"HFC PCI: IRQ(%d) getting no interrupts during init %d\n",
hc->irq, 4 - cnt);
if (cnt == 1) {
return (-EIO);
} else {
reset_hfcpci(hc);
cnt--;
}
} else {
return(0);
}
2003-06-22 12:03:36 +00:00
lock_dev(hc, 0);
2001-08-02 14:55:45 +00:00
}
unlock_dev(hc);
return(-EIO);
}
2001-11-14 10:41:26 +00:00
static int
SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci)
{
bchannel_t *bch;
hfc_pci_t *hfc;
2003-07-21 12:00:05 +00:00
mISDNstack_t *bst;
2001-11-14 10:41:26 +00:00
int cnr;
if (!ci)
return(-EINVAL);
ci->st.p = NULL;
bst = hc->dch.inst.st->child;
cnr=0;
while(bst) {
if(!bst->mgr) {
int_errtxt("no mgr st(%p)", bst);
return(-EINVAL);
}
hfc = bst->mgr->data;
if (!hfc) {
int_errtxt("no mgr->data st(%p)", bst);
return(-EINVAL);
}
bch = &hfc->bch[cnr & 1];
if (!(ci->channel & (~CHANNEL_NUMBER))) {
/* only number is set */
2001-12-02 13:08:08 +00:00
if ((ci->channel & 0x3) == (cnr + 1)) {
2001-11-14 10:41:26 +00:00
if (bch->protocol != ISDN_PID_NONE)
return(-EBUSY);
bch->channel = (cnr & 1) ? 2 : 1;
ci->st.p = bst;
return(0);
}
} else if ((ci->channel & (~CHANNEL_NUMBER)) == 0x00a18300) {
if (bch->protocol == ISDN_PID_NONE) {
ci->st.p = bst;
bch->channel = (cnr & 1) ? 2 : 1;
bch->channel |= CHANNEL_EXT_PCM;
bch->channel |= (ci->channel & 0x1f) << 16;
bch->channel |= (ci->channel & 0x1f) << 8;
ci->st.p = bst;
return(0);
}
}
cnr++;
bst = bst->next;
}
return(-EBUSY);
}
#define MAX_CARDS 8
#define MODULE_PARM_T "1-8i"
2001-08-02 14:55:45 +00:00
static int HFC_cnt;
static u_int protocol[MAX_CARDS];
static int layermask[MAX_CARDS];
2003-07-21 12:00:05 +00:00
static mISDNobject_t HFC_obj;
2001-08-02 14:55:45 +00:00
static int debug;
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
2002-09-16 23:49:38 +00:00
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
2001-08-02 14:55:45 +00:00
MODULE_PARM(debug, "1i");
MODULE_PARM(protocol, MODULE_PARM_T);
/* short description of protocol
* protocol=<p1>[,p2,p3...]
*
* Values:
* the value has following structure
* <bit 3 - 0> D-channel protocol id
* <bit 15 - 4> Flags for special features
* <bit 31 - 16> Spare (set to 0)
*
* D-channel protocol ids
* 1 1TR6 (not released yet)
* 2 DSS1
*
* Feature Flags
* bit 4 0x0010 Net side stack (NT mode)
* bit 5 0x0020 point to point line
* bit 6 0x0040 PCM slave mode
* bit 7 0x0080 use negativ frame pulse
* bit 8 0x0100 use setting from the previous HFC driver and add channels to
* the previous stack, used for the second chip in 2 chip setups
* bit 9 0x0200 switch DD/DU interface
* bit 10 - 15 reserved
*/
2001-08-02 14:55:45 +00:00
MODULE_PARM(layermask, MODULE_PARM_T);
#define HFC_init init_module
#endif
static char HFCName[] = "HFC_PCI";
/* this variable is used as card index when more than one cards are present */
static struct pci_dev *dev_hfcpci = NULL;
static int
setup_hfcpci(hfc_pci_t *hc)
{
char tmp[64];
int i=0;
struct pci_dev *tmp_hfcpci = NULL;
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
strcpy(tmp, hfcpci_revision);
2003-07-21 12:00:05 +00:00
printk(KERN_INFO "mISDN: HFC-PCI driver Rev. %s\n", mISDN_getrev(tmp));
2001-08-02 14:55:45 +00:00
hc->hw.cirm = 0;
hc->dch.ph_state = 0;
2001-08-02 14:55:45 +00:00
while (id_list[i].vendor_id) {
tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
id_list[i].device_id, dev_hfcpci);
i++;
if (tmp_hfcpci) {
if (pci_enable_device(tmp_hfcpci))
continue;
pci_set_master(tmp_hfcpci);
break;
}
}
if (tmp_hfcpci) {
i--;
dev_hfcpci = tmp_hfcpci; /* old device */
hc->hw.pci_bus = dev_hfcpci->bus->number;
hc->hw.pci_device_fn = dev_hfcpci->devfn;
hc->irq = dev_hfcpci->irq;
if (!hc->irq) {
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return (1);
}
2001-09-30 17:09:23 +00:00
hc->hw.pci_io = (char *) get_pcibase(dev_hfcpci, 1);
2003-07-21 12:00:05 +00:00
printk(KERN_INFO "mISDN: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
2001-08-02 14:55:45 +00:00
} else {
printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
return (1);
}
if (!hc->hw.pci_io) {
printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
return (1);
}
/* Allocate memory for FIFOS */
/* Because the HFC-PCI needs a 32K physical alignment, we */
/* need to allocate the double mem and align the address */
if (!((void *) hc->hw.share_start = kmalloc(65536, GFP_KERNEL))) {
printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
return 1;
}
(ulong) hc->hw.fifos =
(((ulong) hc->hw.share_start) & ~0x7FFF) + 0x8000;
pcibios_write_config_dword(hc->hw.pci_bus,
hc->hw.pci_device_fn, 0x80,
(u_int) virt_to_bus(hc->hw.fifos));
hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256);
printk(KERN_INFO
"HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
(u_int) hc->hw.pci_io, (u_int) hc->hw.fifos,
(u_int) virt_to_bus(hc->hw.fifos),
hc->irq, HZ);
pcibios_write_config_word(hc->hw.pci_bus, hc->hw.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
hc->hw.int_m2 = 0; /* disable alle interrupts */
2001-11-16 01:49:21 +00:00
Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
2001-08-02 14:55:45 +00:00
hc->hw.int_m1 = 0;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* At this point the needed PCI config is done */
/* fifos are still not enabled */
hc->hw.timer.function = (void *) hfcpci_Timer;
hc->hw.timer.data = (long) hc;
init_timer(&hc->hw.timer);
2003-06-22 12:03:36 +00:00
lock_dev(hc, 0);
2001-09-29 20:05:01 +00:00
#ifdef SPIN_DEBUG
printk(KERN_ERR "spin_lock_adr=%p now(%p)\n", &hc->lock.spin_adr, hc->lock.spin_adr);
printk(KERN_ERR "busy_lock_adr=%p now(%p)\n", &hc->lock.busy_adr, hc->lock.busy_adr);
2001-09-29 20:05:01 +00:00
#endif
unlock_dev(hc);
2001-08-02 14:55:45 +00:00
reset_hfcpci(hc);
return (0);
}
static void
release_card(hfc_pci_t *hc) {
2003-06-22 12:03:36 +00:00
#ifdef LOCK_STATISTIC
printk(KERN_INFO "try_ok(%d) try_wait(%d) try_mult(%d) try_inirq(%d)\n",
hc->lock.try_ok, hc->lock.try_wait, hc->lock.try_mult, hc->lock.try_inirq);
printk(KERN_INFO "irq_ok(%d) irq_fail(%d)\n",
hc->lock.irq_ok, hc->lock.irq_fail);
#endif
lock_dev(hc, 0);
2001-08-02 14:55:45 +00:00
free_irq(hc->irq, hc);
2001-11-14 10:41:26 +00:00
mode_hfcpci(&hc->bch[0], 1, ISDN_PID_NONE);
mode_hfcpci(&hc->bch[1], 2, ISDN_PID_NONE);
2001-08-02 14:55:45 +00:00
if (hc->dch.dbusytimer.function != NULL) {
del_timer(&hc->dch.dbusytimer);
hc->dch.dbusytimer.function = NULL;
}
release_io_hfcpci(hc);
free_bchannel(&hc->bch[1]);
free_bchannel(&hc->bch[0]);
free_dchannel(&hc->dch);
REMOVE_FROM_LISTBASE(hc, ((hfc_pci_t *)HFC_obj.ilist));
unlock_dev(hc);
kfree(hc);
HFC_obj.refcnt--;
}
static int
HFC_manager(void *data, u_int prim, void *arg) {
hfc_pci_t *card = HFC_obj.ilist;
2003-07-21 12:00:05 +00:00
mISDNinstance_t *inst = data;
2001-08-02 14:55:45 +00:00
struct sk_buff *skb;
int channel = -1;
if (!data) {
2002-09-16 23:49:38 +00:00
printk(KERN_ERR "%s: no data prim %x arg %p\n",
__FUNCTION__, prim, arg);
2001-08-02 14:55:45 +00:00
return(-EINVAL);
}
while(card) {
if (&card->dch.inst == inst) {
channel = 2;
break;
}
if (&card->bch[0].inst == inst) {
channel = 0;
break;
}
if (&card->bch[1].inst == inst) {
inst = &card->bch[1].inst;
channel = 1;
break;
}
card = card->next;
}
if (channel<0) {
2002-09-16 23:49:38 +00:00
printk(KERN_ERR "%s: no channel data %p prim %x arg %p\n",
__FUNCTION__, data, prim, arg);
2001-08-02 14:55:45 +00:00
return(-EINVAL);
}
switch(prim) {
case MGR_REGLAYER | CONFIRM:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: no card found\n", __FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
}
break;
case MGR_UNREGLAYER | REQUEST:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: no card found\n", __FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
} else {
if (channel == 2) {
inst->down.fdata = &card->dch;
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
HW_DEACTIVATE, 0, NULL, 0))) {
if (HFCD_l1hw(&inst->down, skb))
dev_kfree_skb(skb);
}
} else {
inst->down.fdata = &card->bch[channel];
if ((skb = create_link_skb(MGR_DISCONNECT | REQUEST,
0, 0, NULL, 0))) {
if (hfcpci_l2l1(&inst->down, skb))
dev_kfree_skb(skb);
}
}
HFC_obj.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST,
&inst->up);
HFC_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
}
break;
case MGR_RELEASE | INDICATION:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: no card found\n", __FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
} else {
if (channel == 2) {
release_card(card);
} else {
HFC_obj.refcnt--;
}
}
break;
case MGR_CONNECT | REQUEST:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: connect request failed\n",
__FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
}
return(ConnectIF(inst, arg));
break;
case MGR_SETIF | REQUEST:
case MGR_SETIF | INDICATION:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: setif failed\n", __FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
}
if (channel==2)
return(SetIF(inst, arg, prim, HFCD_l1hw, NULL,
&card->dch));
else
return(SetIF(inst, arg, prim, hfcpci_l2l1, NULL,
&card->bch[channel]));
break;
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: del interface request failed\n",
__FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
}
return(DisConnectIF(inst, arg));
break;
2001-11-14 10:41:26 +00:00
case MGR_SELCHANNEL | REQUEST:
if (channel != 2) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: selchannel not dinst\n",
__FUNCTION__);
2001-11-14 10:41:26 +00:00
return(-EINVAL);
}
return(SelFreeBChannel(card, arg));
break;
2001-08-02 14:55:45 +00:00
case MGR_SETSTACK | CONFIRM:
if (!card) {
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: setstack failed\n", __FUNCTION__);
2001-08-02 14:55:45 +00:00
return(-ENODEV);
}
2001-11-14 10:41:26 +00:00
2001-08-02 14:55:45 +00:00
if ((channel!=2) && (inst->pid.global == 2)) {
inst->down.fdata = &card->bch[channel];
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
0, 0, NULL, 0))) {
if (hfcpci_l2l1(&inst->down, skb))
dev_kfree_skb(skb);
}
if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
if_link(&inst->up, DL_ESTABLISH | INDICATION,
0, 0, NULL, 0);
else
if_link(&inst->up, PH_ACTIVATE | INDICATION,
0, 0, NULL, 0);
}
break;
default:
2002-09-16 23:49:38 +00:00
printk(KERN_WARNING "%s: prim %x not handled\n",
__FUNCTION__, prim);
2001-08-02 14:55:45 +00:00
return(-EINVAL);
}
return(0);
}
int
HFC_init(void)
{
2001-11-14 10:41:26 +00:00
int err,i;
hfc_pci_t *card, *prev;
2003-07-21 12:00:05 +00:00
mISDN_pid_t pid;
mISDNstack_t *dst;
2001-08-02 14:55:45 +00:00
SET_MODULE_OWNER(&HFC_obj);
2001-08-02 14:55:45 +00:00
HFC_obj.name = HFCName;
HFC_obj.own_ctrl = HFC_manager;
HFC_obj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 |
ISDN_PID_L0_NT_S0;
2001-09-29 20:05:01 +00:00
HFC_obj.DPROTO.protocol[1] = ISDN_PID_L1_NT_S0;
2001-08-02 14:55:45 +00:00
HFC_obj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
ISDN_PID_L1_B_64HDLC;
2001-09-29 20:05:01 +00:00
HFC_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS |
ISDN_PID_L2_B_RAWDEV;
2001-08-02 14:55:45 +00:00
HFC_obj.prev = NULL;
HFC_obj.next = NULL;
2003-07-21 12:00:05 +00:00
if ((err = mISDN_register(&HFC_obj))) {
2001-08-02 14:55:45 +00:00
printk(KERN_ERR "Can't register HFC PCI error(%d)\n", err);
return(err);
}
while (HFC_cnt < MAX_CARDS) {
if (!(card = kmalloc(sizeof(hfc_pci_t), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for HFCcard\n");
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-08-02 14:55:45 +00:00
return(-ENOMEM);
}
memset(card, 0, sizeof(hfc_pci_t));
APPEND_TO_LIST(card, ((hfc_pci_t *)HFC_obj.ilist));
card->dch.debug = debug;
card->dch.inst.obj = &HFC_obj;
lock_HW_init(&card->lock);
2001-08-02 14:55:45 +00:00
card->dch.inst.lock = lock_dev;
card->dch.inst.unlock = unlock_dev;
card->dch.inst.data = card;
card->dch.inst.pid.layermask = ISDN_LAYER(0);
card->dch.inst.up.owner = &card->dch.inst;
card->dch.inst.down.owner = &card->dch.inst;
2001-09-29 20:05:01 +00:00
HFC_obj.ctrl(NULL, MGR_DISCONNECT | REQUEST,
&card->dch.inst.up);
2001-08-02 14:55:45 +00:00
HFC_obj.ctrl(NULL, MGR_DISCONNECT | REQUEST,
&card->dch.inst.down);
sprintf(card->dch.inst.name, "HFC%d", HFC_cnt+1);
init_dchannel(&card->dch);
for (i=0; i<2; i++) {
2001-11-14 10:41:26 +00:00
card->bch[i].channel = i + 1;
2001-08-02 14:55:45 +00:00
card->bch[i].inst.obj = &HFC_obj;
card->bch[i].inst.data = card;
card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
card->bch[i].inst.up.owner = &card->bch[i].inst;
card->bch[i].inst.down.owner = &card->bch[i].inst;
HFC_obj.ctrl(NULL, MGR_DISCONNECT | REQUEST,
&card->bch[i].inst.down);
card->bch[i].inst.lock = lock_dev;
card->bch[i].inst.unlock = unlock_dev;
card->bch[i].debug = debug;
sprintf(card->bch[i].inst.name, "%s B%d",
card->dch.inst.name, i+1);
init_bchannel(&card->bch[i]);
2001-09-29 20:05:01 +00:00
if (card->bch[i].dev) {
card->bch[i].dev->wport.pif.func =
hfcpci_l2l1;
card->bch[i].dev->wport.pif.fdata =
&card->bch[i];
}
2001-08-02 14:55:45 +00:00
}
2001-11-14 10:41:26 +00:00
if (protocol[HFC_cnt] == 0x100) {
prev = card->prev;
if (!prev) {
int_errtxt("card(%d) no previous HFC",
HFC_cnt);
if (!HFC_cnt)
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-11-14 10:41:26 +00:00
else
err = 0;
return(err);
}
i = HFC_cnt - 1;
test_and_set_bit(HFC_CFG_2HFC, &prev->cfg);
test_and_set_bit(HFC_CFG_2HFC, &card->cfg);
test_and_set_bit(HFC_CFG_SLAVEHFC, &card->cfg);
} else {
prev = NULL;
i = HFC_cnt;
}
set_dchannel_pid(&pid, protocol[i] & 0xf,
layermask[i]);
test_and_set_bit(HFC_CFG_MASTER, &card->cfg);
if (protocol[i] & 0x10) {
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
card->dch.inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
pid.protocol[0] = ISDN_PID_L0_NT_S0;
pid.protocol[1] = ISDN_PID_L1_NT_S0;
card->dch.inst.pid.layermask |= ISDN_LAYER(1);
pid.layermask |= ISDN_LAYER(1);
if (layermask[i] & ISDN_LAYER(2))
pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
card->hw.nt_mode = 1;
} else {
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
card->hw.nt_mode = 0;
}
if (protocol[i] & 0x20) {
if (pid.layermask & ISDN_LAYER(2))
pid.protocol[2] |= ISDN_PID_L2_DF_PTP;
if (pid.layermask & ISDN_LAYER(3))
pid.protocol[3] |= ISDN_PID_L3_DF_PTP;
}
if (protocol[i] & 0x40) {
if (pid.layermask & ISDN_LAYER(3))
pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID;
test_and_set_bit(HFC_CFG_PCM, &card->cfg);
test_and_set_bit(HFC_CFG_SLAVE, &card->cfg);
test_and_clear_bit(HFC_CFG_MASTER, &card->cfg);
}
if (protocol[i] & 0x80) {
test_and_set_bit(HFC_CFG_NEG_F0, &card->cfg);
}
if (protocol[i] & 0x200) {
test_and_set_bit(HFC_CFG_SW_DD_DU, &card->cfg);
}
2001-08-02 14:55:45 +00:00
printk(KERN_DEBUG "HFC card %p dch %p bch1 %p bch2 %p\n",
card, &card->dch, &card->bch[0], &card->bch[1]);
if (setup_hfcpci(card)) {
err = 0;
free_dchannel(&card->dch);
free_bchannel(&card->bch[1]);
free_bchannel(&card->bch[0]);
REMOVE_FROM_LISTBASE(card, ((hfc_pci_t *)HFC_obj.ilist));
kfree(card);
if (!HFC_cnt) {
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-08-02 14:55:45 +00:00
err = -ENODEV;
} else
printk(KERN_INFO "HFC %d cards installed\n",
HFC_cnt);
return(err);
}
HFC_cnt++;
2001-11-14 10:41:26 +00:00
if (prev) {
dst = prev->dch.inst.st;
} else {
if ((err = HFC_obj.ctrl(NULL, MGR_NEWSTACK | REQUEST,
&card->dch.inst))) {
printk(KERN_ERR "MGR_ADDSTACK REQUEST dch err(%d)\n", err);
release_card(card);
if (!HFC_cnt)
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-11-14 10:41:26 +00:00
else
err = 0;
return(err);
}
dst = card->dch.inst.st;
2001-08-02 14:55:45 +00:00
}
2001-11-14 10:41:26 +00:00
for (i = 0; i < 2; i++) {
if ((err = HFC_obj.ctrl(dst,
MGR_NEWSTACK | REQUEST, &card->bch[i].inst))) {
2001-08-02 14:55:45 +00:00
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
HFC_obj.ctrl(card->dch.inst.st,
MGR_DELSTACK | REQUEST, NULL);
if (!HFC_cnt)
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-08-02 14:55:45 +00:00
else
err = 0;
return(err);
}
2001-11-14 10:41:26 +00:00
card->bch[i].st = card->bch[i].inst.st;
}
if (protocol[HFC_cnt] != 0x100) { /* next not second HFC */
if ((err = HFC_obj.ctrl(dst, MGR_SETSTACK | REQUEST,
&pid))) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n",
err);
HFC_obj.ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
if (!HFC_cnt)
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-11-14 10:41:26 +00:00
else
err = 0;
return(err);
}
2001-08-02 14:55:45 +00:00
}
if ((err = init_card(card))) {
2001-11-14 10:41:26 +00:00
HFC_obj.ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
2001-08-02 14:55:45 +00:00
if (!HFC_cnt)
2003-07-21 12:00:05 +00:00
mISDN_unregister(&HFC_obj);
2001-08-02 14:55:45 +00:00
else
err = 0;
return(err);
}
}
printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
return(0);
}
#ifdef MODULE
int
cleanup_module(void)
{
int err;
2003-07-21 12:00:05 +00:00
if ((err = mISDN_unregister(&HFC_obj))) {
2001-08-02 14:55:45 +00:00
printk(KERN_ERR "Can't unregister HFC PCI error(%d)\n", err);
return(err);
}
while(HFC_obj.ilist) {
printk(KERN_ERR "HFC PCI card struct not empty refs %d\n",
HFC_obj.refcnt);
release_card(HFC_obj.ilist);
}
2001-08-02 14:55:45 +00:00
return(0);
}
#endif