update version of ST5481 driver
first version of new Fritz!PCI/PnP driver (also supports PCI v2)
This commit is contained in:
parent
a7c9cd8c7f
commit
276d17903c
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
};
|
||||
|
|
@ -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[],
|
||||
|
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue