📄 baycom_epp.c
字号:
/*****************************************************************************//* * baycom_epp.c -- baycom epp radio modem driver. * * Copyright (C) 1998-2000 * Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Please note that the GPL allows you to use the driver, NOT the radio. * In order to use the radio, you need a license from the communications * authority of your country. * * * History: * 0.1 xx.xx.1998 Initial version by Matthias Welwarsky (dg2fef) * 0.2 21.04.1998 Massive rework by Thomas Sailer * Integrated FPGA EPP modem configuration routines * 0.3 11.05.1998 Took FPGA config out and moved it into a separate program * 0.4 26.07.1999 Adapted to new lowlevel parport driver interface * 0.5 03.08.1999 adapt to Linus' new __setup/__initcall * removed some pre-2.2 kernel compatibility cruft * 0.6 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts * 0.7 12.02.2000 adapted to softnet driver interface * *//*****************************************************************************/#include <linux/crc-ccitt.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/string.h>#include <linux/workqueue.h>#include <linux/fs.h>#include <linux/parport.h>#include <linux/if_arp.h>#include <linux/hdlcdrv.h>#include <linux/baycom.h>#include <linux/jiffies.h>#include <net/ax25.h> #include <asm/uaccess.h>/* --------------------------------------------------------------------- */#define BAYCOM_DEBUG#define BAYCOM_MAGIC 19730510/* --------------------------------------------------------------------- */static const char paranoia_str[] = KERN_ERR "baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n";static const char bc_drvname[] = "baycom_epp";static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"KERN_INFO "baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";/* --------------------------------------------------------------------- */#define NR_PORTS 4static struct net_device *baycom_device[NR_PORTS];/* --------------------------------------------------------------------- *//* EPP status register */#define EPP_DCDBIT 0x80#define EPP_PTTBIT 0x08#define EPP_NREF 0x01#define EPP_NRAEF 0x02#define EPP_NRHF 0x04#define EPP_NTHF 0x20#define EPP_NTAEF 0x10#define EPP_NTEF EPP_PTTBIT/* EPP control register */#define EPP_TX_FIFO_ENABLE 0x10#define EPP_RX_FIFO_ENABLE 0x08#define EPP_MODEM_ENABLE 0x20#define EPP_LEDS 0xC0#define EPP_IRQ_ENABLE 0x10/* LPT registers */#define LPTREG_ECONTROL 0x402#define LPTREG_CONFIGB 0x401#define LPTREG_CONFIGA 0x400#define LPTREG_EPPDATA 0x004#define LPTREG_EPPADDR 0x003#define LPTREG_CONTROL 0x002#define LPTREG_STATUS 0x001#define LPTREG_DATA 0x000/* LPT control register */#define LPTCTRL_PROGRAM 0x04 /* 0 to reprogram */#define LPTCTRL_WRITE 0x01#define LPTCTRL_ADDRSTB 0x08#define LPTCTRL_DATASTB 0x02#define LPTCTRL_INTEN 0x10/* LPT status register */#define LPTSTAT_SHIFT_NINTR 6#define LPTSTAT_WAIT 0x80#define LPTSTAT_NINTR (1<<LPTSTAT_SHIFT_NINTR)#define LPTSTAT_PE 0x20#define LPTSTAT_DONE 0x10#define LPTSTAT_NERROR 0x08#define LPTSTAT_EPPTIMEOUT 0x01/* LPT data register */#define LPTDATA_SHIFT_TDI 0#define LPTDATA_SHIFT_TMS 2#define LPTDATA_TDI (1<<LPTDATA_SHIFT_TDI)#define LPTDATA_TCK 0x02#define LPTDATA_TMS (1<<LPTDATA_SHIFT_TMS)#define LPTDATA_INITBIAS 0x80/* EPP modem config/status bits */#define EPP_DCDBIT 0x80#define EPP_PTTBIT 0x08#define EPP_RXEBIT 0x01#define EPP_RXAEBIT 0x02#define EPP_RXHFULL 0x04#define EPP_NTHF 0x20#define EPP_NTAEF 0x10#define EPP_NTEF EPP_PTTBIT#define EPP_TX_FIFO_ENABLE 0x10#define EPP_RX_FIFO_ENABLE 0x08#define EPP_MODEM_ENABLE 0x20#define EPP_LEDS 0xC0#define EPP_IRQ_ENABLE 0x10/* Xilinx 4k JTAG instructions */#define XC4K_IRLENGTH 3#define XC4K_EXTEST 0#define XC4K_PRELOAD 1#define XC4K_CONFIGURE 5#define XC4K_BYPASS 7#define EPP_CONVENTIONAL 0#define EPP_FPGA 1#define EPP_FPGAEXTSTATUS 2#define TXBUFFER_SIZE ((HDLCDRV_MAXFLEN*6/5)+8)/* ---------------------------------------------------------------------- *//* * Information that need to be kept for each board. */struct baycom_state { int magic; struct pardevice *pdev; unsigned int work_running; struct work_struct run_work; unsigned int modem; unsigned int bitrate; unsigned char stat; struct { unsigned int intclk; unsigned int fclk; unsigned int bps; unsigned int extmodem; unsigned int loopback; } cfg; struct hdlcdrv_channel_params ch_params; struct { unsigned int bitbuf, bitstream, numbits, state; unsigned char *bufptr; int bufcnt; unsigned char buf[TXBUFFER_SIZE]; } hdlcrx; struct { int calibrate; int slotcnt; int flags; enum { tx_idle = 0, tx_keyup, tx_data, tx_tail } state; unsigned char *bufptr; int bufcnt; unsigned char buf[TXBUFFER_SIZE]; } hdlctx; struct net_device_stats stats; unsigned int ptt_keyed; struct sk_buff *skb; /* next transmit packet */#ifdef BAYCOM_DEBUG struct debug_vals { unsigned long last_jiffies; unsigned cur_intcnt; unsigned last_intcnt; int cur_pllcorr; int last_pllcorr; unsigned int mod_cycles; unsigned int demod_cycles; } debug_vals;#endif /* BAYCOM_DEBUG */};/* --------------------------------------------------------------------- */#define KISS_VERBOSE/* --------------------------------------------------------------------- */#define PARAM_TXDELAY 1#define PARAM_PERSIST 2#define PARAM_SLOTTIME 3#define PARAM_TXTAIL 4#define PARAM_FULLDUP 5#define PARAM_HARDWARE 6#define PARAM_RETURN 255/* --------------------------------------------------------------------- *//* * the CRC routines are stolen from WAMPES * by Dieter Deyke *//*---------------------------------------------------------------------------*/#if 0static inline void append_crc_ccitt(unsigned char *buffer, int len){ unsigned int crc = 0xffff; for (;len>0;len--) crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff]; crc ^= 0xffff; *buffer++ = crc; *buffer++ = crc >> 8;}#endif/*---------------------------------------------------------------------------*/static inline int check_crc_ccitt(const unsigned char *buf, int cnt){ return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8;}/*---------------------------------------------------------------------------*/static inline int calc_crc_ccitt(const unsigned char *buf, int cnt){ return (crc_ccitt(0xffff, buf, cnt) ^ 0xffff) & 0xffff;}/* ---------------------------------------------------------------------- */#define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800)/* --------------------------------------------------------------------- */static inline void baycom_int_freq(struct baycom_state *bc){#ifdef BAYCOM_DEBUG unsigned long cur_jiffies = jiffies; /* * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; bc->debug_vals.cur_pllcorr = 0; }#endif /* BAYCOM_DEBUG */}/* ---------------------------------------------------------------------- *//* * eppconfig_path should be setable via /proc/sys. */static char eppconfig_path[256] = "/usr/sbin/eppfpga";static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };/* eppconfig: called during ifconfig up to configure the modem */static int eppconfig(struct baycom_state *bc){ char modearg[256]; char portarg[16]; char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, NULL }; /* set up arguments */ sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", bc->cfg.intclk ? "int" : "ext", bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, (bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps), bc->cfg.loopback ? ",loopback" : ""); sprintf(portarg, "%ld", bc->pdev->port->base); printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); return call_usermodehelper(eppconfig_path, argv, envp, 1);}/* ---------------------------------------------------------------------- */static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs){}/* ---------------------------------------------------------------------- */static inline void do_kiss_params(struct baycom_state *bc, unsigned char *data, unsigned long len){#ifdef KISS_VERBOSE#define PKP(a,b) printk(KERN_INFO "baycomm_epp: channel params: " a "\n", b)#else /* KISS_VERBOSE */ #define PKP(a,b) #endif /* KISS_VERBOSE */ if (len < 2) return; switch(data[0]) { case PARAM_TXDELAY: bc->ch_params.tx_delay = data[1]; PKP("TX delay = %ums", 10 * bc->ch_params.tx_delay); break; case PARAM_PERSIST: bc->ch_params.ppersist = data[1]; PKP("p persistence = %u", bc->ch_params.ppersist); break; case PARAM_SLOTTIME: bc->ch_params.slottime = data[1]; PKP("slot time = %ums", bc->ch_params.slottime); break; case PARAM_TXTAIL: bc->ch_params.tx_tail = data[1]; PKP("TX tail = %ums", bc->ch_params.tx_tail); break; case PARAM_FULLDUP: bc->ch_params.fulldup = !!data[1]; PKP("%s duplex", bc->ch_params.fulldup ? "full" : "half"); break; default: break; }#undef PKP}/* --------------------------------------------------------------------- */static void encode_hdlc(struct baycom_state *bc){ struct sk_buff *skb; unsigned char *wp, *bp; int pkt_len; unsigned bitstream, notbitstream, bitbuf, numbit, crc; unsigned char crcarr[2]; int j; if (bc->hdlctx.bufcnt > 0) return; skb = bc->skb; if (!skb) return; bc->skb = NULL; pkt_len = skb->len-1; /* strip KISS byte */ wp = bc->hdlctx.buf; bp = skb->data+1; crc = calc_crc_ccitt(bp, pkt_len); crcarr[0] = crc; crcarr[1] = crc >> 8; *wp++ = 0x7e; bitstream = bitbuf = numbit = 0; while (pkt_len > -2) { bitstream >>= 8; bitstream |= ((unsigned int)*bp) << 8; bitbuf |= ((unsigned int)*bp) << numbit; notbitstream = ~bitstream; bp++; pkt_len--; if (!pkt_len) bp = crcarr; for (j = 0; j < 8; j++) if (unlikely(!(notbitstream & (0x1f0 << j)))) { bitstream &= ~(0x100 << j); bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); numbit++; notbitstream = ~bitstream; } numbit += 8; while (numbit >= 8) { *wp++ = bitbuf; bitbuf >>= 8; numbit -= 8; } } bitbuf |= 0x7e7e << numbit; numbit += 16; while (numbit >= 8) { *wp++ = bitbuf; bitbuf >>= 8; numbit -= 8; } bc->hdlctx.bufptr = bc->hdlctx.buf; bc->hdlctx.bufcnt = wp - bc->hdlctx.buf; dev_kfree_skb(skb); bc->stats.tx_packets++;}/* ---------------------------------------------------------------------- */static unsigned short random_seed;static inline unsigned short random_num(void){ random_seed = 28629 * random_seed + 157;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -