merge ST5481_USB driver (Frode Isaksen)

This commit is contained in:
Kai Germaschewski 2001-06-13 14:50:22 +00:00
parent 4483226493
commit 6c0e8c43ea
11 changed files with 3833 additions and 3 deletions

View File

@ -114,6 +114,11 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
if [ "CONFIG_USB" != "n" ]; then
bool ' Colognechip HFC-USB support' CONFIG_HISAX_HFC_USB
fi
fi
if [ "$CONFIG_MODULES" != "n" ]; then
if [ "CONFIG_USB" != "n" ]; then
bool ' ST5481 USB ISDN modem' CONFIG_HISAX_ST5481
fi
fi
fi
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA

View File

@ -16,6 +16,7 @@ hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
# Optional parts of multipart objects.
hfcusb-mods-$(CONFIG_HISAX_HFC_USB) := hfc_usb.o
st5481usb-mods-$(CONFIG_HISAX_ST5481) := st5481_usb.o
hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o
@ -50,6 +51,7 @@ hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
hisax-objs-$(CONFIG_HISAX_ST5481) += st5481.o st5481_hdlc.o
#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
hisax-objs += $(sort $(hisax-objs-y))
@ -57,7 +59,7 @@ hisax-objs += $(sort $(hisax-objs-y))
# insert hfc usb module into obj-m
obj-m += $(hfcusb-mods-y)
multi-m += $(hfcusb-mods-y)
obj-m += $(st5481usb-mods-y)
# Each configuration option enables a list of files.

View File

@ -73,6 +73,7 @@
* 38 Travers Technologies NETspider-U PCI card
* 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase
* 40 HFC-S USB none
* 41 ST5481 ISDN USB modem none
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
*
@ -97,6 +98,7 @@ const char *CardType[] =
"Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI",
"Winbond 6692",
"HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA", "HFC-S USB",
"ST5481 ISDN USB modem",
};
void HiSax_closecard(int cardnr);
@ -310,6 +312,15 @@ EXPORT_SYMBOL(hfc_init_pcmcia);
#define DEFAULT_CFG {0,0,0,0}
#endif
#ifdef CONFIG_HISAX_ST5481
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_ST5481
#define DEFAULT_CFG {0,0,0,0}
int st5481_init_usb(struct usb_device *dev, int typ, int prot, int *cardnr);
EXPORT_SYMBOL(st5481_init_usb);
#endif
#ifdef CONFIG_HISAX_1TR6
#define DEFAULT_PROTO ISDN_PTYPE_1TR6
#define DEFAULT_PROTO_NAME "1TR6"
@ -641,6 +652,10 @@ extern int setup_w6692(struct IsdnCard *card);
extern int setup_netjet_u(struct IsdnCard *card);
#endif
#if CARD_ST5481
extern int setup_st5481(struct IsdnCard *card);
#endif
/*
* Find card with given driverId
*/
@ -1194,7 +1209,12 @@ checkcard(int cardnr, char *id, int *busy_flag, void *load_drv)
ret = setup_netjet_u(card);
break;
#endif
default:
#if CARD_ST5481
case ISDN_CTYPE_ST5481:
ret = setup_st5481(card);
break;
#endif
default:
printk(KERN_WARNING
"HiSax: Support for %s Card not selected\n",
CardType[card->typ]);
@ -1533,6 +1553,12 @@ HiSax_init(void)
return 0;
}
#endif
#ifdef CONFIG_HISAX_ST5481
if (type[0] == ISDN_CTYPE_ST5481) {
/* we have to export and return in this case */
return 0;
}
#endif
#endif
nrcards = 0;
#ifdef MODULE
@ -1611,6 +1637,7 @@ HiSax_init(void)
case ISDN_CTYPE_TELESPCI:
case ISDN_CTYPE_W6692:
case ISDN_CTYPE_NETJET_U:
case ISDN_CTYPE_ST5481:
break;
case ISDN_CTYPE_BKM_A4T:
break;
@ -1868,6 +1895,44 @@ avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
}
#endif
#ifdef CONFIG_HISAX_ST5481
int st5481_init_usb(struct usb_device *dev, int typ, int prot, int *cardnr)
{
#ifdef MODULE
int i;
nrcards = 0;
for (i = 0; i < HISAX_MAX_CARDS; i++) {
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
}
}
cards[0].para[1] = (int) dev; // FIXME: broken for sizeof(void *) != sizeof(int)
cards[0].protocol = prot;
cards[0].typ = typ;
*cardnr = 0; // FIXME: only 1 adapter possible
if (!HiSax_id)
HiSax_id = HiSaxID;
if (!HiSaxID[0])
strcpy(HiSaxID, "st5481_usb");
for (i = 0; i < HISAX_MAX_CARDS; i++)
if (cards[i].typ > 0)
nrcards++;
printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
nrcards, (nrcards > 1) ? "s" : "");
HiSax_inithardware(NULL);
printk(KERN_NOTICE "HiSax: module installed\n");
#endif
return (0);
}
#endif
int __devinit
hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
{

View File

View File

@ -457,6 +457,16 @@ struct amd7930_hw {
struct tq_struct tq_xmt;
};
struct st5481B_hw {
int rcvidx;
u_char *rcvbuf; /* B-Channel receive Buffer */
struct hdlc_vars *hdlc_state_in;
struct hdlc_vars *hdlc_state_out;
u_char b_flow_event;
u_long b_out_busy;
struct urb *b_out_urb[2]; /* double buffering */
struct urb *b_in_urb[2]; /* double buffering */
};
#define BC_FLG_INIT 1
#define BC_FLG_ACTIV 2
@ -514,6 +524,7 @@ struct BCState {
struct tiger_hw tiger;
struct amd7930_hw amd7930;
struct w6692B_hw w6692;
struct st5481B_hw st5481;
} hw;
};
@ -791,6 +802,23 @@ struct w6692_hw {
struct timer_list timer;
};
struct st5481_hw {
struct usb_device *dev;
struct hdlc_vars *hdlc_state_in;
struct hdlc_vars *hdlc_state_out;
struct evt_fifo *xmt_evt_fifo;
struct ctrl_msg_fifo *ctrl_msg_fifo;
u_long ctrl_busy;
struct urb *ctrl_urb;
struct urb *int_urb;
int d_out_state;
u_long d_out_busy;
struct urb *d_out_urb[2]; /* double buffering */
struct urb *d_in_urb[2]; /* double buffering */
u_char leds;
unsigned int led_counter;
};
#ifdef CONFIG_HISAX_TESTEMU
struct te_hw {
unsigned char *sfifo;
@ -859,6 +887,10 @@ struct icc_chip {
u_char adf2;
};
struct st5481_chip {
int ph_state;
};
#define HW_IOM1 0
#define HW_IPAC 1
#define HW_ISAR 2
@ -909,6 +941,7 @@ struct IsdnCardState {
struct bkm_hw ax;
struct gazel_hw gazel;
struct w6692_hw w6692;
struct st5481_hw st5481;
} hw;
int myid;
isdn_if iif;
@ -942,6 +975,7 @@ struct IsdnCardState {
struct hfcsx_chip hfcsx;
struct w6692_chip w6692;
struct icc_chip icc;
struct st5481_chip st5481;
} dc;
u_char *rcvbuf;
int rcvidx;
@ -1004,7 +1038,8 @@ struct IsdnCardState {
#define ISDN_CTYPE_NETJET_U 38
#define ISDN_CTYPE_HFC_SP_PCMCIA 39
#define ISDN_CTYPE_HFC_USB 40
#define ISDN_CTYPE_COUNT 40
#define ISDN_CTYPE_ST5481 41
#define ISDN_CTYPE_COUNT 41
#ifdef ISDN_CHIP_ISAC
@ -1263,6 +1298,12 @@ struct IsdnCardState {
#define CARD_NETJET_U 0
#endif
#ifdef CONFIG_HISAX_ST5481
#define CARD_ST5481 1
#else
#define CARD_ST5481 0
#endif
#define TEI_PER_CARD 1
/* L1 Debug */

View File

@ -0,0 +1,184 @@
#if ST5481_DEBUG
/*
DEBUG flags. Set compile option ST5481_DEBUG with the following bits set to trace
the given subsections:
0x01: USB
0x02: D
0x04: B
0x08: PH
0x10: PACKET_DUMP
0x20: ISO_DUMP
*/
#define DBG(level, format, arg...) \
if (level & ST5481_DEBUG) \
printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg) \
static const char *
D_EVENT_string(unsigned int evt)
{
static char s[16];
switch(evt) {
case DNONE_EVENT: return "DNONE_EVENT";
case DXMIT_INITED: return "DXMIT_INITED";
case DXMIT_STOPPED: return "DXMIT_STOPPED";
case DEN_EVENT: return "DEN_EVENT";
case DCOLL_EVENT: return "DCOLL_EVENT";
case DUNDERRUN_EVENT: return "DUNDERRUN_EVENT";
case DXMIT_NOT_BUSY: return "DXMIT_NOT_BUSY";
case DXSHORT_EVENT: return "DXSHORT_EVENT";
case DXRESET_EVENT: return "DXRESET_EVENT";
}
sprintf(s,"%d",evt);
return s;
}
static const char *
D_STATE_string(unsigned int state)
{
static char s[16];
switch(state) {
case DOUT_NONE: return "DOUT_NONE";
case DOUT_STOP: return "DOUT_STOP";
case DOUT_INIT: return "DOUT_INIT";
case DOUT_INIT_SHORT_FRAME: return "DOUT_INIT_SHORT_FRAME";
case DOUT_INIT_LONG_FRAME: return "DOUT_INIT_LONG_FRAME";
case DOUT_SHORT_WAIT_DEN: return "DOUT_SHORT_WAIT_DEN";
case DOUT_WAIT_DEN: return "DOUT_WAIT_DEN";
case DOUT_NORMAL: return "DOUT_NORMAL";
case DOUT_END_OF_FRAME_BUSY: return "DOUT_END_OF_FRAME_BUSY";
case DOUT_END_OF_FRAME_NOT_BUSY: return "DOUT_END_OF_FRAME_NOT_BUSY";
case DOUT_END_OF_SHORT_FRAME: return "DOUT_END_OF_SHORT_FRAME";
case DOUT_WAIT_FOR_NOT_BUSY: return "DOUT_WAIT_FOR_NOT_BUSY";
case DOUT_WAIT_FOR_STOP: return "DOUT_WAIT_FOR_STOP";
case DOUT_WAIT_FOR_RESET: return "DOUT_WAIT_FOR_RESET";
case DOUT_WAIT_FOR_RESET_IDLE: return "DOUT_WAIT_FOR_RESET_IDLE";
case DOUT_IDLE: return "DOUT_IDLE";
}
sprintf(s,"%d",state);
return s;
}
static 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 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 void
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
}
static void
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,data=\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("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");
}
}
#define DUMP_PACKET(level,data,count) \
if (level & ST5481_DEBUG) dump_packet(__FUNCTION__,data,count)
#define DUMP_SKB(level,skb) \
if ((level & ST5481_DEBUG) && skb) dump_packet(__FUNCTION__,skb->data,skb->len)
#define DUMP_ISO_PACKET(level,urb) \
if (level & ST5481_DEBUG) dump_iso_packet(__FUNCTION__,urb)
#else
#define DBG(level,format, arg...) do {} while (0)
#define DUMP_PACKET(level,data,count) do {} while (0)
#define DUMP_SKB(level,skb) do {} while (0)
#define DUMP_ISO_PACKET(level,urb) do {} while (0)
#endif

2465
drivers/isdn/hisax/st5481.c Normal file

File diff suppressed because it is too large Load Diff

189
drivers/isdn/hisax/st5481.h Normal file
View File

@ -0,0 +1,189 @@
#ifndef _ST5481__H_
#define _ST5481__H_
/*
If you have 4 LEDs on your adapter, set this compile flag to 4.
*/
#ifndef NUMBER_OF_LEDS
#define NUMBER_OF_LEDS 2
#endif
#define ST_VENDOR_ID 0x0483
#define ST5481_PRODUCT_ID 0x4810 /* The Product Id is in the range 0x4810-0x481F */
#define ST5481_PRODUCT_ID_MASK 0xFFF0
/*
ST5481 endpoints when using alternative setting 3 (2B+D).
To get the endpoint address, OR with 0x80 for IN endpoints.
*/
#define EP_CTRL 0x00U /* Control endpoint */
#define EP_INT 0x01U /* Interrupt endpoint */
#define EP_B1_OUT 0x02U /* B1 channel out */
#define EP_B1_IN 0x03U /* B1 channel in */
#define EP_B2_OUT 0x04U /* B2 channel out */
#define EP_B2_IN 0x05U /* B2 channel in */
#define EP_D_OUT 0x06U /* D channel out */
#define EP_D_IN 0x07U /* D channel in */
/*
Number of isochronous packets. With 20 packets we get
50 interrupts/sec for each endpoint.
*/
#define NUM_ISO_PACKETS_D 20
#define NUM_ISO_PACKETS_B 20
/*
Size of each isochronous packet.
*/
#define SIZE_ISO_PACKETS_D 16
#define SIZE_ISO_PACKETS_B 32
/*
Registers that are written using vendor specific device request
on endpoint 0.
*/
#define LBA 0x02 /* S loopback */
#define SET_DEFAULT 0x06 /* Soft reset */
#define LBB 0x1D /* S maintenance loopback */
#define STT 0x1e /* S force transmission signals */
#define SDA_MIN 0x20 /* SDA-sin minimal value */
#define SDA_MAX 0x21 /* SDA-sin maximal value */
#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */
#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */
#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */
#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */
#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */
#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */
#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */
#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */
#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */
#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */
#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */
#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */
#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */
#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */
#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */
#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */
#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */
#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */
#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */
#define MPMSK 0x4A /* Multi purpose interrupt MASK register */
#define FFMSK_D 0x4c /* D fifo interrupt MASK register */
#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */
#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */
#define GPIO_DIR 0x52 /* GPIO pins direction registers */
#define GPIO_OUT 0x53 /* GPIO pins output register */
#define GPIO_IN 0x54 /* GPIO pins input register */
#define TXCI 0x56 /* CI command to be transmitted */
/*
Format of the interrupt packet received on endpoint 1:
+--------+--------+--------+--------+--------+--------+
!MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
+--------+--------+--------+--------+--------+--------+
*/
/* Offsets in the interrupt packet */
#define MPINT 0
#define FFINT_D 1
#define FFINT_B1 2
#define FFINT_B2 3
#define CCIST 4
#define GPIO_INT 5
#define INT_PKT_SIZE 6
/* MPINT */
#define LSD_INT 0x80 /* S line activity detected */
#define RXCI_INT 0x40 /* Indicate primitive arrived */
#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */
#define DCOLL_INT 0x10 /* D channel collision */
#define AMIVN_INT 0x04 /* AMI violation number reached 2 */
#define INFOI_INT 0x04 /* INFOi changed */
#define DRXON_INT 0x02 /* Reception channel active */
#define GPCHG_INT 0x01 /* GPIO pin value changed */
/* FFINT_x */
#define IN_OVERRUN 0x80 /* In fifo overrun */
#define OUT_UNDERRUN 0x40 /* Out fifo underrun */
#define IN_UP 0x20 /* In fifo thresholdh up-crossed */
#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */
#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */
#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */
#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */
#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */
#define ANY_REC_INT (IN_OVERRUN+IN_UP+IN_DOWN+IN_COUNTER_ZEROED)
#define ANY_XMIT_INT (OUT_UNDERRUN+OUT_UP+OUT_DOWN+OUT_COUNTER_ZEROED)
/* Level 1 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 */
#define ST5481_CMD_DR 0x0 /* Deactivation Request */
#define ST5481_CMD_RES 0x1 /* state machine RESet */
#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */
#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */
#define ST5481_CMD_PUP 0x7 /* Power UP */
#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */
#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */
#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */
#define ST5481_CMD_PDN 0xF /* Power DoWn */
/* Turn on/off the LEDs using the GPIO device request.
To use the B LEDs, NUMBER_OF_LEDS must be set to 4 */
#define B1_LED 0x10U
#define B2_LED 0x20U
#define GREEN_LED 0x40U
#define RED_LED 0x80U
/* D channel out state machine */
enum {
DOUT_NONE,
DOUT_STOP,
DOUT_INIT,
DOUT_INIT_SHORT_FRAME,
DOUT_INIT_LONG_FRAME,
DOUT_SHORT_WAIT_DEN,
DOUT_WAIT_DEN,
DOUT_NORMAL,
DOUT_END_OF_FRAME_BUSY,
DOUT_END_OF_FRAME_NOT_BUSY,
DOUT_END_OF_SHORT_FRAME,
DOUT_WAIT_FOR_NOT_BUSY,
DOUT_WAIT_FOR_STOP,
DOUT_WAIT_FOR_RESET,
DOUT_WAIT_FOR_RESET_IDLE,
DOUT_IDLE
};
/* D channel out events */
enum {
DNONE_EVENT,
DXMIT_INITED,
DXMIT_STOPPED,
DEN_EVENT,
DCOLL_EVENT,
DUNDERRUN_EVENT,
DXMIT_NOT_BUSY,
DXSHORT_EVENT,
DXRESET_EVENT
};
#endif

View File

@ -0,0 +1,625 @@
#include "st5481_hdlc.h"
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,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
static const unsigned char inverse[] = {
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF,
};
enum {
HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
HDLC_GET_DATA,HDLC_FAST_FLAG
};
enum {
HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
};
void
hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56)
{
hdlc->bit_shift = 0;
hdlc->hdlc_bits1 = 0;
hdlc->data_bits = 0;
hdlc->ffbit_shift = 0;
hdlc->data_received = 0;
hdlc->state = HDLC_GET_DATA;
hdlc->do_adapt56 = do_adapt56;
hdlc->dchannel = 0;
hdlc->crc = 0;
hdlc->cbin = 0;
hdlc->shift_reg = 0;
hdlc->ffvalue = 0;
}
void
hdlc_out_init(struct hdlc_vars *hdlc, int is_d_channel, int do_adapt56)
{
hdlc->bit_shift = 0;
hdlc->hdlc_bits1 = 0;
hdlc->data_bits = 0;
hdlc->ffbit_shift = 0;
hdlc->data_received = 0;
hdlc->do_closing = 0;
hdlc->ffvalue = 0;
if (is_d_channel) {
hdlc->dchannel = 1;
hdlc->state = HDLC_SEND_FIRST_FLAG;
} else {
hdlc->dchannel = 0;
hdlc->state = HDLC_SEND_FAST_FLAG;
hdlc->ffvalue = 0x7e;
}
hdlc->cbin = 0x7e;
hdlc->bit_shift = 0;
if(do_adapt56){
hdlc->do_adapt56 = 1;
hdlc->data_bits = 0;
hdlc->state = HDLC_SENDFLAG_B0;
} else {
hdlc->do_adapt56 = 0;
hdlc->data_bits = 8;
}
hdlc->shift_reg = 0;
}
/*
hdlc_decode - decodes HDLC frames from a transparent bit stream.
The source buffer is scanned for valid HDLC frames looking for
flags (01111110) to indicate the start of a frame. If the start of
the frame is found, the bit stuffing is removed (0 after 5 1's).
When a new flag is found, the complete frame has been received
and the CRC is checked.
If a valid frame is found, the function returns the frame length
excluding the CRC with the bit HDLC_END_OF_FRAME set.
If the beginning of a valid frame is found, the function returns
the length.
If a framing error is found (too many 1s and not a flag) the function
returns the length with the bit HDLC_FRAMING_ERROR set.
If a CRC error is found the function returns the length with the
bit HDLC_CRC_ERROR set.
If the frame length exceeds the destination buffer size, the function
returns the length with the bit HDLC_LENGTH_ERROR set.
src - source buffer
slen - source buffer length
count - number of bytes removed (decoded) from the source buffer
dst _ destination buffer
dsize - destination buffer size
returns - number of decoded bytes in the destination buffer and status
flag.
*/
unsigned short
hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen, int *count,
unsigned char *dst, int dsize)
{
unsigned short status=0;
static const unsigned char fast_flag[]={
0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
};
static const unsigned char fast_flag_value[]={
0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
};
static const unsigned char fast_abort[]={
0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe
};
*count = slen;
while(slen > 0){
if(hdlc->bit_shift==0){
hdlc->cbin = *src++;
slen--;
hdlc->bit_shift = 8;
if(hdlc->do_adapt56){
hdlc->bit_shift --;
}
}
switch(hdlc->state){
case STOPPED:
return 0;
case HDLC_FAST_IDLE:
if(hdlc->cbin == 0xff){
hdlc->bit_shift = 0;
break;
}
hdlc->state = HDLC_GET_FLAG_B0;
hdlc->hdlc_bits1 = 0;
hdlc->bit_shift = 8;
break;
case HDLC_GET_FLAG_B0:
if(!(hdlc->cbin & 0x80)) {
hdlc->state = HDLC_GETFLAG_B1A6;
hdlc->hdlc_bits1 = 0;
} else {
if(!hdlc->do_adapt56){
if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
hdlc->state = HDLC_FAST_IDLE;
}
}
hdlc->cbin<<=1;
hdlc->bit_shift --;
break;
case HDLC_GETFLAG_B1A6:
if(hdlc->cbin & 0x80){
hdlc->hdlc_bits1++;
if(hdlc->hdlc_bits1==6){
hdlc->state = HDLC_GETFLAG_B7;
}
} else {
hdlc->hdlc_bits1 = 0;
}
hdlc->cbin<<=1;
hdlc->bit_shift --;
break;
case HDLC_GETFLAG_B7:
if(hdlc->cbin & 0x80) {
hdlc->state = HDLC_GET_FLAG_B0;
} else {
hdlc->state = HDLC_GET_DATA;
hdlc->crc = 0xffff;
hdlc->shift_reg = 0;
hdlc->hdlc_bits1 = 0;
hdlc->data_bits = 0;
hdlc->data_received = 0;
}
hdlc->cbin<<=1;
hdlc->bit_shift --;
break;
case HDLC_GET_DATA:
if(hdlc->cbin & 0x80){
hdlc->hdlc_bits1++;
switch(hdlc->hdlc_bits1){
case 6:
break;
case 7:
if(hdlc->data_received) {
// bad frame
status = status | HDLC_FRAMING_ERROR;
}
if(!hdlc->do_adapt56){
if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
hdlc->state = HDLC_FAST_IDLE;
hdlc->bit_shift=1;
break;
}
} else {
hdlc->state = HDLC_GET_FLAG_B0;
}
break;
default:
hdlc->shift_reg>>=1;
hdlc->shift_reg |= 0x80;
hdlc->data_bits++;
break;
}
} else {
switch(hdlc->hdlc_bits1){
case 5:
break;
case 6:
if(hdlc->data_received){
if(hdlc->crc != 0xf0b8){
// crc error
status |= HDLC_CRC_ERROR;
} else {
// remove CRC
status -= 2;
// good frame
status |= HDLC_END_OF_FRAME;
}
}
hdlc->crc = 0xffff;
hdlc->shift_reg = 0;
hdlc->data_bits = 0;
if(!hdlc->do_adapt56){
if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
hdlc->state = HDLC_FAST_FLAG;
hdlc->ffbit_shift = hdlc->bit_shift;
hdlc->bit_shift = 1;
} else {
hdlc->state = HDLC_GET_DATA;
hdlc->data_received = 0;
}
} else {
hdlc->state = HDLC_GET_DATA;
hdlc->data_received = 0;
}
break;
default:
hdlc->shift_reg>>=1;
hdlc->data_bits++;
break;
}
hdlc->hdlc_bits1 = 0;
}
if (status & 0xF000) {
*count -= slen;
hdlc->cbin <<= 1;
hdlc->bit_shift--;
return status;
}
if(hdlc->data_bits==8){
unsigned cval;
hdlc->data_bits = 0;
hdlc->data_received = 1;
cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
// good byte received
if (dsize--) {
*dst++ = hdlc->shift_reg;
status++;
} else {
// frame too long
status |= HDLC_LENGTH_ERROR;
}
}
hdlc->cbin <<= 1;
hdlc->bit_shift--;
break;
case HDLC_FAST_FLAG:
if(hdlc->cbin==hdlc->ffvalue){
hdlc->bit_shift = 0;
break;
} else {
if(hdlc->cbin == 0xff){
hdlc->state = HDLC_FAST_IDLE;
hdlc->bit_shift=0;
} else if(hdlc->ffbit_shift==8){
hdlc->state = HDLC_GETFLAG_B7;
break;
} else {
hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
hdlc->data_bits = hdlc->ffbit_shift-1;
hdlc->state = HDLC_GET_DATA;
hdlc->data_received = 0;
}
}
break;
default:
break;
}
}
*count -= slen;
return status;
}
/*
hdlc_encode - encodes HDLC frames to a transparent bit stream.
The bit stream starts with a beginning flag (01111110). After
that each byte is added to the bit stream with bit stuffing added
(0 after 5 1's).
When the last byte has been removed from the source buffer, the
CRC (2 bytes is added) and the frame terminates with the ending flag.
For the dchannel, the idle character (all 1's) is also added at the end.
If this function is called with empty source buffer (slen=0), flags or
idle character will be generated.
src - source buffer
slen - source buffer length
count - number of bytes removed (encoded) from source buffer
dst _ destination buffer
dsize - destination buffer size
returns - number of encoded bytes in the destination buffer
*/
int
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
};
int len = 0;
*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;
} 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--;
}
}
*count -= slen;
return len;
}

View File

@ -0,0 +1,54 @@
#ifndef __ST5481_HDLC__
#define __ST5481_HDLC__
struct hdlc_vars {
int bit_shift;
int hdlc_bits1;
int data_bits;
int ffbit_shift; // encoding only
int state;
int data_received:1; // set if transferring data
int dchannel:1; // set if D channel (send idle instead of flags)
int do_adapt56:1; // set if 56K adaptation
int do_closing:1; // set if in closing phase (need to send CRC + flag
unsigned short crc;
unsigned char cbin;
unsigned char shift_reg;
unsigned char ffvalue;
};
/*
The return value from hdlc_decode is
the frame length with status bits
the MS byte.
+--------+------------------------+
!EFCL ! frame length !
+--------+------------------------+
*/
#define HDLC_END_OF_FRAME 0x8000
#define HDLC_FRAMING_ERROR 0x4000
#define HDLC_CRC_ERROR 0x2000
#define HDLC_LENGTH_ERROR 0x1000
void
hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56);
unsigned short
hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
unsigned char *dst, int dsize);
void
hdlc_out_init(struct hdlc_vars *hdlc,int is_d_channel,int do_adapt56);
int
hdlc_encode(struct hdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
unsigned char *dst,int dsize);
#endif

View File

@ -0,0 +1,200 @@
/*
*
* HiSax ISDN driver - usb specific routines for ST5481 USB ISDN modem
*
* Author Frode Isaksen (fisaksen@bewan.com)
*
*
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/isdn_compat.h>
#include "hisax.h"
#include "st5481.h"
MODULE_AUTHOR("Frode Isaksen <fisaksen@bewan.com>");
MODULE_DESCRIPTION("ST5481 USB ISDN modem");
/* Parameters that can be set with 'insmod' */
static int protocol=2; /* EURO-ISDN Default */
MODULE_PARM(protocol, "i");
static int number_of_leds=2; /* 2 LEDs on the adpater default */
MODULE_PARM(number_of_leds, "i");
void HiSax_closecard(int cardnr);
int st5481_init_usb(struct usb_device *dev, int type, int prot, int *cardnr);
#define MAX_ADAPTERS 4 /* Each adapter needs about 1.3 Mbs of isoc BW */
struct st5481_usb_adapter {
int active;
int protocol;
int number_of_leds;
int cardnr;
};
static struct st5481_usb_adapter usb_adapter_instances[MAX_ADAPTERS];
static struct st5481_usb_adapter *
get_usb_adapter(void)
{
struct st5481_usb_adapter *usb_adapter;
for (usb_adapter = usb_adapter_instances;
usb_adapter < &usb_adapter_instances[MAX_ADAPTERS];
usb_adapter++) {
if (!test_and_set_bit(0, &usb_adapter->active)) {
//MOD_INC_USE_COUNT;
usb_adapter->protocol = protocol;
usb_adapter->number_of_leds = number_of_leds;
usb_adapter->cardnr = -1;
return usb_adapter;
}
}
return NULL;
}
static void
free_usb_adapter(struct st5481_usb_adapter *usb_adapter)
{
if (usb_adapter) {
if (test_and_clear_bit(0, &usb_adapter->active)) {
printk( KERN_DEBUG __FUNCTION__ ": cardnr %d active\n",
usb_adapter->cardnr);
if (usb_adapter->cardnr != -1) {
HiSax_closecard(usb_adapter->cardnr);
}
//MOD_DEC_USE_COUNT;
}
}
}
/*
This function will be called when the adapter is plugged
into the USB bus.
Call init_usb_st5481 to tell HiSax that USB device is
ready.
*/
static void *
probe_st5481(struct usb_device *dev, unsigned int ifnum
#ifdef COMPAT_HAS_USB_IDTAB
,const struct usb_device_id *id
#endif
)
{
struct st5481_usb_adapter *usb_adapter;
printk( KERN_INFO __FILE__ ": "__FUNCTION__ ": VendorId %04x,ProductId %04x\n",
dev->descriptor.idVendor,dev->descriptor.idProduct);
if (dev->descriptor.idVendor != ST_VENDOR_ID) {
return NULL;
}
if ((dev->descriptor.idProduct & ST5481_PRODUCT_ID_MASK) !=
ST5481_PRODUCT_ID) {
return NULL;
}
usb_adapter = get_usb_adapter();
if (!usb_adapter) {
printk( KERN_WARNING __FILE__ ": " __FUNCTION__ ": too many adapters\n");
return NULL;
}
if (st5481_init_usb(dev, ISDN_CTYPE_ST5481, usb_adapter->protocol,
&usb_adapter->cardnr) < 0) {
printk( KERN_WARNING __FILE__ ": " __FUNCTION__ ": st5481_init_usb failed\n");
free_usb_adapter(usb_adapter);
return NULL;
}
return usb_adapter;
}
/*
This function will be called when the adapter is removed
from the USB bus.
Call HiSax_closecard via free_sub_adapter to tell HiSax that USB
device has been removed.
*/
static void
disconnect_st5481(struct usb_device *dev,void *arg)
{
struct st5481_usb_adapter *usb_adapter = arg;
printk( KERN_DEBUG __FUNCTION__ ": disconnect driver\n");
free_usb_adapter(usb_adapter);
}
#ifdef COMPAT_HAS_USB_IDTAB
/*
The last 4 bits in the Product Id is set with 4 pins on the chip.
*/
static struct usb_device_id st5481_ids[] = {
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x0) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x1) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x2) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x3) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x4) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x5) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x6) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x7) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x8) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x9) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xA) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xB) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xC) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xD) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xE) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xF) },
{ }
};
MODULE_DEVICE_TABLE (usb, st5481_ids);
#endif
static struct
usb_driver st5481_usb_driver = {
name: "st5481_usb",
probe: probe_st5481,
disconnect: disconnect_st5481,
#ifdef COMPAT_HAS_USB_IDTAB
id_table: st5481_ids,
#endif
};
static int __init
st5481_usb_init(void)
{
printk( KERN_INFO __FILE__ ": " __FUNCTION__ ": register driver\n");
memset(usb_adapter_instances, 0, sizeof(usb_adapter_instances));
if (usb_register(&st5481_usb_driver) < 0) {
printk( KERN_WARNING __FILE__ ": " __FUNCTION__ ": usb_register failed\n");
return -1;
}
return 0;
}
static void __exit
st5481_usb_cleanup(void)
{
struct st5481_usb_adapter *usb_adapter;
for (usb_adapter = usb_adapter_instances;
usb_adapter < &usb_adapter_instances[MAX_ADAPTERS];
usb_adapter++) {
free_usb_adapter(usb_adapter);
}
usb_deregister(&st5481_usb_driver);
}
module_init(st5481_usb_init);
module_exit(st5481_usb_cleanup);