⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 baycom_par.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *	baycom_par.c  -- baycom par96 and picpar radio modem driver. * *	Copyright (C) 1996-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. * * *  Supported modems * *  par96:  This is a modem for 9600 baud FSK compatible to the G3RUH standard. *          The modem does all the filtering and regenerates the receiver clock. *          Data is transferred from and to the PC via a shift register. *          The shift register is filled with 16 bits and an interrupt is *          signalled. The PC then empties the shift register in a burst. This *          modem connects to the parallel port, hence the name. The modem *          leaves the implementation of the HDLC protocol and the scrambler *          polynomial to the PC. This modem is no longer available (at least *          from Baycom) and has been replaced by the PICPAR modem (see below). *          You may however still build one from the schematics published in *          cq-DL :-). * *  picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The *          modem is protocol compatible to par96, but uses only three low *          power ICs and can therefore be fed from the parallel port and *          does not require an additional power supply. It features *          built in DCD circuitry. The driver should therefore be configured *          for hardware DCD. * * *  Command line options (insmod command line) * *  mode     driver mode string. Valid choices are par96 and picpar. *  iobase   base address of the port; common values are 0x378, 0x278, 0x3bc * * *  History: *   0.1  26.06.1996  Adapted from baycom.c and made network driver interface *        18.10.1996  Changed to new user space access routines (copy_{to,from}_user) *   0.3  26.04.1997  init code/data tagged *   0.4  08.07.1997  alternative ser12 decoding algorithm (uses delta CTS ints) *   0.5  11.11.1997  split into separate files for ser12/par96 *   0.6  03.08.1999  adapt to Linus' new __setup/__initcall *                    removed some pre-2.2 kernel compatibility cruft *   0.7  10.08.1999  Check if parport can do SPP and is safe to access during interrupt contexts *   0.8  12.02.2000  adapted to softnet driver interface *                    removed direct parport access, uses parport driver methods *   0.9  03.07.2000  fix interface name handling *//*****************************************************************************/#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/string.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/hdlcdrv.h>#include <linux/baycom.h>#include <linux/parport.h>/* --------------------------------------------------------------------- */#define BAYCOM_DEBUG/* * modem options; bit mask */#define BAYCOM_OPTIONS_SOFTDCD  1/* --------------------------------------------------------------------- */static const char bc_drvname[] = "baycom_par";static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"KERN_INFO "baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n";/* --------------------------------------------------------------------- */#define NR_PORTS 4static struct net_device baycom_device[NR_PORTS];/* --------------------------------------------------------------------- */#define PAR96_BURSTBITS 16#define PAR96_BURST     4#define PAR96_PTT       2#define PAR96_TXBIT     1#define PAR96_ACK       0x40#define PAR96_RXBIT     0x20#define PAR96_DCD       0x10#define PAR97_POWER     0xf8/* ---------------------------------------------------------------------- *//* * Information that need to be kept for each board. */struct baycom_state {	struct hdlcdrv_state hdrv;	struct pardevice *pdev;	unsigned int options;	struct modem_state {		short arb_divider;		unsigned char flags;		unsigned int shreg;		struct modem_state_par96 {			int dcd_count;			unsigned int dcd_shreg;			unsigned long descram;			unsigned long scram;		} par96;	} modem;#ifdef BAYCOM_DEBUG	struct debug_vals {		unsigned long last_jiffies;		unsigned cur_intcnt;		unsigned last_intcnt;		int cur_pllcorr;		int last_pllcorr;	} debug_vals;#endif /* BAYCOM_DEBUG */};/* --------------------------------------------------------------------- */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 */}/* --------------------------------------------------------------------- *//* * ===================== PAR96 specific routines ========================= */#define PAR96_DESCRAM_TAP1 0x20000#define PAR96_DESCRAM_TAP2 0x01000#define PAR96_DESCRAM_TAP3 0x00001#define PAR96_DESCRAM_TAPSH1 17#define PAR96_DESCRAM_TAPSH2 12#define PAR96_DESCRAM_TAPSH3 0#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 *//* --------------------------------------------------------------------- */static __inline__ void par96_tx(struct net_device *dev, struct baycom_state *bc){	int i;	unsigned int data = hdlcdrv_getbits(&bc->hdrv);	struct parport *pp = bc->pdev->port;	for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) {		unsigned char val = PAR97_POWER;		bc->modem.par96.scram = ((bc->modem.par96.scram << 1) |					 (bc->modem.par96.scram & 1));		if (!(data & 1))			bc->modem.par96.scram ^= 1;		if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1))			bc->modem.par96.scram ^=				(PAR96_SCRAM_TAPN << 1);		if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2))			val |= PAR96_TXBIT;		pp->ops->write_data(pp, val);		pp->ops->write_data(pp, val | PAR96_BURST);	}}/* --------------------------------------------------------------------- */static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc){	int i;	unsigned int data, mask, mask2, descx;	struct parport *pp = bc->pdev->port;	/*	 * do receiver; differential decode and descramble on the fly	 */	for(data = i = 0; i < PAR96_BURSTBITS; i++) {		bc->modem.par96.descram = (bc->modem.par96.descram << 1);		if (pp->ops->read_status(pp) & PAR96_RXBIT)			bc->modem.par96.descram |= 1;		descx = bc->modem.par96.descram ^			(bc->modem.par96.descram >> 1);		/* now the diff decoded data is inverted in descram */		pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT);		descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^			  (descx >> PAR96_DESCRAM_TAPSH2));		data >>= 1;		if (!(descx & 1))			data |= 0x8000;		pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT | PAR96_BURST);	}	hdlcdrv_putbits(&bc->hdrv, data);	/*	 * do DCD algorithm	 */	if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {		bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16)			| (data << 16);		/* search for flags and set the dcd counter appropriately */		for(mask = 0x1fe00, mask2 = 0xfc00, i = 0;		    i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)			if ((bc->modem.par96.dcd_shreg & mask) == mask2)				bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4;		/* check for abort/noise sequences */		for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0;		    i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)			if (((bc->modem.par96.dcd_shreg & mask) == mask2) &&			    (bc->modem.par96.dcd_count >= 0))				bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10;		/* decrement and set the dcd variable */		if (bc->modem.par96.dcd_count >= 0)			bc->modem.par96.dcd_count -= 2;		hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0);	} else {		hdlcdrv_setdcd(&bc->hdrv, !!(pp->ops->read_status(pp) & PAR96_DCD));	}}/* --------------------------------------------------------------------- */static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *)dev_id;	struct baycom_state *bc = (struct baycom_state *)dev->priv;	if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)		return;	baycom_int_freq(bc);	/*	 * check if transmitter active	 */	if (hdlcdrv_ptt(&bc->hdrv))		par96_tx(dev, bc);	else {		par96_rx(dev, bc);		if (--bc->modem.arb_divider <= 0) {			bc->modem.arb_divider = 6;			__sti();			hdlcdrv_arbitrate(dev, &bc->hdrv);		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -