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
nexedi
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
Show 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