merge ST5481_USB driver (Frode Isaksen)
This commit is contained in:
parent
4483226493
commit
6c0e8c43ea
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
Loading…
Reference in New Issue