update version of ST5481 driver

first version of new Fritz!PCI/PnP driver (also supports PCI v2)
This commit is contained in:
Kai Germaschewski 2001-08-15 10:25:49 +00:00
parent a7c9cd8c7f
commit 276d17903c
20 changed files with 2756 additions and 619 deletions

View File

@ -114,7 +114,9 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
dep_tristate 'Colognechip HFC-USB support' CONFIG_HISAX_HFC_USB_CS $CONFIG_HISAX $CONFIG_USB
dep_tristate 'ST5481 USB ISDN modem' CONFIG_HISAX_ST5481_CS $CONFIG_HISAX $CONFIG_USB
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
if [ "$CONFIG_HISAX_SEDLBAUER_CS" != "n" ]; then
define_bool CONFIG_HISAX_SEDLBAUER y
fi
@ -127,6 +129,8 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
if [ "$CONFIG_HISAX_ST5481_CS" != "n" ]; then
define_bool CONFIG_HISAX_ST5481 y
fi
bool ' HiSax debugging' CONFIG_HISAX_DEBUG
fi
endmenu

View File

@ -2,19 +2,19 @@
# The target object and module list name.
O_TARGET := vmlinux-obj.o
O_TARGET := vmlinux-obj.o
# Objects that export symbols.
export-objs := config.o fsm.o
export-objs := config.o fsm.o hisax_isac.o
# Multipart objects.
list-multi := hisax.o st5481_mod.o
hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o cert.o
st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
st5481_hdlc.o
list-multi := hisax.o st5481_mod.o
hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o cert.o
hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
st5481_hdlc.o
# Optional parts of multipart objects.
hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
@ -28,7 +28,6 @@ hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
@ -60,12 +59,9 @@ 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_HFC_USB_CS) += hfc_usb.o
obj-$(CONFIG_HISAX_ST5481_CS) += st5481.o
obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_fcpcipnp.o hisax_isac.o
MD5FILES := isac.c isdnl1.c isdnl2.c isdnl3.c \
tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
elsa.c diva.c sedlbauer.c hfc_pci.c \
hfc_usbr.c hfc_usb.c
CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
@ -76,5 +72,5 @@ include $(TOPDIR)/drivers/isdn/Rules.make
hisax.o: $(hisax-objs)
$(LD) -r -o $@ $(hisax-objs)
st5481.o: $(st5481-objs)
$(LD) -r -o $@ $(st5481-objs)
hisax_st5481.o: $(hisax_st5481-objs)
$(LD) -r -o $@ $(hisax_st5481-objs)

View File

@ -326,7 +326,8 @@ EXPORT_SYMBOL(hfc_init_pcmcia);
#define DEFAULT_PROTO_NAME "UNKNOWN"
#endif
#ifndef DEFAULT_CARD
#error "HiSax: No cards configured"
#define DEFAULT_CARD 0
#define DEFAULT_CFG {0,0,0,0}
#endif
int hisax_init_pcmcia(void *, int *, struct IsdnCard *);
@ -1805,6 +1806,7 @@ 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 IsdnCardState *cs);
static void EChannel_proc_rcv(struct hisax_d_if *d_if);
int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
char *name, int protocol)
@ -1846,13 +1848,17 @@ int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
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"
@ -1866,8 +1872,22 @@ static void hisax_sched_event(struct IsdnCardState *cs, int event)
static void hisax_bh(struct IsdnCardState *cs)
{
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)
@ -1898,12 +1918,12 @@ static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg)
switch (pr) {
case PH_ACTIVATE | INDICATION:
for (st = cs->stlist; st; st = st->next)
st->l1.l1l2(st, pr, NULL);
set_bit(0, &d_if->ph_state);
hisax_sched_event(cs, D_L1STATECHANGE);
break;
case PH_DEACTIVATE | INDICATION:
for (st = cs->stlist; st; st = st->next)
st->l1.l1l2(st, pr, NULL);
clear_bit(0, &d_if->ph_state);
hisax_sched_event(cs, D_L1STATECHANGE);
break;
case PH_DATA | INDICATION:
skb_queue_tail(&cs->rq, arg);
@ -1913,15 +1933,18 @@ static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg)
skb = skb_dequeue(&cs->sq);
if (skb) {
D_L2L1(d_if, PH_DATA | REQUEST, skb);
} else {
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;
}
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);
@ -2058,6 +2081,35 @@ static void hisax_bc_close(struct BCState *bcs)
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);
}
}
#include <linux/pci.h>
static struct pci_device_id hisax_pci_tbl[] __initdata = {

View File

@ -1,3 +1,6 @@
#ifndef __FSM_H__
#define __FSM_H__
#include <linux/timer.h>
struct FsmInst;
@ -41,3 +44,5 @@ int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
void *arg, int where);
void FsmDelTimer(struct FsmTimer *ft, int where);
#endif

View File

@ -0,0 +1,80 @@
/*
* Common debugging macros for use with the hisax driver
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
*
* 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 __FUNCTION__ ": " format "\n" , ## arg); \
} while (0)
#define DBG_PACKET(level,data,count) \
if (level & __debug_variable) dump_packet(__FUNCTION__,data,count)
#define DBG_SKB(level,skb) \
if ((level & __debug_variable) && skb) dump_packet(__FUNCTION__,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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
#include "hisax_if.h"
#include "hisax_isac.h"
#include <linux/pci.h>
#define HSCX_BUFMAX 4096
enum {
AVM_FRITZ_PCI,
AVM_FRITZ_PNP,
AVM_FRITZ_PCIV2,
};
struct hdlc_stat_reg {
#ifdef __BIG_ENDIAN
u_char fill __attribute__((packed));
u_char mode __attribute__((packed));
u_char xml __attribute__((packed));
u_char cmd __attribute__((packed));
#else
u_char cmd __attribute__((packed));
u_char xml __attribute__((packed));
u_char mode __attribute__((packed));
u_char fill __attribute__((packed));
#endif
};
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;
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 {
struct list_head list;
struct pci_dev *pci_dev;
int type;
spinlock_t hw_lock;
unsigned int io;
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);
};

View File

@ -1,6 +1,8 @@
#ifndef __HISAX_IF_H__
#define __HISAX_IF_H__
#include <linux/skbuff.h>
#define REQUEST 0
#define CONFIRM 1
#define INDICATION 2
@ -10,6 +12,7 @@
#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
@ -39,6 +42,8 @@ struct hisax_d_if {
// private to hisax
struct IsdnCardState *cs;
struct hisax_b_if *b_if[2];
struct sk_buff_head erq;
long ph_state;
};
int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],

View File

@ -0,0 +1,891 @@
/*
* Driver for ISAC-S and ISAC-SX
* ISDN Subscriber Access Controller for Terminals
*
* Author Kai Germaschewski
* Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
* 2001 by Karsten Keil <keil@isdn4linux.de>
*
* based upon Karsten Keil's original isac.c driver
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Wizard Computersysteme GmbH, Bremervoerde and
* SoHaNet Technology GmbH, Berlin
* for supporting the development of this driver
*/
/* TODO:
* specifically handle level vs edge triggered?
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include "hisax_isac.h"
// debugging cruft
#define __debug_variable debug
#include "hisax_debug.h"
#ifdef CONFIG_HISAX_DEBUG
static int debug = 1;
MODULE_PARM(debug, "i");
static char *ISACVer[] __devinitdata = {
"2086/2186 V1.1",
"2085 B1",
"2085 B2",
"2085 V2.3"
};
#endif
#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);
vsprintf(buf, fmt, args);
DBG(DBG_L1M, "%s", buf);
va_end(args);
}
static void __devinit 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;
if (!isac->tx_skb)
BUG();
count = isac->tx_skb->len;
if (count <= 0)
BUG();
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;
}
memcpy(skb_put(skb, count), 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_interrupt(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");
}
}
// ======================================================================
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;
}
memcpy(skb_put(skb, count), 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_interrupt(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 __devinit 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 __devinit 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(HW_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;
}
if (isac->tx_skb)
BUG();
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_interrupt);
EXPORT_SYMBOL(isac_setup);
EXPORT_SYMBOL(isac_interrupt);
module_init(hisax_isac_init);
module_exit(hisax_isac_exit);

View File

@ -0,0 +1,45 @@
#ifndef __HISAX_ISAC_H__
#define __HISAX_ISAC_H__
#include <linux/kernel.h>
#include "fsm.h"
#include "hisax_if.h"
#define TIMER3_VALUE 7000
#define MAX_DFRAME_LEN_L1 300
#define HW_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_interrupt(struct isac *isac);
void isacsx_setup(struct isac *isac);
void isacsx_interrupt(struct isac *isac);
#endif

View File

@ -14,6 +14,7 @@
#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

View File

@ -1414,8 +1414,8 @@ l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
freewin(st);
st->l2.tei = -1;
stop_t200(st, 17);
st5_dl_release_l2l3(st);
FsmChangeState(fi, ST_L2_1);
st5_dl_release_l2l3(st);
}
static void

View File

@ -24,50 +24,10 @@
if (level & ST5481_DEBUG) \
printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg) \
static inline const char *
ST5481_IND_string(int evt)
{
static char s[16];
switch(evt) {
case ST5481_IND_DP: return "DP";
case ST5481_IND_RSY: return "RSY";
case ST5481_IND_AP: return "AP";
case ST5481_IND_AI8: return "AI8";
case ST5481_IND_AI10: return "AI10";
case ST5481_IND_AIL: return "AIL";
case ST5481_IND_DI: return "DI";
}
sprintf(s,"0x%x",evt);
return s;
}
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;
}
static inline void
dump_packet(const char *name,const u_char *data,int pkt_len)
{
#define DUMP_HDR_SIZE 20
#define DUMP_HDR_SIZE 200
#define DUMP_TLR_SIZE 8
if (pkt_len) {
int i,len1,len2;

View File

@ -1,14 +1,27 @@
#ifndef _ST5481__H_
#define _ST5481__H_
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef _ST5481_H_
#define _ST5481_H_
// USB IDs, the Product Id is in the range 0x4810-0x481F
#define ST_VENDOR_ID 0x0483
#define ST5481_PRODUCT_ID 0x4810 /* The Product Id is in the range 0x4810-0x481F */
#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.
*/
// 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 */
@ -18,27 +31,27 @@
#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.
*/
// 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.
*/
// 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.
*/
// 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 */
@ -74,16 +87,14 @@
#define TXCI 0x56 /* CI command to be transmitted */
/*
Format of the interrupt packet received on endpoint 1:
// Format of the interrupt packet received on endpoint 1:
//
// +--------+--------+--------+--------+--------+--------+
// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
// +--------+--------+--------+--------+--------+--------+
+--------+--------+--------+--------+--------+--------+
!MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
+--------+--------+--------+--------+--------+--------+
// Offsets in the interrupt packet
*/
/* Offsets in the interrupt packet */
#define MPINT 0
#define FFINT_D 1
#define FFINT_B1 2
@ -92,7 +103,7 @@
#define GPIO_INT 5
#define INT_PKT_SIZE 6
/* MPINT */
// 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 */
@ -102,7 +113,7 @@
#define DRXON_INT 0x02 /* Reception channel active */
#define GPCHG_INT 0x01 /* GPIO pin value changed */
/* FFINT_x */
// 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 */
@ -115,17 +126,8 @@
#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 indications that are found at offset 4 (CCIST)
in the interrupt packet */
#define ST5481_IND_DP 0x0 /* Deactivation Pending */
#define ST5481_IND_RSY 0x4 /* ReSYnchronizing */
#define ST5481_IND_AP 0x8 /* Activation Pending */
#define ST5481_IND_AI8 0xC /* Activation Indication class 8 */
#define ST5481_IND_AI10 0xD /* Activation Indication class 10 */
#define ST5481_IND_AIL 0xE /* Activation Indication Loopback */
#define ST5481_IND_DI 0xF /* Deactivation Indication */
/* Level 1 commands that are sent using the TXCI device request */
// 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 */
@ -136,15 +138,14 @@
#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 */
// 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 */
// D channel out states
enum {
ST_DOUT_NONE,
@ -163,7 +164,7 @@ enum {
#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1)
/* D channel out events */
// D channel out events
enum {
EV_DOUT_START_XMIT,
EV_DOUT_COMPLETE,
@ -172,12 +173,48 @@ enum {
EV_DOUT_STOPPED,
EV_DOUT_COLL,
EV_DOUT_UNDERRUN,
DXMIT_NOT_BUSY,
};
#define DOUT_EVENT_COUNT (DXMIT_NOT_BUSY + 1)
#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1)
#define MIN(a,b) ((a)<(b) ? (a):(b))
// ----------------------------------------------------------------------
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 __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
@ -188,7 +225,6 @@ printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
#define INFO(format, arg...) \
printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
#include "st5481-debug.h"
#include "st5481_hdlc.h"
#include "fsm.h"
#include "hisax_if.h"
@ -265,21 +301,6 @@ static inline int fifo_remove(struct fifo *fifo)
return index;
}
// ----------------------------------------------------------------------
/* FIFO of received interrupt events */
struct evt {
int pr;
void *arg;
};
#define MAX_EVT_FIFO 16
struct evt_fifo {
struct fifo f;
struct evt data[MAX_EVT_FIFO];
};
/* ======================================================================
* control pipe
*/
@ -308,7 +329,7 @@ struct st5481_ctrl {
};
struct st5481_intr {
struct evt_fifo evt_fifo;
// struct evt_fifo evt_fifo;
struct urb *urb;
};
@ -369,9 +390,7 @@ struct st5481_adapter {
unsigned int led_counter;
unsigned long event;
struct tq_struct tqueue;
int ph_state;
struct FsmInst l1m;
struct FsmTimer timer;
@ -414,8 +433,6 @@ void st5481_release_b(struct st5481_bcs *bcs);
void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
/* D Channel */
#define D_L1STATECHANGE 2
#define D_OUT_EVENT 10
int st5481_setup_d(struct st5481_adapter *adapter);
void st5481_release_d(struct st5481_adapter *adapter);
@ -423,9 +440,6 @@ void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg);
int st5481_d_init(void);
void st5481_d_exit(void);
void st5481_sched_event(struct st5481_adapter *adapter, int event);
void st5481_sched_d_out_event(struct st5481_adapter *adapter,
int event, void *arg);
/* USB */
void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command);
int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
@ -448,4 +462,72 @@ 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"
#ifdef CONFIG_HISAX_DEBUG
extern int st5481_debug;
#define DBG_ISO_PACKET(level,urb) \
if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
static void __attribute__((unused))
dump_iso_packet(const char *name,urb_t *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

View File

@ -1,3 +1,15 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@ -6,9 +18,9 @@
#include <linux/netdevice.h>
#include "st5481.h"
static inline void B_L1L2(struct hisax_b_if *b_if, int pr, void *arg)
static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
{
struct hisax_if *ifc = (struct hisax_if *) b_if;
struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
ifc->l1l2(ifc, pr, arg);
}
@ -50,13 +62,15 @@ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
len = 0;
while (len < buf_size) {
if ((skb = b_out->tx_skb)) {
DUMP_SKB(0x100, skb);
DBG_SKB(0x100, skb);
DBG(4,"B%d,len=%d",bcs->channel+1,skb->len);
if (bcs->mode == L1_MODE_TRANS) {
bytes_sent = MIN(buf_size - len, skb->len);
bytes_sent = buf_size - len;
if (skb->len < bytes_sent)
bytes_sent = skb->len;
memcpy(urb->transfer_buffer+len, skb->data, buf_size);
memcpy(urb->transfer_buffer+len, skb->data, bytes_sent);
len += bytes_sent;
} else {
@ -70,8 +84,7 @@ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
if (!skb->len) {
// Frame sent
b_out->tx_skb = NULL;
B_L1L2(&bcs->b_if, PH_DATA | CONFIRM,
(void *) skb->truesize);
B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
dev_kfree_skb_any(skb);
/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
@ -102,7 +115,7 @@ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
urb->number_of_packets = i;
urb->dev = adapter->usb_dev;
DUMP_ISO_PACKET(0x200,urb);
DBG_ISO_PACKET(0x200,urb);
SUBMIT_URB(urb);
}
@ -324,7 +337,6 @@ void __devexit st5481_release_b(struct st5481_bcs *bcs)
*/
void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
{
struct hisax_b_if *b_if = (struct hisax_b_if *) ifc;
struct st5481_bcs *bcs = ifc->priv;
struct sk_buff *skb = arg;
int mode;
@ -342,12 +354,12 @@ void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
mode = (int) arg;
DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
st5481B_mode(bcs, mode);
B_L1L2(b_if, PH_ACTIVATE | INDICATION, NULL);
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(b_if, PH_DEACTIVATE | INDICATION, NULL);
B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
break;
default:
WARN("pr %#x\n", pr);

View File

@ -1,3 +1,15 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@ -8,79 +20,9 @@
static void ph_connect(struct st5481_adapter *adapter);
static void ph_disconnect(struct st5481_adapter *adapter);
static void st5481_d_out_event(struct st5481_adapter *adapter);
/*
* delay processing to bh
*/
void st5481_sched_event(struct st5481_adapter *adapter, int event)
{
test_and_set_bit(event, &adapter->event);
queue_task(&adapter->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
/*
* Schedule the D_OUT_EVENT.
* The actual event is stored in a FIFO.
*/
void st5481_sched_d_out_event(struct st5481_adapter *adapter,
int event, void *arg)
{
struct st5481_intr *intr = &adapter->intr;
int w_index;
// DBG(2,"event=%s",D_EVENT_string(event));
w_index = fifo_add(&intr->evt_fifo.f);
if (w_index < 0) {
WARN("D_OUT event FIFO full");
return;
}
intr->evt_fifo.data[w_index].pr = event;
intr->evt_fifo.data[w_index].arg = arg;
// Schedule to tell that an event has been added
st5481_sched_event(adapter, D_OUT_EVENT);
}
static void st5481_new_ph(struct st5481_adapter *adapter);
static void st5481_bh(struct st5481_adapter *adapter)
{
#if 0
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
#endif
if (test_and_clear_bit(D_L1STATECHANGE, &adapter->event)) {
st5481_new_ph(adapter);
}
if (test_and_clear_bit(D_OUT_EVENT, &adapter->event)) {
st5481_d_out_event(adapter);
}
}
static struct Fsm l1fsm;
enum {
ST_L1_F3,
ST_L1_F4,
ST_L1_F6,
ST_L1_F7,
ST_L1_F8,
};
#define L1_STATE_COUNT (ST_L1_F8+1)
static char *strL1State[] =
{
"ST_L1_F3",
@ -90,36 +32,32 @@ static char *strL1State[] =
"ST_L1_F8",
};
enum {
EV_PH_ACTIVATE_REQ,
EV_PH_DEACTIVATE_REQ,
EV_IND_DI,
EV_IND_DP,
EV_IND_RSY,
EV_IND_AP,
EV_IND_AI8,
EV_IND_AI10,
EV_TIMER3,
};
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
static char *strL1Event[] =
{
"EV_PH_ACTIVATE_REQ",
"EV_PH_DEACTIVATE_REQ",
"EV_IND_DI",
"EV_IND_DP",
"EV_IND_RSY",
"EV_IND_AP",
"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 hisax_d_if *d_if, int pr, void *arg)
static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg)
{
struct hisax_if *ifc = (struct hisax_if *) d_if;
struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if;
ifc->l1l2(ifc, pr, arg);
}
@ -133,7 +71,7 @@ l1_go_f3(struct FsmInst *fi, int event, void *arg)
ph_disconnect(adapter);
FsmChangeState(fi, ST_L1_F3);
D_L1L2(&adapter->hisax_d_if, PH_DEACTIVATE | INDICATION, NULL);
D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
}
static void
@ -155,7 +93,7 @@ l1_go_f7(struct FsmInst *fi, int event, void *arg)
FsmDelTimer(&adapter->timer, 0);
ph_connect(adapter);
FsmChangeState(fi, ST_L1_F7);
D_L1L2(&adapter->hisax_d_if, PH_ACTIVATE | INDICATION, NULL);
D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);
}
static void
@ -176,7 +114,7 @@ l1_timer3(struct FsmInst *fi, int event, void *arg)
st5481_ph_command(adapter, ST5481_CMD_DR);
FsmChangeState(fi, ST_L1_F3);
D_L1L2(&adapter->hisax_d_if, PH_DEACTIVATE | INDICATION, NULL);
D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
}
static void
@ -238,39 +176,11 @@ static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
va_start(args, fmt);
vsprintf(buf, fmt, args);
printk("buf %s\n", buf);
DBG(8, "%s", buf);
va_end(args);
}
static void st5481_new_ph(struct st5481_adapter *adapter)
{
DBG(8,"state=%s", ST5481_IND_string(adapter->ph_state));
switch (adapter->ph_state) {
case ST5481_IND_DI:
FsmEvent(&adapter->l1m, EV_IND_DI, NULL);
break;
case ST5481_IND_DP:
FsmEvent(&adapter->l1m, EV_IND_DP, NULL);
break;
case ST5481_IND_RSY:
FsmEvent(&adapter->l1m, EV_IND_RSY, NULL);
break;
case ST5481_IND_AP:
FsmEvent(&adapter->l1m, EV_IND_AP, NULL);
break;
case ST5481_IND_AI8:
FsmEvent(&adapter->l1m, EV_IND_AI8, NULL);
break;
case ST5481_IND_AI10:
FsmEvent(&adapter->l1m, EV_IND_AI10, NULL);
break;
default:
WARN("unknown st5481.ph_state %x", adapter->ph_state);
break;
}
}
/* ======================================================================
* D-Channel out
*/
@ -360,7 +270,6 @@ static char *strDoutEvent[] =
"EV_DOUT_STOPPED",
"EV_DOUT_COLL",
"EV_DOUT_UNDERRUN",
"DXMIT_NOT_BUSY",
};
static void dout_debug(struct FsmInst *fi, char *fmt, ...)
@ -378,7 +287,7 @@ static void dout_stop_event(void *context)
{
struct st5481_adapter *adapter = context;
st5481_sched_d_out_event(adapter, EV_DOUT_STOPPED, NULL);
FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL);
}
/*
@ -391,6 +300,7 @@ static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
unsigned int num_packets, packet_offset;
int len, buf_size, bytes_sent;
struct sk_buff *skb;
iso_packet_descriptor_t *desc;
if (d_out->fsm.state != ST_DOUT_NORMAL)
return;
@ -422,27 +332,32 @@ static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
}
if (skb && !skb->len) {
d_out->tx_skb = NULL;
D_L1L2(&adapter->hisax_d_if, PH_DATA | CONFIRM, NULL);
D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
dev_kfree_skb_any(skb);
}
// Prepare the URB
urb->transfer_buffer_length = len;
for (num_packets = 0, packet_offset = 0; packet_offset < len;
num_packets++, packet_offset += SIZE_ISO_PACKETS_D_OUT) {
urb->iso_frame_desc[num_packets].offset = packet_offset;
urb->iso_frame_desc[num_packets].length =
MIN(SIZE_ISO_PACKETS_D_OUT, len - packet_offset);
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 8ms after the DEN_EVENT
// 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;
DUMP_ISO_PACKET(0x20,urb);
DBG_ISO_PACKET(0x20,urb);
if (usb_submit_urb(urb) < 0) {
// There is another URB queued up
@ -455,27 +370,7 @@ static void fifo_reseted(void *context)
{
struct st5481_adapter *adapter = context;
st5481_sched_d_out_event(adapter, EV_DOUT_RESETED, NULL);
}
/*
* Remove the event from the FIFO and call the OUT D
* state machine.
*/
static void st5481_d_out_event(struct st5481_adapter *adapter)
{
struct st5481_intr *intr = &adapter->intr;
struct st5481_d_out *d_out = &adapter->d_out;
int r_index;
int event;
void *arg;
while ((r_index = fifo_remove(&intr->evt_fifo.f)) >= 0) {
event = intr->evt_fifo.data[r_index].pr;
arg = intr->evt_fifo.data[r_index].arg;
FsmEvent(&d_out->fsm, event, arg);
}
FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
}
static void usb_d_out_complete(struct urb *urb)
@ -502,11 +397,7 @@ static void usb_d_out_complete(struct urb *urb)
}
}
if (d_out->fsm.state == ST_DOUT_NORMAL)
// submit next urb directly from irq context
usb_d_out(adapter, buf_nr);
else
st5481_sched_d_out_event(adapter, EV_DOUT_COMPLETE, NULL);
FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr);
}
/* ====================================================================== */
@ -533,7 +424,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
}
urb = d_out->urb[buf_nr];
DUMP_SKB(0x10, skb);
DBG_SKB(0x10, skb);
len = hdlc_encode(&d_out->hdlc_state,
skb->data, skb->len, &bytes_sent,
urb->transfer_buffer, 16);
@ -546,7 +437,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
if (skb->len == 0) {
d_out->tx_skb = NULL;
D_L1L2(&adapter->hisax_d_if, PH_DATA | CONFIRM, NULL);
D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
dev_kfree_skb_any(skb);
}
@ -561,7 +452,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
urb->dev = adapter->usb_dev;
urb->transfer_flags = USB_ISO_ASAP;
DUMP_ISO_PACKET(0x20,urb);
DBG_ISO_PACKET(0x20,urb);
SUBMIT_URB(urb);
}
@ -651,6 +542,14 @@ static void dout_reseted(struct FsmInst *fsm, int event, void *arg)
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;
int buf_nr = (int) arg;
usb_d_out(adapter, buf_nr);
}
static void dout_ignore(struct FsmInst *fsm, int event, void *arg)
{
}
@ -670,9 +569,7 @@ static struct FsmNode DoutFnList[] __initdata =
{ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
{ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun},
// {ST_DOUT_NORMAL, DV_DOUT_COMPLETE, ...},
// refilling the fifo is directly handled from irq context, not through
// this state machine
{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},
@ -725,8 +622,8 @@ static void ph_connect(struct st5481_adapter *adapter)
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, 0xff, NULL, NULL);
// 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);
#if LOOPBACK
@ -808,7 +705,6 @@ int __devinit st5481_setup_d(struct st5481_adapter *adapter)
if (retval)
goto err_d_out;
INIT_TQUEUE(&adapter->tqueue, (void *)(void *)st5481_bh, adapter);
adapter->l1m.fsm = &l1fsm;
adapter->l1m.state = ST_L1_F3;
adapter->l1m.debug = 1;
@ -870,7 +766,9 @@ int __init st5481_d_init(void)
return retval;
}
void __exit st5481_d_exit(void)
// can't be __exit
void st5481_d_exit(void)
{
FsmFree(&l1fsm);
FsmFree(&dout_fsm);
}

View File

@ -1,7 +1,18 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "st5481_hdlc.h"
static const unsigned short int crc16_tab[]={
static const unsigned short int crc16_tab[] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
@ -236,7 +247,7 @@ int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src,
} else {
switch(hdlc->hdlc_bits1){
case 5:
break;
break;
case 6:
if(hdlc->data_received){
if (hdlc->dstpos < 2) {
@ -350,260 +361,260 @@ int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src,
dsize - destination buffer size
returns - number of encoded bytes in the destination buffer
*/
int
hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src, unsigned short slen, int *count,
unsigned char *dst, int dsize)
int hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src,
unsigned short slen, int *count,
unsigned char *dst, int dsize)
{
static const unsigned char xfast_flag_value[]={
0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
};
static const unsigned char xfast_flag_value[] = {
0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
};
int len = 0;
int len = 0;
*count = slen;
*count = slen;
while (dsize > 0) {
if(hdlc->bit_shift==0){
if(slen && !hdlc->do_closing){
hdlc->shift_reg = *src++;
slen--;
if (slen == 0)
hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
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){
*dst++ = hdlc->ffvalue;
len++;
dsize--;
break;
}
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){
unsigned cval;
cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
}
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;
while (dsize > 0) {
if(hdlc->bit_shift==0){
if(slen && !hdlc->do_closing){
hdlc->shift_reg = *src++;
slen--;
if (slen == 0)
hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
hdlc->bit_shift = 8;
} 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;
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;
}
}
// Finished with 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 {
*dst++ = hdlc->cbin;
hdlc->bit_shift = hdlc->data_bits = 0;
len++;
dsize = 0;
}
break;
default:
break;
}
if(hdlc->do_adapt56){
if(hdlc->data_bits==7){
switch(hdlc->state){
case STOPPED:
while (dsize--)
*dst++ = 0xff;
return dsize;
case HDLC_SEND_FAST_FLAG:
hdlc->do_closing = 0;
if(slen == 0){
*dst++ = hdlc->ffvalue;
len++;
dsize--;
break;
}
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){
unsigned cval;
cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
}
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 with 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 {
*dst++ = hdlc->cbin;
hdlc->bit_shift = 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){
*dst++ = hdlc->cbin;
hdlc->data_bits = 0;
len++;
dsize--;
}
}
if(hdlc->data_bits==8){
*dst++ = hdlc->cbin;
hdlc->data_bits = 0;
len++;
dsize--;
}
}
*count -= slen;
*count -= slen;
return len;
return len;
}

View File

@ -1,5 +1,17 @@
#ifndef __ST5481_HDLC__
#define __ST5481_HDLC__
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __ST5481_HDLC_H__
#define __ST5481_HDLC_H__
struct hdlc_vars {
int bit_shift;

View File

@ -1,9 +1,12 @@
/*
*
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen (fisaksen@bewan.com)
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
@ -11,29 +14,26 @@
* TODO:
*
* b layer1 delay?
* d out fsm
* hdlc as module
* hotplug / unregister issues
* mod_inc/dec_use_count
* unify parts of d/b channel usb handling
* file header
* PH_PAUSE?
* evt queue w/o arg?
* avoid copy to isoc buffer?
* improve usb delay?
* merge l1 state machines?
* clean up debug
*/
static const char *st5481_revision = "$Revision$";
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include "st5481.h"
MODULE_AUTHOR("Frode Isaksen <fisaksen@bewan.com>");
MODULE_DESCRIPTION("ST5481 USB ISDN modem");
MODULE_DESCRIPTION("ST5481 USB ISDN modem driver");
static int protocol = 2; /* EURO-ISDN Default */
MODULE_PARM(protocol, "i");
@ -41,6 +41,12 @@ MODULE_PARM(protocol, "i");
static int number_of_leds = 2; /* 2 LEDs on the adpater default */
MODULE_PARM(number_of_leds, "i");
#ifdef CONFIG_HISAX_DEBUG
static int debug = 0x1;
MODULE_PARM(debug, "i");
int st5481_debug;
#endif
static LIST_HEAD(adapter_list);
/* ======================================================================
@ -59,6 +65,7 @@ static void * __devinit probe_st5481(struct usb_device *dev,
struct hisax_b_if *b_if[2];
int retval, i;
MOD_INC_USE_COUNT;
printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n",
dev->descriptor.idVendor, dev->descriptor.idProduct,
number_of_leds);
@ -113,7 +120,7 @@ static void * __devinit probe_st5481(struct usb_device *dev,
err_usb:
st5481_release_usb(adapter);
err:
WARN("retval %d\n", retval);
MOD_DEC_USE_COUNT;
return NULL;
}
@ -140,6 +147,7 @@ static void __devexit disconnect_st5481(struct usb_device *dev, void *arg)
hisax_unregister(&adapter->hisax_d_if);
kfree(adapter);
MOD_DEC_USE_COUNT;
}
/*
@ -177,10 +185,11 @@ static int __init st5481_usb_init(void)
{
int retval;
DBG(1,"");
#ifdef CONFIG_HISAX_DEBUG
st5481_debug = debug;
#endif
printk(KERN_INFO "st5481: ST5481 USB ISDN driver %s\n",
st5481_revision);
printk(KERN_INFO "hiax_st5481: ST5481 USB ISDN driver v0.1.0\n");
retval = st5481_d_init();
if (retval < 0)
@ -190,7 +199,6 @@ static int __init st5481_usb_init(void)
if (retval < 0)
goto out_d_exit;
// create_proc_read_entry("driver/st5481", 0, 0, proc_read_proc, NULL);
return 0;
out_d_exit:
@ -199,13 +207,10 @@ static int __init st5481_usb_init(void)
return retval;
}
static void __exit st5481_usb_cleanup(void)
static void __exit st5481_usb_exit(void)
{
DBG(1,"");
usb_deregister(&st5481_usb_driver);
// remove_proc_entry("driver/st5481", NULL);
}
module_init(st5481_usb_init);
module_exit(st5481_usb_cleanup);
module_exit(st5481_usb_exit);

View File

@ -1,3 +1,15 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@ -103,7 +115,7 @@ void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command)
{
DBG(8,"command=%s",ST5481_CMD_string(command));
DBG(8,"command=%s", ST5481_CMD_string(command));
st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL);
}
@ -183,40 +195,32 @@ static void usb_int_complete(struct urb *urb)
}
}
DUMP_PACKET(1, data, INT_PKT_SIZE);
DBG_PACKET(1, data, INT_PKT_SIZE);
if (urb->actual_length == 0) {
return;
}
irqbyte = data[MPINT];
if (irqbyte & DEN_INT) {
st5481_sched_d_out_event(adapter, EV_DOUT_DEN, NULL);
}
if (irqbyte & DEN_INT)
FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL);
if (irqbyte & DCOLL_INT) {
st5481_sched_d_out_event(adapter, EV_DOUT_COLL, NULL);
}
if (irqbyte & DCOLL_INT)
FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL);
irqbyte = data[FFINT_D];
if (irqbyte & OUT_UNDERRUN) {
// printk("OUT_UNDERRUN\n");
st5481_sched_d_out_event(adapter, EV_DOUT_UNDERRUN, NULL);
}
if (irqbyte & OUT_DOWN) {
// printk("OUT_DOWN\n");
}
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) {
DBG(8,"CI %s",ST5481_IND_string(data[CCIST] & 0x0f));
adapter->ph_state = data[CCIST] & 0x0f;
st5481_sched_event(adapter, D_L1STATECHANGE);
}
if (irqbyte & RXCI_INT)
FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL);
for (j = 0; j < 2; j++) {
for (j = 0; j < 2; j++)
adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j];
}
urb->actual_length = 0;
}
@ -298,8 +302,6 @@ int __devinit st5481_setup_usb(struct st5481_adapter *adapter)
usb_int_complete, adapter,
endpoint->bInterval);
fifo_init(&intr->evt_fifo.f, ARRAY_SIZE(intr->evt_fifo.data));
return 0;
}
@ -478,7 +480,7 @@ static void usb_in_complete(struct urb *urb)
}
}
DUMP_ISO_PACKET(0x80,urb);
DBG_ISO_PACKET(0x80,urb);
len = st5481_isoc_flatten(urb);
ptr = urb->transfer_buffer;
@ -497,7 +499,7 @@ static void usb_in_complete(struct urb *urb)
if (status > 0) {
// Good frame received
DBG(4,"count=%d",status);
DUMP_PACKET(0x400, in->rcvbuf, status);
DBG_PACKET(0x400, in->rcvbuf, status);
if (!(skb = dev_alloc_skb(status))) {
WARN("receive out of memory\n");
break;
@ -602,8 +604,6 @@ static void st5481_start_rcv(void *context)
DBG(4,"");
// Start receiving from B channel
in->urb[0]->dev = adapter->usb_dev;
SUBMIT_URB(in->urb[0]);
@ -627,9 +627,15 @@ void st5481_in_mode(struct st5481_in *in, int mode)
in->mode == L1_MODE_HDLC_56K);
st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
#if 0
st5481_usb_device_ctrl_msg(in->adapter, in->counter,
in->packet_size,
st5481_start_rcv, in);
#endif
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);