Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
a01be2d5
Commit
a01be2d5
authored
Feb 25, 2002
by
Kai Germaschewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge vaio.(none):/home/kai/kernel/linux-2.5.isdn.hisax_hfcpci
into vaio.(none):/home/kai/kernel/linux-2.5.isdn
parents
3544950f
f3f8e122
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1688 additions
and
0 deletions
+1688
-0
drivers/isdn/Config.in
drivers/isdn/Config.in
+1
-0
drivers/isdn/hisax/Makefile
drivers/isdn/hisax/Makefile
+1
-0
drivers/isdn/hisax/hisax_hfcpci.c
drivers/isdn/hisax/hisax_hfcpci.c
+1646
-0
drivers/isdn/hisax/hisax_hfcpci.h
drivers/isdn/hisax/hisax_hfcpci.h
+40
-0
No files found.
drivers/isdn/Config.in
View file @
a01be2d5
...
...
@@ -84,6 +84,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
dep_tristate 'AVM Fritz!Card classic support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_CLASSIC $CONFIG_HISAX $CONFIG_EXPERIMENTAL
dep_tristate 'HFC PCI support (EXPERIMENTAL)' CONFIG_HISAX_HFCPCI $CONFIG_HISAX $CONFIG_EXPERIMENTAL
fi
endmenu
...
...
drivers/isdn/hisax/Makefile
View file @
a01be2d5
...
...
@@ -64,6 +64,7 @@ obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
obj-$(CONFIG_HISAX_ST5481)
+=
hisax_st5481.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP)
+=
hisax_isac.o hisax_fcpcipnp.o
obj-$(CONFIG_HISAX_FRITZ_CLASSIC)
+=
hisax_isac.o hisax_hscx.o hisax_fcclassic.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP)
+=
hisax_hfcpci.o
CERT
:=
$(
shell
md5sum
-c
md5sums.asc
>>
/dev/null
;
echo
$$
?
)
CFLAGS_cert.o
:=
-DCERTIFICATION
=
$(CERT)
...
...
drivers/isdn/hisax/hisax_hfcpci.c
0 → 100644
View file @
a01be2d5
/*
* Driver for HFC PCI based cards
*
* Author Kai Germaschewski
* Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
* 2000 by Karsten Keil <keil@isdn4linux.de>
* 2000 by Werner Cornelius <werner@isdn4linux.de>
*
* based upon Werner Cornelius's original hfc_pci.c driver
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
// XXX timer3
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/isapnp.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <asm/delay.h>
#include "hisax_hfcpci.h"
// debugging cruft
#define __debug_variable debug
#include "hisax_debug.h"
#ifdef CONFIG_HISAX_DEBUG
static
int
debug
=
0
;
MODULE_PARM
(
debug
,
"i"
);
#endif
MODULE_AUTHOR
(
"Kai Germaschewski <kai.germaschewski@gmx.de>/Werner Cornelius <werner@isdn4linux.de>"
);
MODULE_DESCRIPTION
(
"HFC PCI ISDN driver"
);
#define ID(ven, dev, name) \
{ vendor: PCI_VENDOR_ID_##ven, \
device: PCI_DEVICE_ID_##dev, \
subvendor: PCI_ANY_ID, \
subdevice: PCI_ANY_ID, \
class: 0, \
class_mask: 0, \
driver_data: (unsigned long) name }
static
struct
pci_device_id
hfcpci_ids
[]
__devinitdata
=
{
ID
(
CCD
,
CCD_2BD0
,
"CCD/Billion/Asuscom 2BD0"
),
ID
(
CCD
,
CCD_B000
,
"Billion B000"
),
ID
(
CCD
,
CCD_B006
,
"Billion B006"
),
ID
(
CCD
,
CCD_B007
,
"Billion B007"
),
ID
(
CCD
,
CCD_B008
,
"Billion B008"
),
ID
(
CCD
,
CCD_B009
,
"Billion B009"
),
ID
(
CCD
,
CCD_B00A
,
"Billion B00A"
),
ID
(
CCD
,
CCD_B00B
,
"Billion B00B"
),
ID
(
CCD
,
CCD_B00C
,
"Billion B00C"
),
ID
(
CCD
,
CCD_B100
,
"Seyeon"
),
ID
(
ABOCOM
,
ABOCOM_2BD1
,
"Abocom/Magitek"
),
ID
(
ASUSTEK
,
ASUSTEK_0675
,
"Asuscom/Askey"
),
ID
(
BERKOM
,
BERKOM_T_CONCEPT
,
"German Telekom T-Concept"
),
ID
(
BERKOM
,
BERKOM_A1T
,
"German Telekom A1T"
),
ID
(
ANIGMA
,
ANIGMA_MC145575
,
"Motorola MC145575"
),
ID
(
ZOLTRIX
,
ZOLTRIX_2BD0
,
"Zoltrix 2BD0"
),
ID
(
DIGI
,
DIGI_DF_M_IOM2_E
,
"Digi DataFire Micro V IOM2 (Europe)"
),
ID
(
DIGI
,
DIGI_DF_M_E
,
"Digi DataFire Micro V (Europe)"
),
ID
(
DIGI
,
DIGI_DF_M_IOM2_A
,
"Digi DataFire Micro V IOM2 (America)"
),
ID
(
DIGI
,
DIGI_DF_M_A
,
"Digi DataFire Micro V (America)"
),
{
}
};
MODULE_DEVICE_TABLE
(
pci
,
hfcpci_ids
);
#undef ID
static
int
protocol
=
2
;
/* EURO-ISDN Default */
MODULE_PARM
(
protocol
,
"i"
);
// ----------------------------------------------------------------------
//
#define DBG_WARN 0x0001
#define DBG_INFO 0x0002
#define DBG_IRQ 0x0010
#define DBG_L1M 0x0020
#define DBG_PR 0x0040
#define DBG_D_XMIT 0x0100
#define DBG_D_RECV 0x0200
#define DBG_B_XMIT 0x1000
#define DBG_B_RECV 0x2000
/* memory window base address offset (in config space) */
#define HFCPCI_MWBA 0x80
/* GCI/IOM bus monitor registers */
#define HCFPCI_C_I 0x08
#define HFCPCI_TRxR 0x0C
#define HFCPCI_MON1_D 0x28
#define HFCPCI_MON2_D 0x2C
/* GCI/IOM bus timeslot registers */
#define HFCPCI_B1_SSL 0x80
#define HFCPCI_B2_SSL 0x84
#define HFCPCI_AUX1_SSL 0x88
#define HFCPCI_AUX2_SSL 0x8C
#define HFCPCI_B1_RSL 0x90
#define HFCPCI_B2_RSL 0x94
#define HFCPCI_AUX1_RSL 0x98
#define HFCPCI_AUX2_RSL 0x9C
/* GCI/IOM bus data registers */
#define HFCPCI_B1_D 0xA0
#define HFCPCI_B2_D 0xA4
#define HFCPCI_AUX1_D 0xA8
#define HFCPCI_AUX2_D 0xAC
/* GCI/IOM bus configuration registers */
#define HFCPCI_MST_EMOD 0xB4
#define HFCPCI_MST_MODE 0xB8
#define HFCPCI_CONNECT 0xBC
/* Interrupt and status registers */
#define HFCPCI_FIFO_EN 0x44
#define HFCPCI_TRM 0x48
#define HFCPCI_B_MODE 0x4C
#define HFCPCI_CHIP_ID 0x58
#define HFCPCI_CIRM 0x60
#define HFCPCI_CTMT 0x64
#define HFCPCI_INT_M1 0x68
#define HFCPCI_INT_M2 0x6C
#define HFCPCI_INT_S1 0x78
#define HFCPCI_INT_S2 0x7C
#define HFCPCI_STATUS 0x70
/* S/T section registers */
#define HFCPCI_STATES 0xC0
#define HFCPCI_SCTRL 0xC4
#define HFCPCI_SCTRL_E 0xC8
#define HFCPCI_SCTRL_R 0xCC
#define HFCPCI_SQ 0xD0
#define HFCPCI_CLKDEL 0xDC
#define HFCPCI_B1_REC 0xF0
#define HFCPCI_B1_SEND 0xF0
#define HFCPCI_B2_REC 0xF4
#define HFCPCI_B2_SEND 0xF4
#define HFCPCI_D_REC 0xF8
#define HFCPCI_D_SEND 0xF8
#define HFCPCI_E_REC 0xFC
/* bits in status register (READ) */
#define HFCPCI_PCI_PROC 0x02
#define HFCPCI_NBUSY 0x04
#define HFCPCI_TIMER_ELAP 0x10
#define HFCPCI_STATINT 0x20
#define HFCPCI_FRAMEINT 0x40
#define HFCPCI_ANYINT 0x80
/* bits in CTMT (Write) */
#define HFCPCI_CLTIMER 0x80
#define HFCPCI_TIM3_125 0x04
#define HFCPCI_TIM25 0x10
#define HFCPCI_TIM50 0x14
#define HFCPCI_TIM400 0x18
#define HFCPCI_TIM800 0x1C
#define HFCPCI_AUTO_TIMER 0x20
#define HFCPCI_TRANSB2 0x02
#define HFCPCI_TRANSB1 0x01
/* bits in CIRM (Write) */
#define HFCPCI_AUX_MSK 0x07
#define HFCPCI_RESET 0x08
#define HFCPCI_B1_REV 0x40
#define HFCPCI_B2_REV 0x80
/* bits in INT_M1 and INT_S1 */
#define HFCPCI_INTS_B1TRANS 0x01
#define HFCPCI_INTS_B2TRANS 0x02
#define HFCPCI_INTS_DTRANS 0x04
#define HFCPCI_INTS_B1REC 0x08
#define HFCPCI_INTS_B2REC 0x10
#define HFCPCI_INTS_DREC 0x20
#define HFCPCI_INTS_L1STATE 0x40
#define HFCPCI_INTS_TIMER 0x80
/* bits in INT_M2 */
#define HFCPCI_PROC_TRANS 0x01
#define HFCPCI_GCI_I_CHG 0x02
#define HFCPCI_GCI_MON_REC 0x04
#define HFCPCI_IRQ_ENABLE 0x08
#define HFCPCI_PMESEL 0x80
/* bits in STATES */
#define HFCPCI_STATE_MSK 0x0F
#define HFCPCI_LOAD_STATE 0x10
#define HFCPCI_ACTIVATE 0x20
#define HFCPCI_DO_ACTION 0x40
#define HFCPCI_NT_G2_G3 0x80
/* bits in HFCD_MST_MODE */
#define HFCPCI_MASTER 0x01
#define HFCPCI_SLAVE 0x00
/* remaining bits are for codecs control */
/* bits in HFCD_SCTRL */
#define SCTRL_B1_ENA 0x01
#define SCTRL_B2_ENA 0x02
#define SCTRL_MODE_TE 0x00
#define SCTRL_MODE_NT 0x04
#define SCTRL_LOW_PRIO 0x08
#define SCTRL_SQ_ENA 0x10
#define SCTRL_TEST 0x20
#define SCTRL_NONE_CAP 0x40
#define SCTRL_PWR_DOWN 0x80
/* bits in SCTRL_E */
#define HFCPCI_AUTO_AWAKE 0x01
#define HFCPCI_DBIT_1 0x04
#define HFCPCI_IGNORE_COL 0x08
#define HFCPCI_CHG_B1_B2 0x80
/* bits in FIFO_EN register */
#define HFCPCI_FIFOEN_B1 0x03
#define HFCPCI_FIFOEN_B2 0x0C
#define HFCPCI_FIFOEN_DTX 0x10
#define HFCPCI_FIFOEN_DRX 0x20
#define HFCPCI_FIFOEN_B1TX 0x01
#define HFCPCI_FIFOEN_B1RX 0x02
#define HFCPCI_FIFOEN_B2TX 0x04
#define HFCPCI_FIFOEN_B2RX 0x08
/*
* thresholds for transparent B-channel mode
* change mask and threshold simultaneously
*/
#define HFCPCI_BTRANS_THRESHOLD 128
#define HFCPCI_BTRANS_THRESMASK 0x00
#define CLKDEL_TE 0x0e
/* CLKDEL in TE mode */
#define CLKDEL_NT 0x6c
/* CLKDEL in NT mode */
#define MAX_D_FRAMES 0x10
#define MAX_B_FRAMES 0x20
#define B_FIFO_START 0x0200
#define B_FIFO_END 0x2000
#define B_FIFO_SIZE (B_FIFO_END - B_FIFO_START)
#define D_FIFO_START 0x0000
#define D_FIFO_END 0x0200
#define D_FIFO_SIZE (D_FIFO_END - D_FIFO_START)
// ----------------------------------------------------------------------
// push messages to the upper layers
static
inline
void
D_L1L2
(
struct
hfcpci_adapter
*
adapter
,
int
pr
,
void
*
arg
)
{
struct
hisax_if
*
ifc
=
(
struct
hisax_if
*
)
&
adapter
->
d_if
;
DBG
(
DBG_PR
,
"pr %#x"
,
pr
);
ifc
->
l1l2
(
ifc
,
pr
,
arg
);
}
static
inline
void
B_L1L2
(
struct
hfcpci_bcs
*
bcs
,
int
pr
,
void
*
arg
)
{
struct
hisax_if
*
ifc
=
(
struct
hisax_if
*
)
&
bcs
->
b_if
;
DBG
(
DBG_PR
,
"pr %#x"
,
pr
);
ifc
->
l1l2
(
ifc
,
pr
,
arg
);
}
// ----------------------------------------------------------------------
// MMIO
static
inline
void
hfcpci_writeb
(
struct
hfcpci_adapter
*
adapter
,
u8
b
,
unsigned
char
offset
)
{
writeb
(
b
,
adapter
->
mmio
+
offset
);
}
static
inline
u8
hfcpci_readb
(
struct
hfcpci_adapter
*
adapter
,
unsigned
char
offset
)
{
return
readb
(
adapter
->
mmio
+
offset
);
}
// ----------------------------------------------------------------------
// magic to define the various F/Z counter accesses
#define DECL_B_F(r, f) \
static inline u8 \
get_b_##r##_##f (struct hfcpci_bcs *bcs) \
{ \
u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \
\
return *(bcs->adapter->fifo + off); \
} \
\
static inline void \
set_b_##r##_##f (struct hfcpci_bcs *bcs, u8 f) \
{ \
u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \
\
*(bcs->adapter->fifo + off) = f; \
}
#define OFF_B1_rx_f1 0x6080
#define OFF_B2_rx_f1 0x6180
#define OFF_B1_rx_f2 0x6081
#define OFF_B2_rx_f2 0x6181
#define OFF_B1_tx_f1 0x2080
#define OFF_B2_tx_f1 0x2180
#define OFF_B1_tx_f2 0x2081
#define OFF_B2_tx_f2 0x2181
DECL_B_F
(
rx
,
f1
)
DECL_B_F
(
rx
,
f2
)
DECL_B_F
(
tx
,
f1
)
DECL_B_F
(
tx
,
f2
)
#undef DECL_B_F
#define DECL_B_Z(r, z) \
static inline u16 \
get_b_##r##_##z (struct hfcpci_bcs *bcs, u8 f) \
{ \
u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \
\
return le16_to_cpu(*((u16 *) (bcs->adapter->fifo + off + f * 4))); \
} \
\
static inline void \
set_b_##r##_##z(struct hfcpci_bcs *bcs, u8 f, u16 z) \
{ \
u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \
\
*((u16 *) (bcs->adapter->fifo + off + f * 4)) = cpu_to_le16(z); \
}
#define OFF_B1_rx_z1 0x6000
#define OFF_B2_rx_z1 0x6100
#define OFF_B1_rx_z2 0x6002
#define OFF_B2_rx_z2 0x6102
#define OFF_B1_tx_z1 0x2000
#define OFF_B2_tx_z1 0x2100
#define OFF_B1_tx_z2 0x2002
#define OFF_B2_tx_z2 0x2102
DECL_B_Z
(
rx
,
z1
)
DECL_B_Z
(
rx
,
z2
)
DECL_B_Z
(
tx
,
z1
)
DECL_B_Z
(
tx
,
z2
)
#undef DECL_B_Z
#define DECL_D_F(r, f) \
static inline u8 \
get_d_##r##_##f (struct hfcpci_adapter *adapter) \
{ \
u16 off = OFF_D_##r##_##f; \
\
return *(adapter->fifo + off) & 0xf; \
} \
\
static inline void \
set_d_##r##_##f (struct hfcpci_adapter *adapter, u8 f) \
{ \
u16 off = OFF_D_##r##_##f; \
\
*(adapter->fifo + off) = f | 0x10; \
}
#define OFF_D_rx_f1 0x60a0
#define OFF_D_rx_f2 0x60a1
#define OFF_D_tx_f1 0x20a0
#define OFF_D_tx_f2 0x20a1
DECL_D_F
(
rx
,
f1
)
DECL_D_F
(
rx
,
f2
)
DECL_D_F
(
tx
,
f1
)
DECL_D_F
(
tx
,
f2
)
#undef DECL_D_F
#define DECL_D_Z(r, z) \
static inline u16 \
get_d_##r##_##z (struct hfcpci_adapter *adapter, u8 f) \
{ \
u16 off = OFF_D_##r##_##z; \
\
return le16_to_cpu(*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)));\
} \
\
static inline void \
set_d_##r##_##z(struct hfcpci_adapter *adapter, u8 f, u16 z) \
{ \
u16 off = OFF_D_##r##_##z; \
\
*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)) = cpu_to_le16(z); \
}
#define OFF_D_rx_z1 0x6080
#define OFF_D_rx_z2 0x6082
#define OFF_D_tx_z1 0x2080
#define OFF_D_tx_z2 0x2082
DECL_D_Z
(
rx
,
z1
)
DECL_D_Z
(
rx
,
z2
)
DECL_D_Z
(
tx
,
z1
)
DECL_D_Z
(
tx
,
z2
)
#undef DECL_B_Z
// ----------------------------------------------------------------------
// fill b / d fifos
static
inline
void
hfcpci_fill_d_fifo
(
struct
hfcpci_adapter
*
adapter
)
{
u8
f1
,
f2
;
u16
z1
,
z2
;
int
cnt
,
fcnt
;
char
*
fifo_adr
=
adapter
->
fifo
;
struct
sk_buff
*
tx_skb
=
adapter
->
tx_skb
;
f1
=
get_d_tx_f1
(
adapter
);
f2
=
get_d_tx_f2
(
adapter
);
DBG
(
DBG_D_XMIT
,
"f1 %#x f2 %#x"
,
f1
,
f2
);
fcnt
=
f1
-
f2
;
if
(
fcnt
<
0
)
fcnt
+=
MAX_D_FRAMES
;
if
(
fcnt
)
{
printk
(
"BUG
\n
"
);
return
;
}
z1
=
get_d_tx_z1
(
adapter
,
f1
);
z2
=
get_d_tx_z2
(
adapter
,
f1
);
//XXX
DBG
(
DBG_D_XMIT
,
"z1 %#x z2 %#x"
,
z1
,
z2
);
cnt
=
z2
-
z1
;
if
(
cnt
<=
0
)
cnt
+=
D_FIFO_SIZE
;
if
(
tx_skb
->
len
>
cnt
)
{
printk
(
"BUG
\n
"
);
return
;
}
cnt
=
tx_skb
->
len
;
if
(
z1
+
cnt
<=
D_FIFO_END
)
{
memcpy
(
fifo_adr
+
z1
,
tx_skb
->
data
,
cnt
);
}
else
{
memcpy
(
fifo_adr
+
z1
,
tx_skb
->
data
,
D_FIFO_END
-
z1
);
memcpy
(
fifo_adr
+
D_FIFO_START
,
tx_skb
->
data
+
(
D_FIFO_END
-
z1
),
cnt
-
(
D_FIFO_END
-
z1
));
}
z1
+=
cnt
;
if
(
z1
>=
D_FIFO_END
)
z1
-=
D_FIFO_SIZE
;
f1
=
(
f1
+
1
)
&
(
MAX_D_FRAMES
-
1
);
mb
();
set_d_tx_z1
(
adapter
,
f1
,
z1
);
mb
();
set_d_tx_f1
(
adapter
,
f1
);
}
static
inline
void
hfcpci_fill_b_fifo_hdlc
(
struct
hfcpci_bcs
*
bcs
)
{
u8
f1
,
f2
;
u16
z1
,
z2
;
int
cnt
,
fcnt
;
char
*
fifo_adr
=
bcs
->
adapter
->
fifo
+
(
bcs
->
channel
?
0x2000
:
0x0000
);
struct
sk_buff
*
tx_skb
=
bcs
->
tx_skb
;
f1
=
get_b_tx_f1
(
bcs
);
f2
=
get_b_tx_f2
(
bcs
);
DBG
(
DBG_B_XMIT
,
"f1 %#x f2 %#x"
,
f1
,
f2
);
fcnt
=
f1
-
f2
;
if
(
fcnt
<
0
)
fcnt
+=
MAX_B_FRAMES
;
if
(
fcnt
)
{
printk
(
"BUG
\n
"
);
return
;
}
z1
=
get_b_tx_z1
(
bcs
,
f1
);
z2
=
get_b_tx_z2
(
bcs
,
f1
);
//XXX
DBG
(
DBG_B_XMIT
,
"z1 %#x z2 %#x"
,
z1
,
z2
);
cnt
=
z2
-
z1
;
if
(
cnt
<=
0
)
cnt
+=
B_FIFO_SIZE
;
if
(
tx_skb
->
len
>
cnt
)
{
printk
(
"BUG
\n
"
);
return
;
}
cnt
=
tx_skb
->
len
;
if
(
z1
+
cnt
<=
B_FIFO_END
)
{
memcpy
(
fifo_adr
+
z1
,
tx_skb
->
data
,
cnt
);
}
else
{
memcpy
(
fifo_adr
+
z1
,
tx_skb
->
data
,
B_FIFO_END
-
z1
);
memcpy
(
fifo_adr
+
B_FIFO_START
,
tx_skb
->
data
+
(
B_FIFO_END
-
z1
),
cnt
-
(
B_FIFO_END
-
z1
));
}
z1
+=
cnt
;
if
(
z1
>=
B_FIFO_END
)
z1
-=
B_FIFO_SIZE
;
f1
=
(
f1
+
1
)
&
(
MAX_B_FRAMES
-
1
);
mb
();
set_b_tx_z1
(
bcs
,
f1
,
z1
);
mb
();
set_b_tx_f1
(
bcs
,
f1
);
}
static
inline
void
hfcpci_fill_b_fifo_trans
(
struct
hfcpci_bcs
*
bcs
)
{
int
cnt
;
char
*
fifo_adr
=
bcs
->
adapter
->
fifo
+
(
bcs
->
channel
?
0x2000
:
0x0000
);
struct
sk_buff
*
tx_skb
=
bcs
->
tx_skb
;
u8
f1
,
f2
;
u16
z1
,
z2
;
f1
=
get_b_tx_f1
(
bcs
);
f2
=
get_b_tx_f2
(
bcs
);
if
(
f1
!=
f2
)
BUG
();
z1
=
get_b_tx_z1
(
bcs
,
f1
);
z2
=
get_b_tx_z2
(
bcs
,
f1
);
cnt
=
z2
-
z1
;
if
(
cnt
<=
0
)
cnt
+=
B_FIFO_SIZE
;
if
(
tx_skb
->
len
>
cnt
)
BUG
();
if
(
z1
+
cnt
<=
B_FIFO_END
)
{
memcpy
(
fifo_adr
+
z1
,
tx_skb
->
data
,
cnt
);
}
else
{
memcpy
(
fifo_adr
+
z1
,
tx_skb
->
data
,
B_FIFO_END
-
z1
);
memcpy
(
fifo_adr
+
B_FIFO_START
,
tx_skb
->
data
+
(
B_FIFO_END
-
z1
),
cnt
-
(
B_FIFO_END
-
z1
));
}
z1
+=
cnt
;
if
(
z1
>=
B_FIFO_END
)
z1
-=
B_FIFO_SIZE
;
mb
();
set_b_tx_z1
(
bcs
,
f1
,
z1
);
}
static
inline
void
hfcpci_fill_b_fifo
(
struct
hfcpci_bcs
*
bcs
)
{
if
(
!
bcs
->
tx_skb
)
{
DBG
(
DBG_WARN
,
"?"
);
return
;
}
switch
(
bcs
->
mode
)
{
case
L1_MODE_TRANS
:
hfcpci_fill_b_fifo_trans
(
bcs
);
break
;
case
L1_MODE_HDLC
:
hfcpci_fill_b_fifo_hdlc
(
bcs
);
break
;
default:
DBG
(
DBG_WARN
,
"?"
);
}
}
static
void
hfcpci_clear_b_rx_fifo
(
struct
hfcpci_bcs
*
bcs
);
static
void
hfcpci_clear_b_tx_fifo
(
struct
hfcpci_bcs
*
bcs
);
static
void
hfcpci_b_mode
(
struct
hfcpci_bcs
*
bcs
,
int
mode
)
{
struct
hfcpci_adapter
*
adapter
=
bcs
->
adapter
;
DBG
(
DBG_B_XMIT
,
"B%d mode %d --> %d"
,
bcs
->
channel
+
1
,
bcs
->
mode
,
mode
);
if
(
bcs
->
mode
==
mode
)
return
;
switch
(
mode
)
{
case
L1_MODE_NULL
:
if
(
bcs
->
channel
==
0
)
{
adapter
->
sctrl
&=
~
SCTRL_B1_ENA
;
adapter
->
sctrl_r
&=
~
SCTRL_B1_ENA
;
adapter
->
fifo_en
&=
~
HFCPCI_FIFOEN_B1
;
adapter
->
int_m1
&=
~
(
HFCPCI_INTS_B1TRANS
+
HFCPCI_INTS_B1REC
);
}
else
{
adapter
->
sctrl
&=
~
SCTRL_B2_ENA
;
adapter
->
sctrl_r
&=
~
SCTRL_B2_ENA
;
adapter
->
fifo_en
&=
~
HFCPCI_FIFOEN_B2
;
adapter
->
int_m1
&=
~
(
HFCPCI_INTS_B2TRANS
+
HFCPCI_INTS_B2REC
);
}
break
;
case
L1_MODE_TRANS
:
case
L1_MODE_HDLC
:
hfcpci_clear_b_rx_fifo
(
bcs
);
hfcpci_clear_b_tx_fifo
(
bcs
);
if
(
bcs
->
channel
==
0
)
{
adapter
->
sctrl
|=
SCTRL_B1_ENA
;
adapter
->
sctrl_r
|=
SCTRL_B1_ENA
;
adapter
->
fifo_en
|=
HFCPCI_FIFOEN_B1
;
adapter
->
int_m1
|=
(
HFCPCI_INTS_B1TRANS
+
HFCPCI_INTS_B1REC
);
if
(
mode
==
L1_MODE_TRANS
)
adapter
->
ctmt
|=
1
;
else
adapter
->
ctmt
&=
~
1
;
}
else
{
adapter
->
sctrl
|=
SCTRL_B2_ENA
;
adapter
->
sctrl_r
|=
SCTRL_B2_ENA
;
adapter
->
fifo_en
|=
HFCPCI_FIFOEN_B2
;
adapter
->
int_m1
|=
(
HFCPCI_INTS_B2TRANS
+
HFCPCI_INTS_B2REC
);
if
(
mode
==
L1_MODE_TRANS
)
adapter
->
ctmt
|=
2
;
else
adapter
->
ctmt
&=
~
2
;
}
break
;
}
hfcpci_writeb
(
adapter
,
adapter
->
int_m1
,
HFCPCI_INT_M1
);
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
hfcpci_writeb
(
adapter
,
adapter
->
sctrl
,
HFCPCI_SCTRL
);
hfcpci_writeb
(
adapter
,
adapter
->
sctrl_r
,
HFCPCI_SCTRL_R
);
hfcpci_writeb
(
adapter
,
adapter
->
ctmt
,
HFCPCI_CTMT
);
hfcpci_writeb
(
adapter
,
adapter
->
conn
,
HFCPCI_CONNECT
);
bcs
->
mode
=
mode
;
}
// ----------------------------------------------------------------------
// Layer 1 state machine
static
struct
Fsm
l1fsm
;
enum
{
ST_L1_F0
,
ST_L1_F2
,
ST_L1_F3
,
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_F0"
,
"ST_L1_F2"
,
"ST_L1_F3"
,
"ST_L1_F4"
,
"ST_L1_F5"
,
"ST_L1_F6"
,
"ST_L1_F7"
,
"ST_L1_F8"
,
};
enum
{
EV_PH_F0
,
EV_PH_1
,
EV_PH_F2
,
EV_PH_F3
,
EV_PH_F4
,
EV_PH_F5
,
EV_PH_F6
,
EV_PH_F7
,
EV_PH_F8
,
EV_PH_ACTIVATE_REQ
,
EV_PH_DEACTIVATE_REQ
,
EV_TIMER3
,
};
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
static
char
*
strL1Event
[]
=
{
"EV_PH_F0"
,
"EV_PH_1"
,
"EV_PH_F2"
,
"EV_PH_F3"
,
"EV_PH_F4"
,
"EV_PH_F5"
,
"EV_PH_F6"
,
"EV_PH_F7"
,
"EV_PH_F8"
,
"EV_PH_ACTIVATE_REQ"
,
"EV_PH_DEACTIVATE_REQ"
,
"EV_TIMER3"
,
};
static
void
l1_ignore
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
}
static
void
l1_go_f3
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
FsmChangeState
(
fi
,
ST_L1_F3
);
}
static
void
l1_go_f3_deact_ind
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
struct
hfcpci_adapter
*
adapter
=
fi
->
userdata
;
FsmChangeState
(
fi
,
ST_L1_F3
);
D_L1L2
(
adapter
,
PH_DEACTIVATE
|
INDICATION
,
NULL
);
}
static
void
l1_go_f4
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
FsmChangeState
(
fi
,
ST_L1_F3
);
}
static
void
l1_go_f5
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
FsmChangeState
(
fi
,
ST_L1_F3
);
}
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
hfcpci_adapter
*
adapter
=
fi
->
userdata
;
FsmChangeState
(
fi
,
ST_L1_F6
);
D_L1L2
(
adapter
,
PH_DEACTIVATE
|
INDICATION
,
NULL
);
}
static
void
l1_go_f7
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
FsmChangeState
(
fi
,
ST_L1_F7
);
}
static
void
l1_go_f7_act_ind
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
struct
hfcpci_adapter
*
adapter
=
fi
->
userdata
;
FsmChangeState
(
fi
,
ST_L1_F7
);
D_L1L2
(
adapter
,
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
hfcpci_adapter
*
adapter
=
fi
->
userdata
;
FsmChangeState
(
fi
,
ST_L1_F8
);
D_L1L2
(
adapter
,
PH_DEACTIVATE
|
INDICATION
,
NULL
);
}
static
void
l1_act_req
(
struct
FsmInst
*
fi
,
int
event
,
void
*
arg
)
{
struct
hfcpci_adapter
*
adapter
=
fi
->
userdata
;
hfcpci_writeb
(
adapter
,
HFCPCI_ACTIVATE
|
HFCPCI_DO_ACTION
,
HFCPCI_STATES
);
}
static
struct
FsmNode
L1FnList
[]
__initdata
=
{
{
ST_L1_F2
,
EV_PH_F3
,
l1_go_f3
},
{
ST_L1_F2
,
EV_PH_F6
,
l1_go_f6
},
{
ST_L1_F2
,
EV_PH_F7
,
l1_go_f7_act_ind
},
{
ST_L1_F3
,
EV_PH_F3
,
l1_ignore
},
{
ST_L1_F3
,
EV_PH_F4
,
l1_go_f4
},
{
ST_L1_F3
,
EV_PH_F5
,
l1_go_f5
},
{
ST_L1_F3
,
EV_PH_F6
,
l1_go_f6
},
{
ST_L1_F3
,
EV_PH_F7
,
l1_go_f7_act_ind
},
{
ST_L1_F3
,
EV_PH_ACTIVATE_REQ
,
l1_act_req
},
{
ST_L1_F4
,
EV_PH_F7
,
l1_ignore
},
{
ST_L1_F4
,
EV_PH_F3
,
l1_go_f3
},
{
ST_L1_F4
,
EV_PH_F5
,
l1_go_f5
},
{
ST_L1_F4
,
EV_PH_F6
,
l1_go_f6
},
{
ST_L1_F4
,
EV_PH_F7
,
l1_go_f7
},
{
ST_L1_F5
,
EV_PH_F7
,
l1_ignore
},
{
ST_L1_F5
,
EV_PH_F3
,
l1_go_f3
},
{
ST_L1_F5
,
EV_PH_F6
,
l1_go_f6
},
{
ST_L1_F5
,
EV_PH_F7
,
l1_go_f7
},
{
ST_L1_F6
,
EV_PH_F7
,
l1_ignore
},
{
ST_L1_F6
,
EV_PH_F3
,
l1_go_f3
},
{
ST_L1_F6
,
EV_PH_F7
,
l1_go_f7_act_ind
},
{
ST_L1_F6
,
EV_PH_F8
,
l1_go_f8
},
{
ST_L1_F7
,
EV_PH_F7
,
l1_ignore
},
{
ST_L1_F7
,
EV_PH_F3
,
l1_go_f3_deact_ind
},
{
ST_L1_F7
,
EV_PH_F6
,
l1_go_f6_deact_ind
},
{
ST_L1_F7
,
EV_PH_F8
,
l1_go_f8_deact_ind
},
{
ST_L1_F8
,
EV_PH_F7
,
l1_ignore
},
{
ST_L1_F8
,
EV_PH_F3
,
l1_go_f3
},
{
ST_L1_F8
,
EV_PH_F6
,
l1_go_f6
},
{
ST_L1_F8
,
EV_PH_F7
,
l1_go_f7_act_ind
},
};
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
);
}
// ----------------------------------------------------------------------
// clear FIFOs
static
void
hfcpci_clear_d_rx_fifo
(
struct
hfcpci_adapter
*
adapter
)
{
u8
fifo_state
;
DBG
(
DBG_D_RECV
,
""
);
fifo_state
=
adapter
->
fifo_en
&
HFCPCI_FIFOEN_DRX
;
if
(
fifo_state
)
{
// enabled
// XXX locking
adapter
->
fifo_en
&=
~
fifo_state
;
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
}
adapter
->
last_fcnt
=
0
;
set_d_rx_z1
(
adapter
,
MAX_D_FRAMES
-
1
,
D_FIFO_END
-
1
);
set_d_rx_z2
(
adapter
,
MAX_D_FRAMES
-
1
,
D_FIFO_END
-
1
);
mb
();
set_d_rx_f1
(
adapter
,
MAX_D_FRAMES
-
1
);
set_d_rx_f2
(
adapter
,
MAX_D_FRAMES
-
1
);
mb
();
if
(
fifo_state
)
{
adapter
->
fifo_en
|=
fifo_state
;
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
}
}
static
void
hfcpci_clear_b_rx_fifo
(
struct
hfcpci_bcs
*
bcs
)
{
struct
hfcpci_adapter
*
adapter
=
bcs
->
adapter
;
int
nr
=
bcs
->
channel
;
u8
fifo_state
;
DBG
(
DBG_B_RECV
,
""
);
fifo_state
=
adapter
->
fifo_en
&
(
nr
?
HFCPCI_FIFOEN_B2RX
:
HFCPCI_FIFOEN_B1RX
);
if
(
fifo_state
)
{
// enabled
adapter
->
fifo_en
&=
~
fifo_state
;
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
}
bcs
->
last_fcnt
=
0
;
set_b_rx_z1
(
bcs
,
MAX_B_FRAMES
-
1
,
B_FIFO_END
-
1
);
set_b_rx_z2
(
bcs
,
MAX_B_FRAMES
-
1
,
B_FIFO_END
-
1
);
mb
();
set_b_rx_f1
(
bcs
,
MAX_B_FRAMES
-
1
);
set_b_rx_f2
(
bcs
,
MAX_B_FRAMES
-
1
);
mb
();
if
(
fifo_state
)
{
adapter
->
fifo_en
|=
fifo_state
;
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
}
}
// XXX clear d_tx_fifo?
static
void
hfcpci_clear_b_tx_fifo
(
struct
hfcpci_bcs
*
bcs
)
{
struct
hfcpci_adapter
*
adapter
=
bcs
->
adapter
;
int
nr
=
bcs
->
channel
;
u8
fifo_state
;
fifo_state
=
adapter
->
fifo_en
&
(
nr
?
HFCPCI_FIFOEN_B2TX
:
HFCPCI_FIFOEN_B1TX
);
if
(
fifo_state
)
{
// enabled
adapter
->
fifo_en
&=
~
fifo_state
;
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
}
bcs
->
last_fcnt
=
0
;
set_b_rx_z1
(
bcs
,
MAX_B_FRAMES
-
1
,
B_FIFO_END
-
1
);
set_b_rx_z2
(
bcs
,
MAX_B_FRAMES
-
1
,
B_FIFO_END
-
1
);
mb
();
set_b_rx_f1
(
bcs
,
MAX_B_FRAMES
-
1
);
set_b_rx_f2
(
bcs
,
MAX_B_FRAMES
-
1
);
mb
();
if
(
fifo_state
)
{
adapter
->
fifo_en
|=
fifo_state
;
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
}
}
// ----------------------------------------------------------------------
// receive messages from upper layers
static
void
hfcpci_d_l2l1
(
struct
hisax_if
*
ifc
,
int
pr
,
void
*
arg
)
{
struct
hfcpci_adapter
*
adapter
=
ifc
->
priv
;
struct
sk_buff
*
skb
=
arg
;
DBG
(
DBG_PR
,
"pr %#x"
,
pr
);
switch
(
pr
)
{
case
PH_ACTIVATE
|
REQUEST
:
FsmEvent
(
&
adapter
->
l1m
,
EV_PH_ACTIVATE_REQ
,
NULL
);
break
;
case
PH_DEACTIVATE
|
REQUEST
:
FsmEvent
(
&
adapter
->
l1m
,
EV_PH_DEACTIVATE_REQ
,
NULL
);
break
;
case
PH_DATA
|
REQUEST
:
DBG
(
DBG_PR
,
"PH_DATA REQUEST len %d"
,
skb
->
len
);
DBG_SKB
(
DBG_D_XMIT
,
skb
);
if
(
adapter
->
l1m
.
state
!=
ST_L1_F7
)
{
DBG
(
DBG_WARN
,
"L1 wrong state %d"
,
adapter
->
l1m
.
state
);
break
;
}
if
(
adapter
->
tx_skb
)
BUG
();
adapter
->
tx_skb
=
skb
;
hfcpci_fill_d_fifo
(
adapter
);
break
;
}
}
static
void
hfcpci_b_l2l1
(
struct
hisax_if
*
ifc
,
int
pr
,
void
*
arg
)
{
struct
hfcpci_bcs
*
bcs
=
ifc
->
priv
;
struct
sk_buff
*
skb
=
arg
;
int
mode
;
DBG
(
DBG_PR
,
"pr %#x"
,
pr
);
switch
(
pr
)
{
case
PH_DATA
|
REQUEST
:
if
(
bcs
->
tx_skb
)
BUG
();
bcs
->
tx_skb
=
skb
;
DBG_SKB
(
DBG_B_XMIT
,
skb
);
hfcpci_fill_b_fifo
(
bcs
);
break
;
case
PH_ACTIVATE
|
REQUEST
:
mode
=
(
int
)
arg
;
DBG
(
DBG_PR
,
"B%d,PH_ACTIVATE_REQUEST %d"
,
bcs
->
channel
+
1
,
mode
);
hfcpci_b_mode
(
bcs
,
mode
);
B_L1L2
(
bcs
,
PH_ACTIVATE
|
INDICATION
,
NULL
);
break
;
case
PH_DEACTIVATE
|
REQUEST
:
DBG
(
DBG_PR
,
"B%d,PH_DEACTIVATE_REQUEST"
,
bcs
->
channel
+
1
);
hfcpci_b_mode
(
bcs
,
L1_MODE_NULL
);
B_L1L2
(
bcs
,
PH_DEACTIVATE
|
INDICATION
,
NULL
);
break
;
}
}
// ----------------------------------------------------------------------
// receive IRQ
static
inline
void
hfcpci_d_recv_irq
(
struct
hfcpci_adapter
*
adapter
)
{
struct
sk_buff
*
skb
;
char
*
fifo_adr
=
adapter
->
fifo
+
0x4000
;
char
*
p
;
int
cnt
,
fcnt
;
int
loop
=
5
;
u8
f1
,
f2
;
u16
z1
,
z2
;
while
(
loop
--
>
0
)
{
f1
=
get_d_rx_f1
(
adapter
);
f2
=
get_d_rx_f2
(
adapter
);
DBG
(
DBG_D_RECV
,
"f1 %#x f2 %#x"
,
f1
,
f2
);
fcnt
=
f1
-
f2
;
if
(
fcnt
<
0
)
fcnt
+=
16
;
if
(
!
fcnt
)
return
;
if
(
fcnt
<
adapter
->
last_fcnt
)
/* overrun */
hfcpci_clear_d_rx_fifo
(
adapter
);
// XXX init last_fcnt
z1
=
get_d_rx_z1
(
adapter
,
f2
);
z2
=
get_d_rx_z2
(
adapter
,
f2
);
DBG
(
DBG_D_RECV
,
"z1 %#x z2 %#x"
,
z1
,
z2
);
cnt
=
z1
-
z2
;
if
(
cnt
<
0
)
cnt
+=
D_FIFO_SIZE
;
cnt
++
;
if
(
cnt
<
4
)
{
DBG
(
DBG_WARN
,
"frame too short"
);
goto
next
;
}
if
(
fifo_adr
[
z1
]
!=
0
)
{
DBG
(
DBG_WARN
,
"CRC error"
);
goto
next
;
}
cnt
-=
3
;
skb
=
dev_alloc_skb
(
cnt
);
if
(
!
skb
)
{
DBG
(
DBG_WARN
,
"no mem"
);
goto
next
;
}
p
=
skb_put
(
skb
,
cnt
);
if
(
z2
+
cnt
<=
D_FIFO_END
)
{
memcpy
(
p
,
fifo_adr
+
z2
,
cnt
);
}
else
{
memcpy
(
p
,
fifo_adr
+
z2
,
D_FIFO_END
-
z2
);
memcpy
(
p
+
(
D_FIFO_END
-
z2
),
fifo_adr
+
D_FIFO_START
,
cnt
-
(
D_FIFO_END
-
z2
));
}
DBG_SKB
(
DBG_D_RECV
,
skb
);
D_L1L2
(
adapter
,
PH_DATA
|
INDICATION
,
skb
);
next:
if
(
++
z1
>=
D_FIFO_END
)
z1
-=
D_FIFO_START
;
f2
=
(
f2
+
1
)
&
(
MAX_D_FRAMES
-
1
);
mb
();
set_d_rx_z2
(
adapter
,
f2
,
z1
);
mb
();
set_d_rx_f2
(
adapter
,
f2
);
adapter
->
last_fcnt
=
fcnt
-
1
;
}
}
static
inline
void
hfcpci_b_recv_hdlc_irq
(
struct
hfcpci_adapter
*
adapter
,
int
nr
)
{
struct
hfcpci_bcs
*
bcs
=
&
adapter
->
bcs
[
nr
];
struct
sk_buff
*
skb
;
char
*
fifo_adr
=
adapter
->
fifo
+
(
nr
?
0x6000
:
0x4000
);
char
*
p
;
int
cnt
,
fcnt
;
int
loop
=
5
;
u8
f1
,
f2
;
u16
z1
,
z2
;
while
(
loop
--
>
0
)
{
f1
=
get_b_rx_f1
(
bcs
);
f2
=
get_b_rx_f2
(
bcs
);
DBG
(
DBG_B_RECV
,
"f1 %d f2 %d"
,
f1
,
f2
);
fcnt
=
f1
-
f2
;
if
(
fcnt
<
0
)
fcnt
+=
32
;
if
(
!
fcnt
)
return
;
if
(
fcnt
<
bcs
->
last_fcnt
)
/* overrun */
hfcpci_clear_b_rx_fifo
(
bcs
);
// XXX init last_fcnt
z1
=
get_b_rx_z1
(
bcs
,
f2
);
z2
=
get_b_rx_z2
(
bcs
,
f2
);
DBG
(
DBG_B_RECV
,
"z1 %d z2 %d"
,
z1
,
z2
);
cnt
=
z1
-
z2
;
if
(
cnt
<
0
)
cnt
+=
B_FIFO_SIZE
;
cnt
++
;
if
(
cnt
<
4
)
{
DBG
(
DBG_WARN
,
"frame too short"
);
goto
next
;
}
if
(
fifo_adr
[
z1
]
!=
0
)
{
DBG
(
DBG_WARN
,
"CRC error"
);
goto
next
;
}
cnt
-=
3
;
skb
=
dev_alloc_skb
(
cnt
);
if
(
!
skb
)
{
DBG
(
DBG_WARN
,
"no mem"
);
goto
next
;
}
p
=
skb_put
(
skb
,
cnt
);
if
(
z2
+
cnt
<=
B_FIFO_END
)
{
memcpy
(
p
,
fifo_adr
+
z2
,
cnt
);
}
else
{
memcpy
(
p
,
fifo_adr
+
z2
,
B_FIFO_END
-
z2
);
memcpy
(
p
+
(
B_FIFO_END
-
z2
),
fifo_adr
+
B_FIFO_START
,
cnt
-
(
B_FIFO_END
-
z2
));
}
DBG_SKB
(
DBG_B_RECV
,
skb
);
B_L1L2
(
bcs
,
PH_DATA
|
INDICATION
,
skb
);
next:
if
(
++
z1
>=
B_FIFO_END
)
z1
-=
B_FIFO_SIZE
;
f2
=
(
f2
+
1
)
&
(
MAX_B_FRAMES
-
1
);
mb
();
set_b_rx_z2
(
bcs
,
f2
,
z1
);
mb
();
set_b_rx_f2
(
bcs
,
f2
);
bcs
->
last_fcnt
=
fcnt
-
1
;
}
}
static
inline
void
hfcpci_b_recv_trans_irq
(
struct
hfcpci_adapter
*
adapter
,
int
nr
)
{
struct
hfcpci_bcs
*
bcs
=
&
adapter
->
bcs
[
nr
];
struct
sk_buff
*
skb
;
char
*
fifo_adr
=
adapter
->
fifo
+
(
nr
?
0x6000
:
0x4000
);
char
*
p
;
int
cnt
;
int
loop
=
5
;
u8
f1
,
f2
;
u16
z1
,
z2
;
f1
=
get_b_rx_f1
(
bcs
);
f2
=
get_b_rx_f2
(
bcs
);
if
(
f1
!=
f2
)
BUG
();
while
(
loop
--
>
0
)
{
z1
=
get_b_rx_z1
(
bcs
,
f2
);
z2
=
get_b_rx_z2
(
bcs
,
f2
);
cnt
=
z1
-
z2
;
if
(
!
cnt
)
/* no data available */
return
;
if
(
cnt
<
0
)
cnt
+=
B_FIFO_SIZE
;
if
(
cnt
>
HFCPCI_BTRANS_THRESHOLD
)
cnt
=
HFCPCI_BTRANS_THRESHOLD
;
skb
=
dev_alloc_skb
(
cnt
);
if
(
!
skb
)
{
DBG
(
DBG_WARN
,
"no mem"
);
goto
next
;
}
p
=
skb_put
(
skb
,
cnt
);
if
(
z2
+
cnt
<=
0x2000
)
{
memcpy
(
p
,
fifo_adr
+
z2
,
cnt
);
}
else
{
memcpy
(
p
,
fifo_adr
+
z2
,
0x2000
-
z2
);
p
+=
0x2000
-
z2
;
memcpy
(
p
,
fifo_adr
+
0x200
,
cnt
-
(
0x2000
-
z2
));
}
DBG_SKB
(
DBG_B_RECV
,
skb
);
B_L1L2
(
bcs
,
PH_DATA
|
INDICATION
,
skb
);
next:
z2
+=
cnt
;
if
(
z2
>=
0x2000
)
z2
-=
B_FIFO_SIZE
;
mb
();
set_b_rx_z2
(
bcs
,
f2
,
z2
);
// XXX always receive buffers of a given size
}
}
static
inline
void
hfcpci_b_recv_irq
(
struct
hfcpci_adapter
*
adapter
,
int
nr
)
{
DBG
(
DBG_B_RECV
,
""
);
switch
(
adapter
->
bcs
[
nr
].
mode
)
{
case
L1_MODE_NULL
:
DBG
(
DBG_WARN
,
"?"
);
break
;
case
L1_MODE_HDLC
:
hfcpci_b_recv_hdlc_irq
(
adapter
,
nr
);
break
;
case
L1_MODE_TRANS
:
hfcpci_b_recv_trans_irq
(
adapter
,
nr
);
break
;
}
}
// ----------------------------------------------------------------------
// transmit IRQ
// XXX make xmit FIFO deeper than 1
static
inline
void
hfcpci_d_xmit_irq
(
struct
hfcpci_adapter
*
adapter
)
{
struct
sk_buff
*
skb
;
DBG
(
DBG_D_XMIT
,
""
);
skb
=
adapter
->
tx_skb
;
if
(
!
skb
)
{
DBG
(
DBG_WARN
,
"?"
);
return
;
}
adapter
->
tx_skb
=
NULL
;
D_L1L2
(
adapter
,
PH_DATA
|
CONFIRM
,
(
void
*
)
skb
->
truesize
);
dev_kfree_skb_irq
(
skb
);
}
static
inline
void
hfcpci_b_xmit_irq
(
struct
hfcpci_adapter
*
adapter
,
int
nr
)
{
struct
hfcpci_bcs
*
bcs
=
&
adapter
->
bcs
[
nr
];
struct
sk_buff
*
skb
;
DBG
(
DBG_B_XMIT
,
""
);
skb
=
bcs
->
tx_skb
;
if
(
!
skb
)
{
DBG
(
DBG_WARN
,
"?"
);
return
;
}
bcs
->
tx_skb
=
NULL
;
B_L1L2
(
bcs
,
PH_DATA
|
CONFIRM
,
(
void
*
)
skb
->
truesize
);
dev_kfree_skb_irq
(
skb
);
}
// ----------------------------------------------------------------------
// Layer 1 state change IRQ
static
inline
void
hfcpci_state_irq
(
struct
hfcpci_adapter
*
adapter
)
{
u8
val
;
val
=
hfcpci_readb
(
adapter
,
HFCPCI_STATES
);
DBG
(
DBG_L1M
,
"STATES %#x"
,
val
);
FsmEvent
(
&
adapter
->
l1m
,
val
&
0xf
,
NULL
);
}
// ----------------------------------------------------------------------
// Timer IRQ
static
inline
void
hfcpci_timer_irq
(
struct
hfcpci_adapter
*
adapter
)
{
hfcpci_writeb
(
adapter
,
adapter
->
ctmt
|
HFCPCI_CLTIMER
,
HFCPCI_CTMT
);
}
// ----------------------------------------------------------------------
// IRQ handler
static
void
hfcpci_irq
(
int
intno
,
void
*
dev
,
struct
pt_regs
*
regs
)
{
struct
hfcpci_adapter
*
adapter
=
dev
;
int
loop
=
15
;
u8
val
,
stat
;
if
(
!
(
adapter
->
int_m2
&
0x08
))
return
;
/* not initialised */
// XX
stat
=
hfcpci_readb
(
adapter
,
HFCPCI_STATUS
);
if
(
!
(
stat
&
HFCPCI_ANYINT
))
return
;
spin_lock
(
&
adapter
->
hw_lock
);
while
(
loop
--
>
0
)
{
val
=
hfcpci_readb
(
adapter
,
HFCPCI_INT_S1
);
DBG
(
DBG_IRQ
,
"stat %02x s1 %02x"
,
stat
,
val
);
val
&=
adapter
->
int_m1
;
if
(
!
val
)
break
;
if
(
val
&
0x08
)
hfcpci_b_recv_irq
(
adapter
,
0
);
if
(
val
&
0x10
)
hfcpci_b_recv_irq
(
adapter
,
1
);
if
(
val
&
0x01
)
hfcpci_b_xmit_irq
(
adapter
,
0
);
if
(
val
&
0x02
)
hfcpci_b_xmit_irq
(
adapter
,
1
);
if
(
val
&
0x20
)
hfcpci_d_recv_irq
(
adapter
);
if
(
val
&
0x04
)
hfcpci_d_xmit_irq
(
adapter
);
if
(
val
&
0x40
)
hfcpci_state_irq
(
adapter
);
if
(
val
&
0x80
)
hfcpci_timer_irq
(
adapter
);
}
spin_unlock
(
&
adapter
->
hw_lock
);
}
// ----------------------------------------------------------------------
// reset hardware
static
void
hfcpci_reset
(
struct
hfcpci_adapter
*
adapter
)
{
/* disable all interrupts */
adapter
->
int_m1
=
0
;
adapter
->
int_m2
=
0
;
hfcpci_writeb
(
adapter
,
adapter
->
int_m1
,
HFCPCI_INT_M1
);
hfcpci_writeb
(
adapter
,
adapter
->
int_m2
,
HFCPCI_INT_M2
);
/* reset */
hfcpci_writeb
(
adapter
,
HFCPCI_RESET
,
HFCPCI_CIRM
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
((
30
*
HZ
)
/
1000
);
hfcpci_writeb
(
adapter
,
0
,
HFCPCI_CIRM
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
((
20
*
HZ
)
/
1000
);
if
(
hfcpci_readb
(
adapter
,
HFCPCI_STATUS
)
&
2
)
// XX
printk
(
KERN_WARNING
"HFC-PCI init bit busy
\n
"
);
}
// ----------------------------------------------------------------------
// init hardware
static
void
hfcpci_hw_init
(
struct
hfcpci_adapter
*
adapter
)
{
adapter
->
fifo_en
=
0x30
;
/* only D fifos enabled */
// XX
hfcpci_writeb
(
adapter
,
adapter
->
fifo_en
,
HFCPCI_FIFO_EN
);
/* no echo connect , threshold */
adapter
->
trm
=
HFCPCI_BTRANS_THRESMASK
;
hfcpci_writeb
(
adapter
,
adapter
->
trm
,
HFCPCI_TRM
);
/* ST-Bit delay for TE-Mode */
hfcpci_writeb
(
adapter
,
CLKDEL_TE
,
HFCPCI_CLKDEL
);
/* S/T Auto awake */
adapter
->
sctrl_e
=
HFCPCI_AUTO_AWAKE
;
hfcpci_writeb
(
adapter
,
adapter
->
sctrl_e
,
HFCPCI_SCTRL_E
);
/* no exchange */
adapter
->
bswapped
=
0
;
/* we are in TE mode */
adapter
->
nt_mode
=
0
;
adapter
->
ctmt
=
HFCPCI_TIM3_125
|
HFCPCI_AUTO_TIMER
;
hfcpci_writeb
(
adapter
,
adapter
->
ctmt
,
HFCPCI_CTMT
);
adapter
->
int_m1
=
HFCPCI_INTS_DTRANS
|
HFCPCI_INTS_DREC
|
HFCPCI_INTS_L1STATE
;
hfcpci_writeb
(
adapter
,
adapter
->
int_m1
,
HFCPCI_INT_M1
);
/* clear already pending ints */
hfcpci_readb
(
adapter
,
HFCPCI_INT_S1
);
adapter
->
l1m
.
state
=
2
;
hfcpci_writeb
(
adapter
,
HFCPCI_LOAD_STATE
|
2
,
HFCPCI_STATES
);
// XX /* HFC ST 2 */
udelay
(
10
);
hfcpci_writeb
(
adapter
,
2
,
HFCPCI_STATES
);
/* HFC ST 2 */
/* HFC Master Mode */
adapter
->
mst_m
=
HFCPCI_MASTER
;
hfcpci_writeb
(
adapter
,
adapter
->
mst_m
,
HFCPCI_MST_MODE
);
/* set tx_lo mode, error in datasheet ! */
adapter
->
sctrl
=
0x40
;
hfcpci_writeb
(
adapter
,
adapter
->
sctrl
,
HFCPCI_SCTRL
);
adapter
->
sctrl_r
=
0
;
hfcpci_writeb
(
adapter
,
adapter
->
sctrl_r
,
HFCPCI_SCTRL_R
);
// XXX
/* Init GCI/IOM2 in master mode */
/* Slots 0 and 1 are set for B-chan 1 and 2 */
/* D- and monitor/CI channel are not enabled */
/* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
/* STIO2 is used as data input, B1+B2 from IOM->ST */
/* ST B-channel send disabled -> continous 1s */
/* The IOM slots are always enabled */
adapter
->
conn
=
0
;
/* set data flow directions */
hfcpci_writeb
(
adapter
,
adapter
->
conn
,
HFCPCI_CONNECT
);
hfcpci_writeb
(
adapter
,
0x80
,
HFCPCI_B1_SSL
);
/* B1-Slot 0 STIO1 out enabled */
hfcpci_writeb
(
adapter
,
0x81
,
HFCPCI_B2_SSL
);
/* B2-Slot 1 STIO1 out enabled */
hfcpci_writeb
(
adapter
,
0x80
,
HFCPCI_B1_RSL
);
/* B1-Slot 0 STIO2 in enabled */
hfcpci_writeb
(
adapter
,
0x81
,
HFCPCI_B2_RSL
);
/* B2-Slot 1 STIO2 in enabled */
/* Finally enable IRQ output */
adapter
->
int_m2
=
HFCPCI_IRQ_ENABLE
;
hfcpci_writeb
(
adapter
,
adapter
->
int_m2
,
HFCPCI_INT_M2
);
hfcpci_readb
(
adapter
,
HFCPCI_INT_S2
);
}
// ----------------------------------------------------------------------
// probe / remove
static
struct
hfcpci_adapter
*
__devinit
new_adapter
(
struct
pci_dev
*
pdev
)
{
struct
hfcpci_adapter
*
adapter
;
struct
hisax_b_if
*
b_if
[
2
];
int
i
;
adapter
=
kmalloc
(
sizeof
(
struct
hfcpci_adapter
),
GFP_KERNEL
);
if
(
!
adapter
)
return
NULL
;
memset
(
adapter
,
0
,
sizeof
(
struct
hfcpci_adapter
));
SET_MODULE_OWNER
(
&
adapter
->
d_if
);
adapter
->
d_if
.
ifc
.
priv
=
adapter
;
adapter
->
d_if
.
ifc
.
l2l1
=
hfcpci_d_l2l1
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
adapter
->
bcs
[
i
].
adapter
=
adapter
;
adapter
->
bcs
[
i
].
channel
=
i
;
adapter
->
bcs
[
i
].
b_if
.
ifc
.
priv
=
&
adapter
->
bcs
[
i
];
adapter
->
bcs
[
i
].
b_if
.
ifc
.
l2l1
=
hfcpci_b_l2l1
;
}
pci_set_drvdata
(
pdev
,
adapter
);
for
(
i
=
0
;
i
<
2
;
i
++
)
b_if
[
i
]
=
&
adapter
->
bcs
[
i
].
b_if
;
hisax_register
(
&
adapter
->
d_if
,
b_if
,
"hfcpci"
,
protocol
);
return
adapter
;
}
static
void
delete_adapter
(
struct
hfcpci_adapter
*
adapter
)
{
hisax_unregister
(
&
adapter
->
d_if
);
kfree
(
adapter
);
}
static
int
__devinit
hfcpci_probe
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
struct
hfcpci_adapter
*
adapter
;
int
retval
;
DBG
(
DBG_INFO
,
""
);
retval
=
-
ENOMEM
;
adapter
=
new_adapter
(
pdev
);
if
(
!
adapter
)
goto
err
;
retval
=
pci_enable_device
(
pdev
);
if
(
retval
)
goto
err_free
;
adapter
->
irq
=
pdev
->
irq
;
retval
=
request_irq
(
adapter
->
irq
,
hfcpci_irq
,
SA_SHIRQ
,
"hfcpci"
,
adapter
);
if
(
retval
)
goto
err_free
;
retval
=
-
EBUSY
;
if
(
!
request_mem_region
(
pci_resource_start
(
pdev
,
1
),
256
,
"hfcpci"
))
goto
err_free_irq
;
adapter
->
mmio
=
ioremap
(
pci_resource_start
(
pdev
,
1
),
256
);
// XX pci_io
if
(
!
adapter
->
mmio
)
goto
err_release_region
;
/* Allocate 32K for FIFOs */
if
(
pci_set_dma_mask
(
pdev
,
0xffffffff
))
goto
err_unmap
;
adapter
->
fifo
=
pci_alloc_consistent
(
pdev
,
32768
,
&
adapter
->
fifo_dma
);
if
(
!
adapter
->
fifo
)
goto
err_unmap
;
pci_write_config_dword
(
pdev
,
HFCPCI_MWBA
,
(
u32
)
adapter
->
fifo_dma
);
pci_set_master
(
pdev
);
adapter
->
l1m
.
fsm
=
&
l1fsm
;
adapter
->
l1m
.
state
=
ST_L1_F0
;
#ifdef CONFIG_HISAX_DEBUG
adapter
->
l1m
.
debug
=
1
;
#else
adapter
->
l1m
.
debug
=
0
;
#endif
adapter
->
l1m
.
userdata
=
adapter
;
adapter
->
l1m
.
printdebug
=
l1m_debug
;
FsmInitTimer
(
&
adapter
->
l1m
,
&
adapter
->
timer
);
hfcpci_reset
(
adapter
);
hfcpci_hw_init
(
adapter
);
printk
(
KERN_INFO
"hisax_hfcpci: found adapter %s at %s
\n
"
,
(
char
*
)
ent
->
driver_data
,
pdev
->
slot_name
);
return
0
;
err_unmap:
iounmap
(
adapter
->
mmio
);
err_release_region:
release_mem_region
(
pci_resource_start
(
pdev
,
1
),
256
);
err_free_irq:
free_irq
(
adapter
->
irq
,
adapter
);
err_free:
delete_adapter
(
adapter
);
err:
return
retval
;
}
static
void
__devexit
hfcpci_remove
(
struct
pci_dev
*
pdev
)
{
struct
hfcpci_adapter
*
adapter
=
pci_get_drvdata
(
pdev
);
hfcpci_reset
(
adapter
);
// del_timer(&cs->hw.hfcpci.timer); XX
/* disable DMA */
pci_disable_device
(
pdev
);
pci_write_config_dword
(
pdev
,
HFCPCI_MWBA
,
0
);
pci_free_consistent
(
pdev
,
32768
,
adapter
->
fifo
,
adapter
->
fifo_dma
);
iounmap
(
adapter
->
mmio
);
release_mem_region
(
pci_resource_start
(
pdev
,
1
),
256
);
free_irq
(
adapter
->
irq
,
adapter
);
delete_adapter
(
adapter
);
}
static
struct
pci_driver
hfcpci_driver
=
{
name:
"hfcpci"
,
probe:
hfcpci_probe
,
remove:
hfcpci_remove
,
id_table:
hfcpci_ids
,
};
static
int
__init
hisax_hfcpci_init
(
void
)
{
int
retval
;
printk
(
KERN_INFO
"hisax_hfcpcipnp: HFC PCI ISDN driver v0.0.1
\n
"
);
l1fsm
.
state_count
=
L1_STATE_COUNT
;
l1fsm
.
event_count
=
L1_EVENT_COUNT
;
l1fsm
.
strState
=
strL1State
;
l1fsm
.
strEvent
=
strL1Event
;
retval
=
FsmNew
(
&
l1fsm
,
L1FnList
,
ARRAY_SIZE
(
L1FnList
));
if
(
retval
)
goto
err
;
retval
=
pci_module_init
(
&
hfcpci_driver
);
if
(
retval
)
goto
err_fsm
;
return
0
;
err_fsm:
FsmFree
(
&
l1fsm
);
err:
return
retval
;
}
static
void
__exit
hisax_hfcpci_exit
(
void
)
{
FsmFree
(
&
l1fsm
);
pci_unregister_driver
(
&
hfcpci_driver
);
}
module_init
(
hisax_hfcpci_init
);
module_exit
(
hisax_hfcpci_exit
);
drivers/isdn/hisax/hisax_hfcpci.h
0 → 100644
View file @
a01be2d5
#include "hisax_if.h"
#include "hisax_isac.h"
#include <linux/pci.h>
struct
hfcpci_bcs
{
struct
hisax_b_if
b_if
;
struct
hfcpci_adapter
*
adapter
;
int
mode
;
int
channel
;
int
last_fcnt
;
struct
sk_buff
*
tx_skb
;
};
struct
hfcpci_adapter
{
struct
hisax_d_if
d_if
;
spinlock_t
hw_lock
;
unsigned
int
irq
;
void
*
mmio
;
u8
*
fifo
;
dma_addr_t
fifo_dma
;
struct
FsmInst
l1m
;
struct
FsmTimer
timer
;
struct
sk_buff
*
tx_skb
;
int
last_fcnt
;
u8
int_m1
,
int_m2
;
u8
fifo_en
;
u8
trm
;
u8
sctrl
,
sctrl_r
,
sctrl_e
;
u8
nt_mode
;
u8
ctmt
;
u8
mst_m
;
u8
conn
;
u8
bswapped
;
struct
hfcpci_bcs
bcs
[
2
];
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment