📄 hisax_isac.c
字号:
/* * Driver for ISAC-S and ISAC-SX * ISDN Subscriber Access Controller for Terminals * * Author Kai Germaschewski * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> * 2001 by Karsten Keil <keil@isdn4linux.de> * * based upon Karsten Keil's original isac.c driver * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * Thanks to Wizard Computersysteme GmbH, Bremervoerde and * SoHaNet Technology GmbH, Berlin * for supporting the development of this driver *//* TODO: * specifically handle level vs edge triggered? */#include <linux/module.h>#include <linux/init.h>#include <linux/netdevice.h>#include "hisax_isac.h"// debugging cruft#define __debug_variable debug#include "hisax_debug.h"#ifdef CONFIG_HISAX_DEBUGstatic int debug = 1;module_param(debug, int, 0);static char *ISACVer[] = { "2086/2186 V1.1", "2085 B1", "2085 B2", "2085 V2.3"};#endifMODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");MODULE_DESCRIPTION("ISAC/ISAC-SX driver");MODULE_LICENSE("GPL");#define DBG_WARN 0x0001#define DBG_IRQ 0x0002#define DBG_L1M 0x0004#define DBG_PR 0x0008#define DBG_RFIFO 0x0100#define DBG_RPACKET 0x0200#define DBG_XFIFO 0x1000#define DBG_XPACKET 0x2000// we need to distinguish ISAC-S and ISAC-SX#define TYPE_ISAC 0x00#define TYPE_ISACSX 0x01// registers etc.#define ISAC_MASK 0x20#define ISAC_ISTA 0x20#define ISAC_ISTA_EXI 0x01#define ISAC_ISTA_SIN 0x02#define ISAC_ISTA_CISQ 0x04#define ISAC_ISTA_XPR 0x10#define ISAC_ISTA_RSC 0x20#define ISAC_ISTA_RPF 0x40#define ISAC_ISTA_RME 0x80#define ISAC_STAR 0x21#define ISAC_CMDR 0x21#define ISAC_CMDR_XRES 0x01#define ISAC_CMDR_XME 0x02#define ISAC_CMDR_XTF 0x08#define ISAC_CMDR_RRES 0x40#define ISAC_CMDR_RMC 0x80#define ISAC_EXIR 0x24#define ISAC_EXIR_MOS 0x04#define ISAC_EXIR_XDU 0x40#define ISAC_EXIR_XMR 0x80#define ISAC_ADF2 0x39#define ISAC_SPCR 0x30#define ISAC_ADF1 0x38#define ISAC_CIR0 0x31#define ISAC_CIX0 0x31#define ISAC_CIR0_CIC0 0x02#define ISAC_CIR0_CIC1 0x01#define ISAC_CIR1 0x33#define ISAC_CIX1 0x33#define ISAC_STCR 0x37#define ISAC_MODE 0x22#define ISAC_RSTA 0x27#define ISAC_RSTA_RDO 0x40#define ISAC_RSTA_CRC 0x20#define ISAC_RSTA_RAB 0x10#define ISAC_RBCL 0x25#define ISAC_RBCH 0x2A#define ISAC_TIMR 0x23#define ISAC_SQXR 0x3b#define ISAC_MOSR 0x3a#define ISAC_MOCR 0x3a#define ISAC_MOR0 0x32#define ISAC_MOX0 0x32#define ISAC_MOR1 0x34#define ISAC_MOX1 0x34#define ISAC_RBCH_XAC 0x80#define ISAC_CMD_TIM 0x0#define ISAC_CMD_RES 0x1#define ISAC_CMD_SSP 0x2#define ISAC_CMD_SCP 0x3#define ISAC_CMD_AR8 0x8#define ISAC_CMD_AR10 0x9#define ISAC_CMD_ARL 0xa#define ISAC_CMD_DI 0xf#define ISACSX_MASK 0x60#define ISACSX_ISTA 0x60#define ISACSX_ISTA_ICD 0x01#define ISACSX_ISTA_CIC 0x10#define ISACSX_MASKD 0x20#define ISACSX_ISTAD 0x20#define ISACSX_ISTAD_XDU 0x04#define ISACSX_ISTAD_XMR 0x08#define ISACSX_ISTAD_XPR 0x10#define ISACSX_ISTAD_RFO 0x20#define ISACSX_ISTAD_RPF 0x40#define ISACSX_ISTAD_RME 0x80#define ISACSX_CMDRD 0x21#define ISACSX_CMDRD_XRES 0x01#define ISACSX_CMDRD_XME 0x02#define ISACSX_CMDRD_XTF 0x08#define ISACSX_CMDRD_RRES 0x40#define ISACSX_CMDRD_RMC 0x80#define ISACSX_MODED 0x22#define ISACSX_RBCLD 0x26#define ISACSX_RSTAD 0x28#define ISACSX_RSTAD_RAB 0x10#define ISACSX_RSTAD_CRC 0x20#define ISACSX_RSTAD_RDO 0x40#define ISACSX_RSTAD_VFR 0x80#define ISACSX_CIR0 0x2e#define ISACSX_CIR0_CIC0 0x08#define ISACSX_CIX0 0x2e#define ISACSX_TR_CONF0 0x30#define ISACSX_TR_CONF2 0x32static struct Fsm l1fsm;enum { ST_L1_RESET, ST_L1_F3_PDOWN, ST_L1_F3_PUP, ST_L1_F3_PEND_DEACT, ST_L1_F4, ST_L1_F5, ST_L1_F6, ST_L1_F7, ST_L1_F8,};#define L1_STATE_COUNT (ST_L1_F8+1)static char *strL1State[] ={ "ST_L1_RESET", "ST_L1_F3_PDOWN", "ST_L1_F3_PUP", "ST_L1_F3_PEND_DEACT", "ST_L1_F4", "ST_L1_F5", "ST_L1_F6", "ST_L1_F7", "ST_L1_F8",};enum { EV_PH_DR, // 0000 EV_PH_RES, // 0001 EV_PH_TMA, // 0010 EV_PH_SLD, // 0011 EV_PH_RSY, // 0100 EV_PH_DR6, // 0101 EV_PH_EI, // 0110 EV_PH_PU, // 0111 EV_PH_AR, // 1000 EV_PH_9, // 1001 EV_PH_ARL, // 1010 EV_PH_CVR, // 1011 EV_PH_AI8, // 1100 EV_PH_AI10, // 1101 EV_PH_AIL, // 1110 EV_PH_DC, // 1111 EV_PH_ACTIVATE_REQ, EV_PH_DEACTIVATE_REQ, EV_TIMER3,};#define L1_EVENT_COUNT (EV_TIMER3 + 1)static char *strL1Event[] ={ "EV_PH_DR", // 0000 "EV_PH_RES", // 0001 "EV_PH_TMA", // 0010 "EV_PH_SLD", // 0011 "EV_PH_RSY", // 0100 "EV_PH_DR6", // 0101 "EV_PH_EI", // 0110 "EV_PH_PU", // 0111 "EV_PH_AR", // 1000 "EV_PH_9", // 1001 "EV_PH_ARL", // 1010 "EV_PH_CVR", // 1011 "EV_PH_AI8", // 1100 "EV_PH_AI10", // 1101 "EV_PH_AIL", // 1110 "EV_PH_DC", // 1111 "EV_PH_ACTIVATE_REQ", "EV_PH_DEACTIVATE_REQ", "EV_TIMER3",};static inline void D_L1L2(struct isac *isac, int pr, void *arg){ struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if; DBG(DBG_PR, "pr %#x", pr); ifc->l1l2(ifc, pr, arg);}static void ph_command(struct isac *isac, unsigned int command){ DBG(DBG_L1M, "ph_command %#x", command); switch (isac->type) { case TYPE_ISAC: isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3); break; case TYPE_ISACSX: isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1)); break; }}// ----------------------------------------------------------------------static void l1_di(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmChangeState(fi, ST_L1_RESET); ph_command(isac, ISAC_CMD_DI);}static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmChangeState(fi, ST_L1_RESET); D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); ph_command(isac, ISAC_CMD_DI);}static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg){ FsmChangeState(fi, ST_L1_F3_PDOWN);}static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmChangeState(fi, ST_L1_F3_PEND_DEACT); D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); ph_command(isac, ISAC_CMD_DI);}static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmChangeState(fi, ST_L1_F3_PEND_DEACT); ph_command(isac, ISAC_CMD_DI);}static void l1_go_f4(struct FsmInst *fi, int event, void *arg){ FsmChangeState(fi, ST_L1_F4);}static void l1_go_f5(struct FsmInst *fi, int event, void *arg){ FsmChangeState(fi, ST_L1_F5);}static void l1_go_f6(struct FsmInst *fi, int event, void *arg){ FsmChangeState(fi, ST_L1_F6);}static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmChangeState(fi, ST_L1_F6); D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);}static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmDelTimer(&isac->timer, 0); FsmChangeState(fi, ST_L1_F7); ph_command(isac, ISAC_CMD_AR8); D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);}static void l1_go_f8(struct FsmInst *fi, int event, void *arg){ FsmChangeState(fi, ST_L1_F8);}static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmChangeState(fi, ST_L1_F8); D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);}static void l1_ar8(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); ph_command(isac, ISAC_CMD_AR8);}static void l1_timer3(struct FsmInst *fi, int event, void *arg){ struct isac *isac = fi->userdata; ph_command(isac, ISAC_CMD_DI); D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);}// state machines according to data sheet PSB 2186 / 3186static struct FsmNode L1FnList[] __initdata ={ {ST_L1_RESET, EV_PH_RES, l1_di}, {ST_L1_RESET, EV_PH_EI, l1_di}, {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown}, {ST_L1_RESET, EV_PH_AR, l1_go_f6}, {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F3_PDOWN, EV_PH_RES, l1_di}, {ST_L1_F3_PDOWN, EV_PH_EI, l1_di}, {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6}, {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5}, {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4}, {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8}, {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3}, {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di}, {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di}, {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown}, {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5}, {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6}, {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F4, EV_PH_RES, l1_di}, {ST_L1_F4, EV_PH_EI, l1_di}, {ST_L1_F4, EV_PH_RSY, l1_go_f5}, {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F4, EV_TIMER3, l1_timer3}, {ST_L1_F4, EV_PH_DC, l1_go_f3pdown}, {ST_L1_F5, EV_PH_RES, l1_di}, {ST_L1_F5, EV_PH_EI, l1_di}, {ST_L1_F5, EV_PH_AR, l1_go_f6}, {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F5, EV_TIMER3, l1_timer3}, {ST_L1_F5, EV_PH_DR, l1_go_f3pend}, {ST_L1_F5, EV_PH_DC, l1_go_f3pdown}, {ST_L1_F6, EV_PH_RES, l1_di}, {ST_L1_F6, EV_PH_EI, l1_di}, {ST_L1_F6, EV_PH_RSY, l1_go_f8}, {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F6, EV_PH_DR6, l1_go_f3pend}, {ST_L1_F6, EV_TIMER3, l1_timer3}, {ST_L1_F6, EV_PH_DC, l1_go_f3pdown}, {ST_L1_F7, EV_PH_RES, l1_di_deact_ind}, {ST_L1_F7, EV_PH_EI, l1_di_deact_ind}, {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind}, {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind}, {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind}, {ST_L1_F8, EV_PH_RES, l1_di}, {ST_L1_F8, EV_PH_EI, l1_di}, {ST_L1_F8, EV_PH_AR, l1_go_f6}, {ST_L1_F8, EV_PH_DR, l1_go_f3pend}, {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind}, {ST_L1_F8, EV_TIMER3, l1_timer3}, {ST_L1_F8, EV_PH_DC, l1_go_f3pdown},};static void l1m_debug(struct FsmInst *fi, char *fmt, ...){ va_list args; char buf[256]; va_start(args, fmt); vsprintf(buf, fmt, args); DBG(DBG_L1M, "%s", buf); va_end(args);}static void isac_version(struct isac *cs){ int val; val = cs->read_isac(cs, ISAC_RBCH); DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);}static void isac_empty_fifo(struct isac *isac, int count)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -