📄 baycom_epp.c
字号:
for (; cnt > 0; cnt--) crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; return (crc & 0xffff) == 0xf0b8;}/*---------------------------------------------------------------------------*/extern inline int calc_crc_ccitt(const unsigned char *buf, int cnt){ unsigned int crc = 0xffff; for (; cnt > 0; cnt--) crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; crc ^= 0xffff; return (crc & 0xffff);}/* ---------------------------------------------------------------------- */#define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800)/* --------------------------------------------------------------------- */static void inline 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 ((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. */char eppconfig_path[256] = "/sbin/eppfpga";static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };static int errno;static int exec_eppfpga(void *b){ struct baycom_state *bc = (struct baycom_state *)b; char modearg[256]; char portarg[16]; char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, NULL}; int i; /* set up arguments */ sprintf(modearg, "%sclk,%smodem,divider=%d%s,extstat", bc->cfg.intclk ? "int" : "ext", bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider, 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); for (i = 0; i < current->files->max_fds; i++ ) if (current->files->fd[i]) close(i); set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */ current->uid = current->euid = current->fsuid = 0; if (execve(eppconfig_path, argv, envp) < 0) { printk(KERN_ERR "%s: failed to exec %s -s -p %s -m %s, errno = %d\n", bc_drvname, eppconfig_path, portarg, modearg, errno); return -errno; } return 0;}/* eppconfig: called during ifconfig up to configure the modem */static int eppconfig(struct baycom_state *bc){ int i, pid, r; mm_segment_t fs; pid = kernel_thread(exec_eppfpga, bc, CLONE_FS); if (pid < 0) { printk(KERN_ERR "%s: fork failed, errno %d\n", bc_drvname, -pid); return pid; } fs = get_fs(); set_fs(KERNEL_DS); /* Allow i to be in kernel space. */ r = waitpid(pid, &i, __WCLONE); set_fs(fs); if (r != pid) { printk(KERN_ERR "%s: waitpid(%d) failed, returning %d\n", bc_drvname, pid, r); return -1; } printk(KERN_DEBUG "%s: eppfpga returned %d\n", bc_drvname, i); return i;}/* ---------------------------------------------------------------------- */static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs){}/* ---------------------------------------------------------------------- */static void inline do_kiss_params(struct baycom_state *bc, unsigned char *data, unsigned long len){#ifdef KISS_VERBOSE#define PKP(a,b) printk(KERN_INFO "%s: channel params: " a "\n", bc->ifname, 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}/* --------------------------------------------------------------------- *//* * high performance HDLC encoder * yes, it's ugly, but generates pretty good code */#define ENCODEITERA(j) \({ \ if (!(notbitstream & (0x1f0 << j))) \ goto stuff##j; \ encodeend##j: \})#define ENCODEITERB(j) \({ \ stuff##j: \ bitstream &= ~(0x100 << j); \ bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | \ ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); \ numbit++; \ notbitstream = ~bitstream; \ goto encodeend##j; \})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]; if (bc->hdlctx.bufcnt > 0) return; while ((skb = skb_dequeue(&bc->send_queue))) { if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); continue; } pkt_len = skb->len-1; /* strip KISS byte */ if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { dev_kfree_skb(skb); continue; } 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; ENCODEITERA(0); ENCODEITERA(1); ENCODEITERA(2); ENCODEITERA(3); ENCODEITERA(4); ENCODEITERA(5); ENCODEITERA(6); ENCODEITERA(7); goto enditer; ENCODEITERB(0); ENCODEITERB(1); ENCODEITERB(2); ENCODEITERB(3); ENCODEITERB(4); ENCODEITERB(5); ENCODEITERB(6); ENCODEITERB(7); enditer: 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++; return; }}/* ---------------------------------------------------------------------- */static unsigned short random_seed;static inline unsigned short random_num(void){ random_seed = 28629 * random_seed + 157; return random_seed;}/* ---------------------------------------------------------------------- */static void transmit(struct baycom_state *bc, int cnt, unsigned char stat){ struct parport *pp = bc->pdev->port; int i; if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT)) bc->hdlctx.state = tx_idle; if (bc->hdlctx.state == tx_idle && bc->hdlctx.calibrate <= 0) { if (bc->hdlctx.bufcnt <= 0) encode_hdlc(bc); if (bc->hdlctx.bufcnt <= 0) return; if (!bc->ch_params.fulldup) { if (!(stat & EPP_DCDBIT)) { bc->hdlctx.slotcnt = bc->ch_params.slottime; return; } if ((--bc->hdlctx.slotcnt) > 0) return; bc->hdlctx.slotcnt = bc->ch_params.slottime; if ((random_num() % 256) > bc->ch_params.ppersist) return; } } if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) { bc->hdlctx.state = tx_keyup; bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_delay); bc->ptt_keyed++; } while (cnt > 0) { switch (bc->hdlctx.state) { case tx_keyup: i = min(cnt, bc->hdlctx.flags); cnt -= i; bc->hdlctx.flags -= i; if (bc->hdlctx.flags <= 0) bc->hdlctx.state = tx_data; for (; i > 0; i--) parport_epp_write_data(pp, 0x7e); break; case tx_data: if (bc->hdlctx.bufcnt <= 0) { encode_hdlc(bc); if (bc->hdlctx.bufcnt <= 0) { bc->hdlctx.state = tx_tail; bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_tail); break; } } i = min(cnt, bc->hdlctx.bufcnt); bc->hdlctx.bufcnt -= i; cnt -= i; for (; i > 0; i--) parport_epp_write_data(pp, *(bc->hdlctx.bufptr)++); break; case tx_tail: encode_hdlc(bc); if (bc->hdlctx.bufcnt > 0) { bc->hdlctx.state = tx_data; break; } i = min(cnt, bc->hdlctx.flags); if (i) { cnt -= i; bc->hdlctx.flags -= i; for (; i > 0; i--) parport_epp_write_data(pp, 0x7e); break; } default: /* fall through */ if (bc->hdlctx.calibrate <= 0) return; i = min(cnt, bc->hdlctx.calibrate); cnt -= i; bc->hdlctx.calibrate -= i; for (; i > 0; i--) parport_epp_write_data(pp, 0); break; } }}/* ---------------------------------------------------------------------- */static void do_rxpacket(struct device *dev){ struct baycom_state *bc = (struct baycom_state *)dev->priv; struct sk_buff *skb; unsigned char *cp; unsigned pktlen; if (bc->hdlcrx.bufcnt < 4) return; if (!check_crc_ccitt(bc->hdlcrx.buf, bc->hdlcrx.bufcnt)) return; pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */ if (!(skb = dev_alloc_skb(pktlen))) { printk("%s: memory squeeze, dropping packet\n", bc->ifname); bc->stats.rx_dropped++; return; } skb->dev = dev; cp = skb_put(skb, pktlen); *cp++ = 0; /* KISS kludge */ memcpy(cp, bc->hdlcrx.buf, pktlen - 1); skb->protocol = htons(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); bc->stats.rx_packets++;}#define DECODEITERA(j) \({ \ if (!(notbitstream & (0x0fc << j))) /* flag or abort */ \ goto flgabrt##j; \ if ((bitstream & (0x1f8 << j)) == (0xf8 << j)) /* stuffed bit */ \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -