| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /*****************************************************************************/ | 
 | 2 |  | 
 | 3 | /* | 
 | 4 |  *	baycom_epp.c  -- baycom epp radio modem driver. | 
 | 5 |  * | 
 | 6 |  *	Copyright (C) 1998-2000 | 
 | 7 |  *          Thomas Sailer (sailer@ife.ee.ethz.ch) | 
 | 8 |  * | 
 | 9 |  *	This program is free software; you can redistribute it and/or modify | 
 | 10 |  *	it under the terms of the GNU General Public License as published by | 
 | 11 |  *	the Free Software Foundation; either version 2 of the License, or | 
 | 12 |  *	(at your option) any later version. | 
 | 13 |  * | 
 | 14 |  *	This program is distributed in the hope that it will be useful, | 
 | 15 |  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 16 |  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 17 |  *	GNU General Public License for more details. | 
 | 18 |  * | 
 | 19 |  *	You should have received a copy of the GNU General Public License | 
 | 20 |  *	along with this program; if not, write to the Free Software | 
 | 21 |  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
 | 22 |  * | 
 | 23 |  *  Please note that the GPL allows you to use the driver, NOT the radio. | 
 | 24 |  *  In order to use the radio, you need a license from the communications | 
 | 25 |  *  authority of your country. | 
 | 26 |  * | 
 | 27 |  * | 
 | 28 |  *  History: | 
 | 29 |  *   0.1  xx.xx.1998  Initial version by Matthias Welwarsky (dg2fef) | 
 | 30 |  *   0.2  21.04.1998  Massive rework by Thomas Sailer | 
 | 31 |  *                    Integrated FPGA EPP modem configuration routines | 
 | 32 |  *   0.3  11.05.1998  Took FPGA config out and moved it into a separate program | 
 | 33 |  *   0.4  26.07.1999  Adapted to new lowlevel parport driver interface | 
 | 34 |  *   0.5  03.08.1999  adapt to Linus' new __setup/__initcall | 
 | 35 |  *                    removed some pre-2.2 kernel compatibility cruft | 
 | 36 |  *   0.6  10.08.1999  Check if parport can do SPP and is safe to access during interrupt contexts | 
 | 37 |  *   0.7  12.02.2000  adapted to softnet driver interface | 
 | 38 |  * | 
 | 39 |  */ | 
 | 40 |  | 
 | 41 | /*****************************************************************************/ | 
 | 42 |  | 
| Ralf Baechle | c4bc7ee | 2005-09-12 14:19:26 -0700 | [diff] [blame] | 43 | #include <linux/crc-ccitt.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | #include <linux/module.h> | 
 | 45 | #include <linux/kernel.h> | 
 | 46 | #include <linux/init.h> | 
 | 47 | #include <linux/string.h> | 
 | 48 | #include <linux/workqueue.h> | 
 | 49 | #include <linux/fs.h> | 
 | 50 | #include <linux/parport.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | #include <linux/if_arp.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | #include <linux/hdlcdrv.h> | 
 | 53 | #include <linux/baycom.h> | 
| Marcelo Feitoza Parisi | cd8749b | 2005-07-15 11:16:42 +0100 | [diff] [blame] | 54 | #include <linux/jiffies.h> | 
| Ralf Baechle | 8b5b467 | 2007-02-16 11:55:33 +0000 | [diff] [blame] | 55 | #include <linux/random.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | #include <net/ax25.h>  | 
| Ralf Baechle | c4bc7ee | 2005-09-12 14:19:26 -0700 | [diff] [blame] | 57 | #include <asm/uaccess.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 |  | 
 | 59 | /* --------------------------------------------------------------------- */ | 
 | 60 |  | 
 | 61 | #define BAYCOM_DEBUG | 
 | 62 | #define BAYCOM_MAGIC 19730510 | 
 | 63 |  | 
 | 64 | /* --------------------------------------------------------------------- */ | 
 | 65 |  | 
 | 66 | static const char paranoia_str[] = KERN_ERR  | 
 | 67 | 	"baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n"; | 
 | 68 |  | 
 | 69 | static const char bc_drvname[] = "baycom_epp"; | 
 | 70 | static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n" | 
 | 71 | KERN_INFO "baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n"; | 
 | 72 |  | 
 | 73 | /* --------------------------------------------------------------------- */ | 
 | 74 |  | 
 | 75 | #define NR_PORTS 4 | 
 | 76 |  | 
 | 77 | static struct net_device *baycom_device[NR_PORTS]; | 
 | 78 |  | 
 | 79 | /* --------------------------------------------------------------------- */ | 
 | 80 |  | 
 | 81 | /* EPP status register */ | 
 | 82 | #define EPP_DCDBIT      0x80 | 
 | 83 | #define EPP_PTTBIT      0x08 | 
 | 84 | #define EPP_NREF        0x01 | 
 | 85 | #define EPP_NRAEF       0x02 | 
 | 86 | #define EPP_NRHF        0x04 | 
 | 87 | #define EPP_NTHF        0x20 | 
 | 88 | #define EPP_NTAEF       0x10 | 
 | 89 | #define EPP_NTEF        EPP_PTTBIT | 
 | 90 |  | 
 | 91 | /* EPP control register */ | 
 | 92 | #define EPP_TX_FIFO_ENABLE 0x10 | 
 | 93 | #define EPP_RX_FIFO_ENABLE 0x08 | 
 | 94 | #define EPP_MODEM_ENABLE   0x20 | 
 | 95 | #define EPP_LEDS           0xC0 | 
 | 96 | #define EPP_IRQ_ENABLE     0x10 | 
 | 97 |  | 
 | 98 | /* LPT registers */ | 
 | 99 | #define LPTREG_ECONTROL       0x402 | 
 | 100 | #define LPTREG_CONFIGB        0x401 | 
 | 101 | #define LPTREG_CONFIGA        0x400 | 
 | 102 | #define LPTREG_EPPDATA        0x004 | 
 | 103 | #define LPTREG_EPPADDR        0x003 | 
 | 104 | #define LPTREG_CONTROL        0x002 | 
 | 105 | #define LPTREG_STATUS         0x001 | 
 | 106 | #define LPTREG_DATA           0x000 | 
 | 107 |  | 
 | 108 | /* LPT control register */ | 
 | 109 | #define LPTCTRL_PROGRAM       0x04   /* 0 to reprogram */ | 
 | 110 | #define LPTCTRL_WRITE         0x01 | 
 | 111 | #define LPTCTRL_ADDRSTB       0x08 | 
 | 112 | #define LPTCTRL_DATASTB       0x02 | 
 | 113 | #define LPTCTRL_INTEN         0x10 | 
 | 114 |  | 
 | 115 | /* LPT status register */ | 
 | 116 | #define LPTSTAT_SHIFT_NINTR   6 | 
 | 117 | #define LPTSTAT_WAIT          0x80 | 
 | 118 | #define LPTSTAT_NINTR         (1<<LPTSTAT_SHIFT_NINTR) | 
 | 119 | #define LPTSTAT_PE            0x20 | 
 | 120 | #define LPTSTAT_DONE          0x10 | 
 | 121 | #define LPTSTAT_NERROR        0x08 | 
 | 122 | #define LPTSTAT_EPPTIMEOUT    0x01 | 
 | 123 |  | 
 | 124 | /* LPT data register */ | 
 | 125 | #define LPTDATA_SHIFT_TDI     0 | 
 | 126 | #define LPTDATA_SHIFT_TMS     2 | 
 | 127 | #define LPTDATA_TDI           (1<<LPTDATA_SHIFT_TDI) | 
 | 128 | #define LPTDATA_TCK           0x02 | 
 | 129 | #define LPTDATA_TMS           (1<<LPTDATA_SHIFT_TMS) | 
 | 130 | #define LPTDATA_INITBIAS      0x80 | 
 | 131 |  | 
 | 132 |  | 
 | 133 | /* EPP modem config/status bits */ | 
 | 134 | #define EPP_DCDBIT            0x80 | 
 | 135 | #define EPP_PTTBIT            0x08 | 
 | 136 | #define EPP_RXEBIT            0x01 | 
 | 137 | #define EPP_RXAEBIT           0x02 | 
 | 138 | #define EPP_RXHFULL           0x04 | 
 | 139 |  | 
 | 140 | #define EPP_NTHF              0x20 | 
 | 141 | #define EPP_NTAEF             0x10 | 
 | 142 | #define EPP_NTEF              EPP_PTTBIT | 
 | 143 |  | 
 | 144 | #define EPP_TX_FIFO_ENABLE    0x10 | 
 | 145 | #define EPP_RX_FIFO_ENABLE    0x08 | 
 | 146 | #define EPP_MODEM_ENABLE      0x20 | 
 | 147 | #define EPP_LEDS              0xC0 | 
 | 148 | #define EPP_IRQ_ENABLE        0x10 | 
 | 149 |  | 
 | 150 | /* Xilinx 4k JTAG instructions */ | 
 | 151 | #define XC4K_IRLENGTH   3 | 
 | 152 | #define XC4K_EXTEST     0 | 
 | 153 | #define XC4K_PRELOAD    1 | 
 | 154 | #define XC4K_CONFIGURE  5 | 
 | 155 | #define XC4K_BYPASS     7 | 
 | 156 |  | 
 | 157 | #define EPP_CONVENTIONAL  0 | 
 | 158 | #define EPP_FPGA          1 | 
 | 159 | #define EPP_FPGAEXTSTATUS 2 | 
 | 160 |  | 
 | 161 | #define TXBUFFER_SIZE     ((HDLCDRV_MAXFLEN*6/5)+8) | 
 | 162 |  | 
 | 163 | /* ---------------------------------------------------------------------- */ | 
 | 164 | /* | 
 | 165 |  * Information that need to be kept for each board. | 
 | 166 |  */ | 
 | 167 |  | 
 | 168 | struct baycom_state { | 
 | 169 | 	int magic; | 
 | 170 |  | 
 | 171 |         struct pardevice *pdev; | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 172 | 	struct net_device *dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | 	unsigned int work_running; | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 174 | 	struct delayed_work run_work; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 | 	unsigned int modem; | 
 | 176 | 	unsigned int bitrate; | 
 | 177 | 	unsigned char stat; | 
 | 178 |  | 
 | 179 | 	struct { | 
 | 180 | 		unsigned int intclk; | 
 | 181 | 		unsigned int fclk; | 
 | 182 | 		unsigned int bps; | 
 | 183 | 		unsigned int extmodem; | 
 | 184 | 		unsigned int loopback; | 
 | 185 | 	} cfg; | 
 | 186 |  | 
 | 187 |         struct hdlcdrv_channel_params ch_params; | 
 | 188 |  | 
 | 189 |         struct { | 
 | 190 | 		unsigned int bitbuf, bitstream, numbits, state; | 
 | 191 | 		unsigned char *bufptr; | 
 | 192 | 		int bufcnt; | 
 | 193 | 		unsigned char buf[TXBUFFER_SIZE]; | 
 | 194 |         } hdlcrx; | 
 | 195 |  | 
 | 196 |         struct { | 
 | 197 | 		int calibrate; | 
 | 198 |                 int slotcnt; | 
 | 199 | 		int flags; | 
 | 200 | 		enum { tx_idle = 0, tx_keyup, tx_data, tx_tail } state; | 
 | 201 | 		unsigned char *bufptr; | 
 | 202 | 		int bufcnt; | 
 | 203 | 		unsigned char buf[TXBUFFER_SIZE]; | 
 | 204 |         } hdlctx; | 
 | 205 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | 	unsigned int ptt_keyed; | 
 | 207 | 	struct sk_buff *skb;  /* next transmit packet  */ | 
 | 208 |  | 
 | 209 | #ifdef BAYCOM_DEBUG | 
 | 210 | 	struct debug_vals { | 
 | 211 | 		unsigned long last_jiffies; | 
 | 212 | 		unsigned cur_intcnt; | 
 | 213 | 		unsigned last_intcnt; | 
 | 214 | 		int cur_pllcorr; | 
 | 215 | 		int last_pllcorr; | 
 | 216 | 		unsigned int mod_cycles; | 
 | 217 | 		unsigned int demod_cycles; | 
 | 218 | 	} debug_vals; | 
 | 219 | #endif /* BAYCOM_DEBUG */ | 
 | 220 | }; | 
 | 221 |  | 
 | 222 | /* --------------------------------------------------------------------- */ | 
 | 223 |  | 
 | 224 | #define KISS_VERBOSE | 
 | 225 |  | 
 | 226 | /* --------------------------------------------------------------------- */ | 
 | 227 |  | 
 | 228 | #define PARAM_TXDELAY   1 | 
 | 229 | #define PARAM_PERSIST   2 | 
 | 230 | #define PARAM_SLOTTIME  3 | 
 | 231 | #define PARAM_TXTAIL    4 | 
 | 232 | #define PARAM_FULLDUP   5 | 
 | 233 | #define PARAM_HARDWARE  6 | 
 | 234 | #define PARAM_RETURN    255 | 
 | 235 |  | 
 | 236 | /* --------------------------------------------------------------------- */ | 
 | 237 | /* | 
 | 238 |  * the CRC routines are stolen from WAMPES | 
 | 239 |  * by Dieter Deyke | 
 | 240 |  */ | 
 | 241 |  | 
 | 242 |  | 
 | 243 | /*---------------------------------------------------------------------------*/ | 
 | 244 |  | 
 | 245 | #if 0 | 
 | 246 | static inline void append_crc_ccitt(unsigned char *buffer, int len) | 
 | 247 | { | 
 | 248 |  	unsigned int crc = 0xffff; | 
 | 249 |  | 
 | 250 | 	for (;len>0;len--) | 
 | 251 | 		crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff]; | 
 | 252 | 	crc ^= 0xffff; | 
 | 253 | 	*buffer++ = crc; | 
 | 254 | 	*buffer++ = crc >> 8; | 
 | 255 | } | 
 | 256 | #endif | 
 | 257 |  | 
 | 258 | /*---------------------------------------------------------------------------*/ | 
 | 259 |  | 
 | 260 | static inline int check_crc_ccitt(const unsigned char *buf, int cnt) | 
 | 261 | { | 
 | 262 | 	return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8; | 
 | 263 | } | 
 | 264 |  | 
 | 265 | /*---------------------------------------------------------------------------*/ | 
 | 266 |  | 
 | 267 | static inline int calc_crc_ccitt(const unsigned char *buf, int cnt) | 
 | 268 | { | 
 | 269 | 	return (crc_ccitt(0xffff, buf, cnt) ^ 0xffff) & 0xffff; | 
 | 270 | } | 
 | 271 |  | 
 | 272 | /* ---------------------------------------------------------------------- */ | 
 | 273 |  | 
 | 274 | #define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800) | 
 | 275 |  | 
 | 276 | /* --------------------------------------------------------------------- */ | 
 | 277 |  | 
 | 278 | static inline void baycom_int_freq(struct baycom_state *bc) | 
 | 279 | { | 
 | 280 | #ifdef BAYCOM_DEBUG | 
 | 281 | 	unsigned long cur_jiffies = jiffies; | 
 | 282 | 	/* | 
 | 283 | 	 * measure the interrupt frequency | 
 | 284 | 	 */ | 
 | 285 | 	bc->debug_vals.cur_intcnt++; | 
| Marcelo Feitoza Parisi | cd8749b | 2005-07-15 11:16:42 +0100 | [diff] [blame] | 286 | 	if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 287 | 		bc->debug_vals.last_jiffies = cur_jiffies; | 
 | 288 | 		bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; | 
 | 289 | 		bc->debug_vals.cur_intcnt = 0; | 
 | 290 | 		bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; | 
 | 291 | 		bc->debug_vals.cur_pllcorr = 0; | 
 | 292 | 	} | 
 | 293 | #endif /* BAYCOM_DEBUG */ | 
 | 294 | } | 
 | 295 |  | 
 | 296 | /* ---------------------------------------------------------------------- */ | 
 | 297 | /* | 
 | 298 |  *    eppconfig_path should be setable  via /proc/sys. | 
 | 299 |  */ | 
 | 300 |  | 
 | 301 | static char eppconfig_path[256] = "/usr/sbin/eppfpga"; | 
 | 302 |  | 
 | 303 | static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; | 
 | 304 |  | 
 | 305 | /* eppconfig: called during ifconfig up to configure the modem */ | 
 | 306 | static int eppconfig(struct baycom_state *bc) | 
 | 307 | { | 
 | 308 | 	char modearg[256]; | 
 | 309 | 	char portarg[16]; | 
 | 310 |         char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, | 
 | 311 | 			 NULL }; | 
 | 312 |  | 
 | 313 | 	/* set up arguments */ | 
 | 314 | 	sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", | 
 | 315 | 		bc->cfg.intclk ? "int" : "ext", | 
 | 316 | 		bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, | 
 | 317 | 		(bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps), | 
 | 318 | 		bc->cfg.loopback ? ",loopback" : ""); | 
 | 319 | 	sprintf(portarg, "%ld", bc->pdev->port->base); | 
 | 320 | 	printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); | 
 | 321 |  | 
| Jeremy Fitzhardinge | 86313c4 | 2007-07-17 18:37:03 -0700 | [diff] [blame] | 322 | 	return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 323 | } | 
 | 324 |  | 
 | 325 | /* ---------------------------------------------------------------------- */ | 
 | 326 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 327 | static inline void do_kiss_params(struct baycom_state *bc, | 
 | 328 | 				  unsigned char *data, unsigned long len) | 
 | 329 | { | 
 | 330 |  | 
 | 331 | #ifdef KISS_VERBOSE | 
 | 332 | #define PKP(a,b) printk(KERN_INFO "baycomm_epp: channel params: " a "\n", b) | 
 | 333 | #else /* KISS_VERBOSE */	       | 
 | 334 | #define PKP(a,b)  | 
 | 335 | #endif /* KISS_VERBOSE */	       | 
 | 336 |  | 
 | 337 | 	if (len < 2) | 
 | 338 | 		return; | 
 | 339 | 	switch(data[0]) { | 
 | 340 | 	case PARAM_TXDELAY: | 
 | 341 | 		bc->ch_params.tx_delay = data[1]; | 
 | 342 | 		PKP("TX delay = %ums", 10 * bc->ch_params.tx_delay); | 
 | 343 | 		break; | 
 | 344 | 	case PARAM_PERSIST:    | 
 | 345 | 		bc->ch_params.ppersist = data[1]; | 
 | 346 | 		PKP("p persistence = %u", bc->ch_params.ppersist); | 
 | 347 | 		break; | 
 | 348 | 	case PARAM_SLOTTIME:   | 
 | 349 | 		bc->ch_params.slottime = data[1]; | 
 | 350 | 		PKP("slot time = %ums", bc->ch_params.slottime); | 
 | 351 | 		break; | 
 | 352 | 	case PARAM_TXTAIL:     | 
 | 353 | 		bc->ch_params.tx_tail = data[1]; | 
 | 354 | 		PKP("TX tail = %ums", bc->ch_params.tx_tail); | 
 | 355 | 		break; | 
 | 356 | 	case PARAM_FULLDUP:    | 
 | 357 | 		bc->ch_params.fulldup = !!data[1]; | 
 | 358 | 		PKP("%s duplex", bc->ch_params.fulldup ? "full" : "half"); | 
 | 359 | 		break; | 
 | 360 | 	default: | 
 | 361 | 		break; | 
 | 362 | 	} | 
 | 363 | #undef PKP | 
 | 364 | } | 
 | 365 |  | 
 | 366 | /* --------------------------------------------------------------------- */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 367 |  | 
 | 368 | static void encode_hdlc(struct baycom_state *bc) | 
 | 369 | { | 
 | 370 | 	struct sk_buff *skb; | 
 | 371 | 	unsigned char *wp, *bp; | 
 | 372 | 	int pkt_len; | 
 | 373 |         unsigned bitstream, notbitstream, bitbuf, numbit, crc; | 
 | 374 | 	unsigned char crcarr[2]; | 
| Adrian Bunk | 0fd56f6 | 2005-06-02 14:04:00 -0700 | [diff] [blame] | 375 | 	int j; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 376 | 	 | 
 | 377 | 	if (bc->hdlctx.bufcnt > 0) | 
 | 378 | 		return; | 
 | 379 | 	skb = bc->skb; | 
 | 380 | 	if (!skb) | 
 | 381 | 		return; | 
 | 382 | 	bc->skb = NULL; | 
 | 383 | 	pkt_len = skb->len-1; /* strip KISS byte */ | 
 | 384 | 	wp = bc->hdlctx.buf; | 
 | 385 | 	bp = skb->data+1; | 
 | 386 | 	crc = calc_crc_ccitt(bp, pkt_len); | 
 | 387 | 	crcarr[0] = crc; | 
 | 388 | 	crcarr[1] = crc >> 8; | 
 | 389 | 	*wp++ = 0x7e; | 
 | 390 | 	bitstream = bitbuf = numbit = 0; | 
 | 391 | 	while (pkt_len > -2) { | 
 | 392 | 		bitstream >>= 8; | 
 | 393 | 		bitstream |= ((unsigned int)*bp) << 8; | 
 | 394 | 		bitbuf |= ((unsigned int)*bp) << numbit; | 
 | 395 | 		notbitstream = ~bitstream; | 
 | 396 | 		bp++; | 
 | 397 | 		pkt_len--; | 
 | 398 | 		if (!pkt_len) | 
 | 399 | 			bp = crcarr; | 
| Adrian Bunk | 0fd56f6 | 2005-06-02 14:04:00 -0700 | [diff] [blame] | 400 | 		for (j = 0; j < 8; j++) | 
 | 401 | 			if (unlikely(!(notbitstream & (0x1f0 << j)))) { | 
 | 402 | 				bitstream &= ~(0x100 << j); | 
 | 403 |  				bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | | 
 | 404 | 					((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); | 
 | 405 | 				numbit++; | 
 | 406 | 				notbitstream = ~bitstream; | 
 | 407 | 			} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 408 | 		numbit += 8; | 
 | 409 | 		while (numbit >= 8) { | 
 | 410 | 			*wp++ = bitbuf; | 
 | 411 | 			bitbuf >>= 8; | 
 | 412 | 			numbit -= 8; | 
 | 413 | 		} | 
 | 414 | 	} | 
 | 415 | 	bitbuf |= 0x7e7e << numbit; | 
 | 416 | 	numbit += 16; | 
 | 417 | 	while (numbit >= 8) { | 
 | 418 | 		*wp++ = bitbuf; | 
 | 419 | 		bitbuf >>= 8; | 
 | 420 | 		numbit -= 8; | 
 | 421 | 	} | 
 | 422 | 	bc->hdlctx.bufptr = bc->hdlctx.buf; | 
 | 423 | 	bc->hdlctx.bufcnt = wp - bc->hdlctx.buf; | 
 | 424 | 	dev_kfree_skb(skb); | 
| Stephen Hemminger | cd94f08 | 2009-01-09 13:01:29 +0000 | [diff] [blame] | 425 | 	bc->dev->stats.tx_packets++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 426 | } | 
 | 427 |  | 
 | 428 | /* ---------------------------------------------------------------------- */ | 
 | 429 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 430 | static int transmit(struct baycom_state *bc, int cnt, unsigned char stat) | 
 | 431 | { | 
 | 432 | 	struct parport *pp = bc->pdev->port; | 
 | 433 | 	unsigned char tmp[128]; | 
 | 434 | 	int i, j; | 
 | 435 |  | 
 | 436 | 	if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT)) | 
 | 437 | 		bc->hdlctx.state = tx_idle; | 
 | 438 | 	if (bc->hdlctx.state == tx_idle && bc->hdlctx.calibrate <= 0) { | 
 | 439 | 		if (bc->hdlctx.bufcnt <= 0) | 
 | 440 | 			encode_hdlc(bc); | 
 | 441 | 		if (bc->hdlctx.bufcnt <= 0) | 
 | 442 | 			return 0; | 
 | 443 | 		if (!bc->ch_params.fulldup) { | 
 | 444 | 			if (!(stat & EPP_DCDBIT)) { | 
 | 445 | 				bc->hdlctx.slotcnt = bc->ch_params.slottime; | 
 | 446 | 				return 0; | 
 | 447 | 			} | 
 | 448 | 			if ((--bc->hdlctx.slotcnt) > 0) | 
 | 449 | 				return 0; | 
 | 450 | 			bc->hdlctx.slotcnt = bc->ch_params.slottime; | 
| Ralf Baechle | 8b5b467 | 2007-02-16 11:55:33 +0000 | [diff] [blame] | 451 | 			if ((random32() % 256) > bc->ch_params.ppersist) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 452 | 				return 0; | 
 | 453 | 		} | 
 | 454 | 	} | 
 | 455 | 	if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) { | 
 | 456 | 		bc->hdlctx.state = tx_keyup; | 
 | 457 | 		bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_delay); | 
 | 458 | 		bc->ptt_keyed++; | 
 | 459 | 	} | 
 | 460 | 	while (cnt > 0) { | 
 | 461 | 		switch (bc->hdlctx.state) { | 
 | 462 | 		case tx_keyup: | 
 | 463 | 			i = min_t(int, cnt, bc->hdlctx.flags); | 
 | 464 | 			cnt -= i; | 
 | 465 | 			bc->hdlctx.flags -= i; | 
 | 466 | 			if (bc->hdlctx.flags <= 0) | 
 | 467 | 				bc->hdlctx.state = tx_data; | 
 | 468 | 			memset(tmp, 0x7e, sizeof(tmp)); | 
 | 469 | 			while (i > 0) { | 
 | 470 | 				j = (i > sizeof(tmp)) ? sizeof(tmp) : i; | 
 | 471 | 				if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) | 
 | 472 | 					return -1; | 
 | 473 | 				i -= j; | 
 | 474 | 			} | 
 | 475 | 			break; | 
 | 476 |  | 
 | 477 | 		case tx_data: | 
 | 478 | 			if (bc->hdlctx.bufcnt <= 0) { | 
 | 479 | 				encode_hdlc(bc); | 
 | 480 | 				if (bc->hdlctx.bufcnt <= 0) { | 
 | 481 | 					bc->hdlctx.state = tx_tail; | 
 | 482 | 					bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_tail); | 
 | 483 | 					break; | 
 | 484 | 				} | 
 | 485 | 			} | 
 | 486 | 			i = min_t(int, cnt, bc->hdlctx.bufcnt); | 
 | 487 | 			bc->hdlctx.bufcnt -= i; | 
 | 488 | 			cnt -= i; | 
 | 489 | 			if (i != pp->ops->epp_write_data(pp, bc->hdlctx.bufptr, i, 0)) | 
 | 490 | 					return -1; | 
 | 491 | 			bc->hdlctx.bufptr += i; | 
 | 492 | 			break; | 
 | 493 | 			 | 
 | 494 | 		case tx_tail: | 
 | 495 | 			encode_hdlc(bc); | 
 | 496 | 			if (bc->hdlctx.bufcnt > 0) { | 
 | 497 | 				bc->hdlctx.state = tx_data; | 
 | 498 | 				break; | 
 | 499 | 			} | 
 | 500 | 			i = min_t(int, cnt, bc->hdlctx.flags); | 
 | 501 | 			if (i) { | 
 | 502 | 				cnt -= i; | 
 | 503 | 				bc->hdlctx.flags -= i; | 
 | 504 | 				memset(tmp, 0x7e, sizeof(tmp)); | 
 | 505 | 				while (i > 0) { | 
 | 506 | 					j = (i > sizeof(tmp)) ? sizeof(tmp) : i; | 
 | 507 | 					if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) | 
 | 508 | 						return -1; | 
 | 509 | 					i -= j; | 
 | 510 | 				} | 
 | 511 | 				break; | 
 | 512 | 			} | 
 | 513 |  | 
 | 514 | 		default:  /* fall through */ | 
 | 515 | 			if (bc->hdlctx.calibrate <= 0) | 
 | 516 | 				return 0; | 
 | 517 | 			i = min_t(int, cnt, bc->hdlctx.calibrate); | 
 | 518 | 			cnt -= i; | 
 | 519 | 			bc->hdlctx.calibrate -= i; | 
 | 520 | 			memset(tmp, 0, sizeof(tmp)); | 
 | 521 | 			while (i > 0) { | 
 | 522 | 				j = (i > sizeof(tmp)) ? sizeof(tmp) : i; | 
 | 523 | 				if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) | 
 | 524 | 					return -1; | 
 | 525 | 				i -= j; | 
 | 526 | 			} | 
 | 527 | 			break; | 
 | 528 | 		} | 
 | 529 | 	} | 
 | 530 | 	return 0; | 
 | 531 | } | 
 | 532 |  | 
 | 533 | /* ---------------------------------------------------------------------- */ | 
 | 534 |  | 
 | 535 | static void do_rxpacket(struct net_device *dev) | 
 | 536 | { | 
 | 537 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 538 | 	struct sk_buff *skb; | 
 | 539 | 	unsigned char *cp; | 
 | 540 | 	unsigned pktlen; | 
 | 541 |  | 
 | 542 | 	if (bc->hdlcrx.bufcnt < 4)  | 
 | 543 | 		return; | 
 | 544 | 	if (!check_crc_ccitt(bc->hdlcrx.buf, bc->hdlcrx.bufcnt))  | 
 | 545 | 		return; | 
 | 546 | 	pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */ | 
 | 547 | 	if (!(skb = dev_alloc_skb(pktlen))) { | 
 | 548 | 		printk("%s: memory squeeze, dropping packet\n", dev->name); | 
| Stephen Hemminger | cd94f08 | 2009-01-09 13:01:29 +0000 | [diff] [blame] | 549 | 		dev->stats.rx_dropped++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 550 | 		return; | 
 | 551 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 552 | 	cp = skb_put(skb, pktlen); | 
 | 553 | 	*cp++ = 0; /* KISS kludge */ | 
 | 554 | 	memcpy(cp, bc->hdlcrx.buf, pktlen - 1); | 
| Arnaldo Carvalho de Melo | 56cb515 | 2005-04-24 18:53:06 -0700 | [diff] [blame] | 555 | 	skb->protocol = ax25_type_trans(skb, dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 556 | 	netif_rx(skb); | 
| Stephen Hemminger | cd94f08 | 2009-01-09 13:01:29 +0000 | [diff] [blame] | 557 | 	dev->stats.rx_packets++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 558 | } | 
 | 559 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 560 | static int receive(struct net_device *dev, int cnt) | 
 | 561 | { | 
 | 562 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 563 | 	struct parport *pp = bc->pdev->port; | 
 | 564 |         unsigned int bitbuf, notbitstream, bitstream, numbits, state; | 
 | 565 | 	unsigned char tmp[128]; | 
 | 566 |         unsigned char *cp; | 
 | 567 | 	int cnt2, ret = 0; | 
| Adrian Bunk | 0fd56f6 | 2005-06-02 14:04:00 -0700 | [diff] [blame] | 568 | 	int j; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 569 |          | 
 | 570 |         numbits = bc->hdlcrx.numbits; | 
 | 571 | 	state = bc->hdlcrx.state; | 
 | 572 | 	bitstream = bc->hdlcrx.bitstream; | 
 | 573 | 	bitbuf = bc->hdlcrx.bitbuf; | 
 | 574 | 	while (cnt > 0) { | 
 | 575 | 		cnt2 = (cnt > sizeof(tmp)) ? sizeof(tmp) : cnt; | 
 | 576 | 		cnt -= cnt2; | 
 | 577 | 		if (cnt2 != pp->ops->epp_read_data(pp, tmp, cnt2, 0)) { | 
 | 578 | 			ret = -1; | 
 | 579 | 			break; | 
 | 580 | 		} | 
 | 581 | 		cp = tmp; | 
 | 582 | 		for (; cnt2 > 0; cnt2--, cp++) { | 
 | 583 | 			bitstream >>= 8; | 
 | 584 | 			bitstream |= (*cp) << 8; | 
 | 585 | 			bitbuf >>= 8; | 
 | 586 | 			bitbuf |= (*cp) << 8; | 
 | 587 | 			numbits += 8; | 
 | 588 | 			notbitstream = ~bitstream; | 
| Adrian Bunk | 0fd56f6 | 2005-06-02 14:04:00 -0700 | [diff] [blame] | 589 | 			for (j = 0; j < 8; j++) { | 
 | 590 |  | 
 | 591 | 				/* flag or abort */ | 
 | 592 | 			        if (unlikely(!(notbitstream & (0x0fc << j)))) { | 
 | 593 |  | 
 | 594 | 					/* abort received */ | 
 | 595 | 					if (!(notbitstream & (0x1fc << j))) | 
 | 596 | 						state = 0; | 
 | 597 |  | 
 | 598 | 					/* not flag received */ | 
 | 599 | 					else if (!(bitstream & (0x1fe << j)) != (0x0fc << j)) { | 
 | 600 | 						if (state) | 
 | 601 | 							do_rxpacket(dev); | 
 | 602 | 						bc->hdlcrx.bufcnt = 0; | 
 | 603 | 						bc->hdlcrx.bufptr = bc->hdlcrx.buf; | 
 | 604 | 						state = 1; | 
 | 605 | 						numbits = 7-j; | 
 | 606 | 						} | 
 | 607 | 					} | 
 | 608 |  | 
 | 609 | 				/* stuffed bit */ | 
 | 610 | 				else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) { | 
 | 611 | 					numbits--; | 
 | 612 | 					bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1); | 
 | 613 | 					} | 
 | 614 | 				} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 615 | 			while (state && numbits >= 8) { | 
 | 616 | 				if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) { | 
 | 617 | 					state = 0; | 
 | 618 | 				} else { | 
 | 619 | 					*(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits); | 
 | 620 | 					bc->hdlcrx.bufcnt++; | 
 | 621 | 					numbits -= 8; | 
 | 622 | 				} | 
 | 623 | 			} | 
 | 624 | 		} | 
 | 625 | 	} | 
 | 626 |         bc->hdlcrx.numbits = numbits; | 
 | 627 | 	bc->hdlcrx.state = state; | 
 | 628 | 	bc->hdlcrx.bitstream = bitstream; | 
 | 629 | 	bc->hdlcrx.bitbuf = bitbuf; | 
 | 630 | 	return ret; | 
 | 631 | } | 
 | 632 |  | 
 | 633 | /* --------------------------------------------------------------------- */ | 
 | 634 |  | 
 | 635 | #ifdef __i386__ | 
 | 636 | #include <asm/msr.h> | 
 | 637 | #define GETTICK(x)                                                \ | 
 | 638 | ({                                                                \ | 
 | 639 | 	if (cpu_has_tsc)                                          \ | 
 | 640 | 		rdtscl(x);                                        \ | 
 | 641 | }) | 
 | 642 | #else /* __i386__ */ | 
 | 643 | #define GETTICK(x) | 
 | 644 | #endif /* __i386__ */ | 
 | 645 |  | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 646 | static void epp_bh(struct work_struct *work) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 647 | { | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 648 | 	struct net_device *dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 649 | 	struct baycom_state *bc; | 
 | 650 | 	struct parport *pp; | 
 | 651 | 	unsigned char stat; | 
 | 652 | 	unsigned char tmp[2]; | 
 | 653 | 	unsigned int time1 = 0, time2 = 0, time3 = 0; | 
 | 654 | 	int cnt, cnt2; | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 655 |  | 
 | 656 | 	bc = container_of(work, struct baycom_state, run_work.work); | 
 | 657 | 	dev = bc->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 658 | 	if (!bc->work_running) | 
 | 659 | 		return; | 
 | 660 | 	baycom_int_freq(bc); | 
 | 661 | 	pp = bc->pdev->port; | 
 | 662 | 	/* update status */ | 
 | 663 | 	if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | 
 | 664 | 		goto epptimeout; | 
 | 665 | 	bc->stat = stat; | 
 | 666 | 	bc->debug_vals.last_pllcorr = stat; | 
 | 667 | 	GETTICK(time1); | 
 | 668 | 	if (bc->modem == EPP_FPGAEXTSTATUS) { | 
 | 669 | 		/* get input count */ | 
 | 670 | 		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1; | 
 | 671 | 		if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | 
 | 672 | 			goto epptimeout; | 
 | 673 | 		if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) | 
 | 674 | 			goto epptimeout; | 
 | 675 | 		cnt = tmp[0] | (tmp[1] << 8); | 
 | 676 | 		cnt &= 0x7fff; | 
 | 677 | 		/* get output count */ | 
 | 678 | 		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2; | 
 | 679 | 		if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | 
 | 680 | 			goto epptimeout; | 
 | 681 | 		if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) | 
 | 682 | 			goto epptimeout; | 
 | 683 | 		cnt2 = tmp[0] | (tmp[1] << 8); | 
 | 684 | 		cnt2 = 16384 - (cnt2 & 0x7fff); | 
 | 685 | 		/* return to normal */ | 
 | 686 | 		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; | 
 | 687 | 		if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | 
 | 688 | 			goto epptimeout; | 
 | 689 | 		if (transmit(bc, cnt2, stat)) | 
 | 690 | 			goto epptimeout; | 
 | 691 | 		GETTICK(time2); | 
 | 692 | 		if (receive(dev, cnt)) | 
 | 693 | 			goto epptimeout; | 
 | 694 | 		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | 
 | 695 | 			goto epptimeout; | 
 | 696 | 		bc->stat = stat; | 
 | 697 | 	} else { | 
 | 698 | 		/* try to tx */ | 
 | 699 | 		switch (stat & (EPP_NTAEF|EPP_NTHF)) { | 
 | 700 | 		case EPP_NTHF: | 
 | 701 | 			cnt = 2048 - 256; | 
 | 702 | 			break; | 
 | 703 | 		 | 
 | 704 | 		case EPP_NTAEF: | 
 | 705 | 			cnt = 2048 - 1793; | 
 | 706 | 			break; | 
 | 707 | 		 | 
 | 708 | 		case 0: | 
 | 709 | 			cnt = 0; | 
 | 710 | 			break; | 
 | 711 | 		 | 
 | 712 | 		default: | 
 | 713 | 			cnt = 2048 - 1025; | 
 | 714 | 			break; | 
 | 715 | 		} | 
 | 716 | 		if (transmit(bc, cnt, stat)) | 
 | 717 | 			goto epptimeout; | 
 | 718 | 		GETTICK(time2); | 
 | 719 | 		/* do receiver */ | 
 | 720 | 		while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) { | 
 | 721 | 			switch (stat & (EPP_NRAEF|EPP_NRHF)) { | 
 | 722 | 			case EPP_NRAEF: | 
 | 723 | 				cnt = 1025; | 
 | 724 | 				break; | 
 | 725 |  | 
 | 726 | 			case 0: | 
 | 727 | 				cnt = 1793; | 
 | 728 | 				break; | 
 | 729 |  | 
 | 730 | 			default: | 
 | 731 | 				cnt = 256; | 
 | 732 | 				break; | 
 | 733 | 			} | 
 | 734 | 			if (receive(dev, cnt)) | 
 | 735 | 				goto epptimeout; | 
 | 736 | 			if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | 
 | 737 | 				goto epptimeout; | 
 | 738 | 		} | 
 | 739 | 		cnt = 0; | 
 | 740 | 		if (bc->bitrate < 50000) | 
 | 741 | 			cnt = 256; | 
 | 742 | 		else if (bc->bitrate < 100000) | 
 | 743 | 			cnt = 128; | 
 | 744 | 		while (cnt > 0 && stat & EPP_NREF) { | 
 | 745 | 			if (receive(dev, 1)) | 
 | 746 | 				goto epptimeout; | 
 | 747 | 			cnt--; | 
 | 748 | 			if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | 
 | 749 | 				goto epptimeout; | 
 | 750 | 		} | 
 | 751 | 	} | 
 | 752 | 	GETTICK(time3); | 
 | 753 | #ifdef BAYCOM_DEBUG | 
 | 754 | 	bc->debug_vals.mod_cycles = time2 - time1; | 
 | 755 | 	bc->debug_vals.demod_cycles = time3 - time2; | 
 | 756 | #endif /* BAYCOM_DEBUG */ | 
 | 757 | 	schedule_delayed_work(&bc->run_work, 1); | 
 | 758 | 	if (!bc->skb) | 
 | 759 | 		netif_wake_queue(dev); | 
 | 760 | 	return; | 
 | 761 |  epptimeout: | 
 | 762 | 	printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname); | 
 | 763 | } | 
 | 764 |  | 
 | 765 | /* ---------------------------------------------------------------------- */ | 
 | 766 | /* | 
 | 767 |  * ===================== network driver interface ========================= | 
 | 768 |  */ | 
 | 769 |  | 
 | 770 | static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) | 
 | 771 | { | 
 | 772 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 773 |  | 
 | 774 | 	if (skb->data[0] != 0) { | 
 | 775 | 		do_kiss_params(bc, skb->data, skb->len); | 
 | 776 | 		dev_kfree_skb(skb); | 
 | 777 | 		return 0; | 
 | 778 | 	} | 
 | 779 | 	if (bc->skb) | 
 | 780 | 		return -1; | 
 | 781 | 	/* strip KISS byte */ | 
 | 782 | 	if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { | 
 | 783 | 		dev_kfree_skb(skb); | 
 | 784 | 		return 0; | 
 | 785 | 	} | 
 | 786 | 	netif_stop_queue(dev); | 
 | 787 | 	bc->skb = skb; | 
 | 788 | 	return 0; | 
 | 789 | } | 
 | 790 |  | 
 | 791 | /* --------------------------------------------------------------------- */ | 
 | 792 |  | 
 | 793 | static int baycom_set_mac_address(struct net_device *dev, void *addr) | 
 | 794 | { | 
 | 795 | 	struct sockaddr *sa = (struct sockaddr *)addr; | 
 | 796 |  | 
 | 797 | 	/* addr is an AX.25 shifted ASCII mac address */ | 
 | 798 | 	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);  | 
 | 799 | 	return 0;                                          | 
 | 800 | } | 
 | 801 |  | 
 | 802 | /* --------------------------------------------------------------------- */ | 
 | 803 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 804 | static void epp_wakeup(void *handle) | 
 | 805 | { | 
 | 806 |         struct net_device *dev = (struct net_device *)handle; | 
 | 807 |         struct baycom_state *bc = netdev_priv(dev); | 
 | 808 |  | 
 | 809 |         printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name); | 
 | 810 |         if (!parport_claim(bc->pdev)) | 
 | 811 |                 printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name); | 
 | 812 | } | 
 | 813 |  | 
 | 814 | /* --------------------------------------------------------------------- */ | 
 | 815 |  | 
 | 816 | /* | 
 | 817 |  * Open/initialize the board. This is called (in the current kernel) | 
 | 818 |  * sometime after booting when the 'ifconfig' program is run. | 
 | 819 |  * | 
 | 820 |  * This routine should set everything up anew at each open, even | 
 | 821 |  * registers that "should" only need to be set once at boot, so that | 
 | 822 |  * there is non-reboot way to recover if something goes wrong. | 
 | 823 |  */ | 
 | 824 |  | 
 | 825 | static int epp_open(struct net_device *dev) | 
 | 826 | { | 
 | 827 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 828 |         struct parport *pp = parport_find_base(dev->base_addr); | 
 | 829 | 	unsigned int i, j; | 
 | 830 | 	unsigned char tmp[128]; | 
 | 831 | 	unsigned char stat; | 
 | 832 | 	unsigned long tstart; | 
 | 833 | 	 | 
 | 834 |         if (!pp) { | 
 | 835 |                 printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr); | 
 | 836 |                 return -ENXIO; | 
 | 837 |         } | 
 | 838 | #if 0 | 
 | 839 |         if (pp->irq < 0) { | 
 | 840 |                 printk(KERN_ERR "%s: parport at 0x%lx has no irq\n", bc_drvname, pp->base); | 
 | 841 | 		parport_put_port(pp); | 
 | 842 |                 return -ENXIO; | 
 | 843 |         } | 
 | 844 | #endif | 
 | 845 | 	if ((~pp->modes) & (PARPORT_MODE_TRISTATE | PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { | 
 | 846 |                 printk(KERN_ERR "%s: parport at 0x%lx cannot be used\n", | 
 | 847 | 		       bc_drvname, pp->base); | 
 | 848 | 		parport_put_port(pp); | 
 | 849 |                 return -EIO; | 
 | 850 | 	} | 
 | 851 | 	memset(&bc->modem, 0, sizeof(bc->modem)); | 
 | 852 |         bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup,  | 
| Jeff Garzik | 5712cb3 | 2007-10-19 02:54:26 -0400 | [diff] [blame] | 853 | 					   NULL, PARPORT_DEV_EXCL, dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 854 | 	parport_put_port(pp); | 
 | 855 |         if (!bc->pdev) { | 
 | 856 |                 printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base); | 
 | 857 |                 return -ENXIO; | 
 | 858 |         } | 
 | 859 |         if (parport_claim(bc->pdev)) { | 
 | 860 |                 printk(KERN_ERR "%s: parport at 0x%lx busy\n", bc_drvname, pp->base); | 
 | 861 |                 parport_unregister_device(bc->pdev); | 
 | 862 |                 return -EBUSY; | 
 | 863 |         } | 
 | 864 |         dev->irq = /*pp->irq*/ 0; | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 865 | 	INIT_DELAYED_WORK(&bc->run_work, epp_bh); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 866 | 	bc->work_running = 1; | 
 | 867 | 	bc->modem = EPP_CONVENTIONAL; | 
 | 868 | 	if (eppconfig(bc)) | 
 | 869 | 		printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname); | 
 | 870 | 	else | 
 | 871 | 		bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS; | 
 | 872 | 	parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */ | 
 | 873 | 	/* reset the modem */ | 
 | 874 | 	tmp[0] = 0; | 
 | 875 | 	tmp[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; | 
 | 876 | 	if (pp->ops->epp_write_addr(pp, tmp, 2, 0) != 2) | 
 | 877 | 		goto epptimeout; | 
 | 878 | 	/* autoprobe baud rate */ | 
 | 879 | 	tstart = jiffies; | 
 | 880 | 	i = 0; | 
| Marcelo Feitoza Parisi | ff5688a | 2006-01-09 18:37:15 -0800 | [diff] [blame] | 881 | 	while (time_before(jiffies, tstart + HZ/3)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 882 | 		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | 
 | 883 | 			goto epptimeout; | 
 | 884 | 		if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) { | 
 | 885 | 			schedule(); | 
 | 886 | 			continue; | 
 | 887 | 		} | 
 | 888 | 		if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) | 
 | 889 | 			goto epptimeout; | 
 | 890 | 		if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) | 
 | 891 | 			goto epptimeout; | 
 | 892 | 		i += 256; | 
 | 893 | 	} | 
 | 894 | 	for (j = 0; j < 256; j++) { | 
 | 895 | 		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | 
 | 896 | 			goto epptimeout; | 
 | 897 | 		if (!(stat & EPP_NREF)) | 
 | 898 | 			break; | 
 | 899 | 		if (pp->ops->epp_read_data(pp, tmp, 1, 0) != 1) | 
 | 900 | 			goto epptimeout; | 
 | 901 | 		i++; | 
 | 902 | 	} | 
 | 903 | 	tstart = jiffies - tstart; | 
 | 904 | 	bc->bitrate = i * (8 * HZ) / tstart; | 
 | 905 | 	j = 1; | 
 | 906 | 	i = bc->bitrate >> 3; | 
 | 907 | 	while (j < 7 && i > 150) { | 
 | 908 | 		j++; | 
 | 909 | 		i >>= 1; | 
 | 910 | 	} | 
 | 911 | 	printk(KERN_INFO "%s: autoprobed bitrate: %d  int divider: %d  int rate: %d\n",  | 
 | 912 | 	       bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2)); | 
 | 913 | 	tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/; | 
 | 914 | 	if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | 
 | 915 | 		goto epptimeout; | 
 | 916 | 	/* | 
 | 917 | 	 * initialise hdlc variables | 
 | 918 | 	 */ | 
 | 919 | 	bc->hdlcrx.state = 0; | 
 | 920 | 	bc->hdlcrx.numbits = 0; | 
 | 921 | 	bc->hdlctx.state = tx_idle; | 
 | 922 | 	bc->hdlctx.bufcnt = 0; | 
 | 923 | 	bc->hdlctx.slotcnt = bc->ch_params.slottime; | 
 | 924 | 	bc->hdlctx.calibrate = 0; | 
 | 925 | 	/* start the bottom half stuff */ | 
 | 926 | 	schedule_delayed_work(&bc->run_work, 1); | 
 | 927 | 	netif_start_queue(dev); | 
 | 928 | 	return 0; | 
 | 929 |  | 
 | 930 |  epptimeout: | 
 | 931 | 	printk(KERN_ERR "%s: epp timeout during bitrate probe\n", bc_drvname); | 
 | 932 | 	parport_write_control(pp, 0); /* reset the adapter */ | 
 | 933 |         parport_release(bc->pdev); | 
 | 934 |         parport_unregister_device(bc->pdev); | 
 | 935 | 	return -EIO; | 
 | 936 | } | 
 | 937 |  | 
 | 938 | /* --------------------------------------------------------------------- */ | 
 | 939 |  | 
 | 940 | static int epp_close(struct net_device *dev) | 
 | 941 | { | 
 | 942 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 943 | 	struct parport *pp = bc->pdev->port; | 
 | 944 | 	unsigned char tmp[1]; | 
 | 945 |  | 
 | 946 | 	bc->work_running = 0; | 
| David S. Miller | 4bb073c | 2008-06-12 02:22:02 -0700 | [diff] [blame] | 947 | 	cancel_delayed_work_sync(&bc->run_work); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 948 | 	bc->stat = EPP_DCDBIT; | 
 | 949 | 	tmp[0] = 0; | 
 | 950 | 	pp->ops->epp_write_addr(pp, tmp, 1, 0); | 
 | 951 | 	parport_write_control(pp, 0); /* reset the adapter */ | 
 | 952 |         parport_release(bc->pdev); | 
 | 953 |         parport_unregister_device(bc->pdev); | 
 | 954 | 	if (bc->skb) | 
 | 955 | 		dev_kfree_skb(bc->skb); | 
 | 956 | 	bc->skb = NULL; | 
 | 957 | 	printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n", | 
 | 958 | 	       bc_drvname, dev->base_addr, dev->irq); | 
 | 959 | 	return 0; | 
 | 960 | } | 
 | 961 |  | 
 | 962 | /* --------------------------------------------------------------------- */ | 
 | 963 |  | 
 | 964 | static int baycom_setmode(struct baycom_state *bc, const char *modestr) | 
 | 965 | { | 
 | 966 | 	const char *cp; | 
 | 967 |  | 
 | 968 | 	if (strstr(modestr,"intclk")) | 
 | 969 | 		bc->cfg.intclk = 1; | 
 | 970 | 	if (strstr(modestr,"extclk")) | 
 | 971 | 		bc->cfg.intclk = 0; | 
 | 972 | 	if (strstr(modestr,"intmodem")) | 
 | 973 | 		bc->cfg.extmodem = 0; | 
 | 974 | 	if (strstr(modestr,"extmodem")) | 
 | 975 | 		bc->cfg.extmodem = 1; | 
 | 976 | 	if (strstr(modestr,"noloopback")) | 
 | 977 | 		bc->cfg.loopback = 0; | 
 | 978 | 	if (strstr(modestr,"loopback")) | 
 | 979 | 		bc->cfg.loopback = 1; | 
 | 980 | 	if ((cp = strstr(modestr,"fclk="))) { | 
 | 981 | 		bc->cfg.fclk = simple_strtoul(cp+5, NULL, 0); | 
 | 982 | 		if (bc->cfg.fclk < 1000000) | 
 | 983 | 			bc->cfg.fclk = 1000000; | 
 | 984 | 		if (bc->cfg.fclk > 25000000) | 
 | 985 | 			bc->cfg.fclk = 25000000; | 
 | 986 | 	} | 
 | 987 | 	if ((cp = strstr(modestr,"bps="))) { | 
 | 988 | 		bc->cfg.bps = simple_strtoul(cp+4, NULL, 0); | 
 | 989 | 		if (bc->cfg.bps < 1000) | 
 | 990 | 			bc->cfg.bps = 1000; | 
 | 991 | 		if (bc->cfg.bps > 1500000) | 
 | 992 | 			bc->cfg.bps = 1500000; | 
 | 993 | 	} | 
 | 994 | 	return 0; | 
 | 995 | } | 
 | 996 |  | 
 | 997 | /* --------------------------------------------------------------------- */ | 
 | 998 |  | 
 | 999 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 
 | 1000 | { | 
 | 1001 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 1002 | 	struct hdlcdrv_ioctl hi; | 
 | 1003 |  | 
 | 1004 | 	if (cmd != SIOCDEVPRIVATE) | 
 | 1005 | 		return -ENOIOCTLCMD; | 
 | 1006 |  | 
 | 1007 | 	if (copy_from_user(&hi, ifr->ifr_data, sizeof(hi))) | 
 | 1008 | 		return -EFAULT; | 
 | 1009 | 	switch (hi.cmd) { | 
 | 1010 | 	default: | 
 | 1011 | 		return -ENOIOCTLCMD; | 
 | 1012 |  | 
 | 1013 | 	case HDLCDRVCTL_GETCHANNELPAR: | 
 | 1014 | 		hi.data.cp.tx_delay = bc->ch_params.tx_delay; | 
 | 1015 | 		hi.data.cp.tx_tail = bc->ch_params.tx_tail; | 
 | 1016 | 		hi.data.cp.slottime = bc->ch_params.slottime; | 
 | 1017 | 		hi.data.cp.ppersist = bc->ch_params.ppersist; | 
 | 1018 | 		hi.data.cp.fulldup = bc->ch_params.fulldup; | 
 | 1019 | 		break; | 
 | 1020 |  | 
 | 1021 | 	case HDLCDRVCTL_SETCHANNELPAR: | 
 | 1022 | 		if (!capable(CAP_NET_ADMIN)) | 
 | 1023 | 			return -EACCES; | 
 | 1024 | 		bc->ch_params.tx_delay = hi.data.cp.tx_delay; | 
 | 1025 | 		bc->ch_params.tx_tail = hi.data.cp.tx_tail; | 
 | 1026 | 		bc->ch_params.slottime = hi.data.cp.slottime; | 
 | 1027 | 		bc->ch_params.ppersist = hi.data.cp.ppersist; | 
 | 1028 | 		bc->ch_params.fulldup = hi.data.cp.fulldup; | 
 | 1029 | 		bc->hdlctx.slotcnt = 1; | 
 | 1030 | 		return 0; | 
 | 1031 | 		 | 
 | 1032 | 	case HDLCDRVCTL_GETMODEMPAR: | 
 | 1033 | 		hi.data.mp.iobase = dev->base_addr; | 
 | 1034 | 		hi.data.mp.irq = dev->irq; | 
 | 1035 | 		hi.data.mp.dma = dev->dma; | 
 | 1036 | 		hi.data.mp.dma2 = 0; | 
 | 1037 | 		hi.data.mp.seriobase = 0; | 
 | 1038 | 		hi.data.mp.pariobase = 0; | 
 | 1039 | 		hi.data.mp.midiiobase = 0; | 
 | 1040 | 		break; | 
 | 1041 |  | 
 | 1042 | 	case HDLCDRVCTL_SETMODEMPAR: | 
 | 1043 | 		if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev)) | 
 | 1044 | 			return -EACCES; | 
 | 1045 | 		dev->base_addr = hi.data.mp.iobase; | 
 | 1046 | 		dev->irq = /*hi.data.mp.irq*/0; | 
 | 1047 | 		dev->dma = /*hi.data.mp.dma*/0; | 
 | 1048 | 		return 0;	 | 
 | 1049 | 		 | 
 | 1050 | 	case HDLCDRVCTL_GETSTAT: | 
 | 1051 | 		hi.data.cs.ptt = !!(bc->stat & EPP_PTTBIT); | 
 | 1052 | 		hi.data.cs.dcd = !(bc->stat & EPP_DCDBIT); | 
 | 1053 | 		hi.data.cs.ptt_keyed = bc->ptt_keyed; | 
| Stephen Hemminger | cd94f08 | 2009-01-09 13:01:29 +0000 | [diff] [blame] | 1054 | 		hi.data.cs.tx_packets = dev->stats.tx_packets; | 
 | 1055 | 		hi.data.cs.tx_errors = dev->stats.tx_errors; | 
 | 1056 | 		hi.data.cs.rx_packets = dev->stats.rx_packets; | 
 | 1057 | 		hi.data.cs.rx_errors = dev->stats.rx_errors; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1058 | 		break;		 | 
 | 1059 |  | 
 | 1060 | 	case HDLCDRVCTL_OLDGETSTAT: | 
 | 1061 | 		hi.data.ocs.ptt = !!(bc->stat & EPP_PTTBIT); | 
 | 1062 | 		hi.data.ocs.dcd = !(bc->stat & EPP_DCDBIT); | 
 | 1063 | 		hi.data.ocs.ptt_keyed = bc->ptt_keyed; | 
 | 1064 | 		break;		 | 
 | 1065 |  | 
 | 1066 | 	case HDLCDRVCTL_CALIBRATE: | 
 | 1067 | 		if (!capable(CAP_SYS_RAWIO)) | 
 | 1068 | 			return -EACCES; | 
 | 1069 | 		bc->hdlctx.calibrate = hi.data.calibrate * bc->bitrate / 8; | 
 | 1070 | 		return 0; | 
 | 1071 |  | 
 | 1072 | 	case HDLCDRVCTL_DRIVERNAME: | 
 | 1073 | 		strncpy(hi.data.drivername, "baycom_epp", sizeof(hi.data.drivername)); | 
 | 1074 | 		break; | 
 | 1075 | 		 | 
 | 1076 | 	case HDLCDRVCTL_GETMODE: | 
 | 1077 | 		sprintf(hi.data.modename, "%sclk,%smodem,fclk=%d,bps=%d%s",  | 
 | 1078 | 			bc->cfg.intclk ? "int" : "ext", | 
 | 1079 | 			bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, | 
 | 1080 | 			bc->cfg.loopback ? ",loopback" : ""); | 
 | 1081 | 		break; | 
 | 1082 |  | 
 | 1083 | 	case HDLCDRVCTL_SETMODE: | 
 | 1084 | 		if (!capable(CAP_NET_ADMIN) || netif_running(dev)) | 
 | 1085 | 			return -EACCES; | 
 | 1086 | 		hi.data.modename[sizeof(hi.data.modename)-1] = '\0'; | 
 | 1087 | 		return baycom_setmode(bc, hi.data.modename); | 
 | 1088 |  | 
 | 1089 | 	case HDLCDRVCTL_MODELIST: | 
 | 1090 | 		strncpy(hi.data.modename, "intclk,extclk,intmodem,extmodem,divider=x", | 
 | 1091 | 			sizeof(hi.data.modename)); | 
 | 1092 | 		break; | 
 | 1093 |  | 
 | 1094 | 	case HDLCDRVCTL_MODEMPARMASK: | 
 | 1095 | 		return HDLCDRV_PARMASK_IOBASE; | 
 | 1096 |  | 
 | 1097 | 	} | 
 | 1098 | 	if (copy_to_user(ifr->ifr_data, &hi, sizeof(hi))) | 
 | 1099 | 		return -EFAULT; | 
 | 1100 | 	return 0; | 
 | 1101 | } | 
 | 1102 |  | 
 | 1103 | /* --------------------------------------------------------------------- */ | 
 | 1104 |  | 
| Stephen Hemminger | 9772a25 | 2009-01-09 13:01:30 +0000 | [diff] [blame] | 1105 | static const struct net_device_ops baycom_netdev_ops = { | 
 | 1106 | 	.ndo_open	     = epp_open, | 
 | 1107 | 	.ndo_stop	     = epp_close, | 
 | 1108 | 	.ndo_do_ioctl	     = baycom_ioctl, | 
 | 1109 | 	.ndo_start_xmit      = baycom_send_packet, | 
 | 1110 | 	.ndo_set_mac_address = baycom_set_mac_address, | 
 | 1111 | }; | 
 | 1112 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1113 | /* | 
 | 1114 |  * Check for a network adaptor of this type, and return '0' if one exists. | 
 | 1115 |  * If dev->base_addr == 0, probe all likely locations. | 
 | 1116 |  * If dev->base_addr == 1, always return failure. | 
 | 1117 |  * If dev->base_addr == 2, allocate space for the device and return success | 
 | 1118 |  * (detachable devices only). | 
 | 1119 |  */ | 
 | 1120 | static void baycom_probe(struct net_device *dev) | 
 | 1121 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1122 | 	const struct hdlcdrv_channel_params dflt_ch_params = {  | 
 | 1123 | 		20, 2, 10, 40, 0  | 
 | 1124 | 	}; | 
 | 1125 | 	struct baycom_state *bc; | 
 | 1126 |  | 
 | 1127 | 	/* | 
 | 1128 | 	 * not a real probe! only initialize data structures | 
 | 1129 | 	 */ | 
 | 1130 | 	bc = netdev_priv(dev); | 
 | 1131 | 	/* | 
 | 1132 | 	 * initialize the baycom_state struct | 
 | 1133 | 	 */ | 
 | 1134 | 	bc->ch_params = dflt_ch_params; | 
 | 1135 | 	bc->ptt_keyed = 0; | 
 | 1136 |  | 
 | 1137 | 	/* | 
 | 1138 | 	 * initialize the device struct | 
 | 1139 | 	 */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1140 |  | 
 | 1141 | 	/* Fill in the fields of the device structure */ | 
 | 1142 | 	bc->skb = NULL; | 
 | 1143 | 	 | 
| Stephen Hemminger | 9772a25 | 2009-01-09 13:01:30 +0000 | [diff] [blame] | 1144 | 	dev->netdev_ops = &baycom_netdev_ops; | 
| Stephen Hemminger | 3b04ddd | 2007-10-09 01:40:57 -0700 | [diff] [blame] | 1145 | 	dev->header_ops = &ax25_header_ops; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1146 | 	 | 
 | 1147 | 	dev->type = ARPHRD_AX25;           /* AF_AX25 device */ | 
 | 1148 | 	dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; | 
 | 1149 | 	dev->mtu = AX25_DEF_PACLEN;        /* eth_mtu is the default */ | 
 | 1150 | 	dev->addr_len = AX25_ADDR_LEN;     /* sizeof an ax.25 address */ | 
| Ralf Baechle | 15b1c0e | 2006-12-07 15:47:08 -0800 | [diff] [blame] | 1151 | 	memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); | 
| Ralf Baechle | f654c85 | 2006-12-10 13:46:45 -0800 | [diff] [blame] | 1152 | 	memcpy(dev->dev_addr, &null_ax25_address, AX25_ADDR_LEN); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1153 | 	dev->tx_queue_len = 16; | 
 | 1154 |  | 
 | 1155 | 	/* New style flags */ | 
 | 1156 | 	dev->flags = 0; | 
 | 1157 | } | 
 | 1158 |  | 
 | 1159 | /* --------------------------------------------------------------------- */ | 
 | 1160 |  | 
 | 1161 | /* | 
 | 1162 |  * command line settable parameters | 
 | 1163 |  */ | 
 | 1164 | static const char *mode[NR_PORTS] = { "", }; | 
 | 1165 | static int iobase[NR_PORTS] = { 0x378, }; | 
 | 1166 |  | 
 | 1167 | module_param_array(mode, charp, NULL, 0); | 
 | 1168 | MODULE_PARM_DESC(mode, "baycom operating mode"); | 
 | 1169 | module_param_array(iobase, int, NULL, 0); | 
 | 1170 | MODULE_PARM_DESC(iobase, "baycom io base address"); | 
 | 1171 |  | 
 | 1172 | MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); | 
 | 1173 | MODULE_DESCRIPTION("Baycom epp amateur radio modem driver"); | 
 | 1174 | MODULE_LICENSE("GPL"); | 
 | 1175 |  | 
 | 1176 | /* --------------------------------------------------------------------- */ | 
 | 1177 |  | 
 | 1178 | static void __init baycom_epp_dev_setup(struct net_device *dev) | 
 | 1179 | { | 
 | 1180 | 	struct baycom_state *bc = netdev_priv(dev); | 
 | 1181 |  | 
 | 1182 | 	/* | 
 | 1183 | 	 * initialize part of the baycom_state struct | 
 | 1184 | 	 */ | 
| David Howells | c402895 | 2006-11-22 14:57:56 +0000 | [diff] [blame] | 1185 | 	bc->dev = dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1186 | 	bc->magic = BAYCOM_MAGIC; | 
 | 1187 | 	bc->cfg.fclk = 19666600; | 
 | 1188 | 	bc->cfg.bps = 9600; | 
 | 1189 | 	/* | 
 | 1190 | 	 * initialize part of the device struct | 
 | 1191 | 	 */ | 
 | 1192 | 	baycom_probe(dev); | 
 | 1193 | } | 
 | 1194 |  | 
 | 1195 | static int __init init_baycomepp(void) | 
 | 1196 | { | 
 | 1197 | 	int i, found = 0; | 
 | 1198 | 	char set_hw = 1; | 
 | 1199 |  | 
 | 1200 | 	printk(bc_drvinfo); | 
 | 1201 | 	/* | 
 | 1202 | 	 * register net devices | 
 | 1203 | 	 */ | 
 | 1204 | 	for (i = 0; i < NR_PORTS; i++) { | 
 | 1205 | 		struct net_device *dev; | 
 | 1206 | 		 | 
 | 1207 | 		dev = alloc_netdev(sizeof(struct baycom_state), "bce%d", | 
 | 1208 | 				   baycom_epp_dev_setup); | 
 | 1209 |  | 
 | 1210 | 		if (!dev) { | 
 | 1211 | 			printk(KERN_WARNING "bce%d : out of memory\n", i); | 
 | 1212 | 			return found ? 0 : -ENOMEM; | 
 | 1213 | 		} | 
 | 1214 | 			 | 
 | 1215 | 		sprintf(dev->name, "bce%d", i); | 
 | 1216 | 		dev->base_addr = iobase[i]; | 
 | 1217 |  | 
 | 1218 | 		if (!mode[i]) | 
 | 1219 | 			set_hw = 0; | 
 | 1220 | 		if (!set_hw) | 
 | 1221 | 			iobase[i] = 0; | 
 | 1222 |  | 
 | 1223 | 		if (register_netdev(dev)) { | 
 | 1224 | 			printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name); | 
 | 1225 | 			free_netdev(dev); | 
 | 1226 | 			break; | 
 | 1227 | 		} | 
 | 1228 | 		if (set_hw && baycom_setmode(netdev_priv(dev), mode[i])) | 
 | 1229 | 			set_hw = 0; | 
 | 1230 | 		baycom_device[i] = dev; | 
 | 1231 | 		found++; | 
 | 1232 | 	} | 
 | 1233 |  | 
 | 1234 | 	return found ? 0 : -ENXIO; | 
 | 1235 | } | 
 | 1236 |  | 
 | 1237 | static void __exit cleanup_baycomepp(void) | 
 | 1238 | { | 
 | 1239 | 	int i; | 
 | 1240 |  | 
 | 1241 | 	for(i = 0; i < NR_PORTS; i++) { | 
 | 1242 | 		struct net_device *dev = baycom_device[i]; | 
 | 1243 |  | 
 | 1244 | 		if (dev) { | 
 | 1245 | 			struct baycom_state *bc = netdev_priv(dev); | 
 | 1246 | 			if (bc->magic == BAYCOM_MAGIC) { | 
 | 1247 | 				unregister_netdev(dev); | 
 | 1248 | 				free_netdev(dev); | 
 | 1249 | 			} else | 
 | 1250 | 				printk(paranoia_str, "cleanup_module"); | 
 | 1251 | 		} | 
 | 1252 | 	} | 
 | 1253 | } | 
 | 1254 |  | 
 | 1255 | module_init(init_baycomepp); | 
 | 1256 | module_exit(cleanup_baycomepp); | 
 | 1257 |  | 
 | 1258 | /* --------------------------------------------------------------------- */ | 
 | 1259 |  | 
 | 1260 | #ifndef MODULE | 
 | 1261 |  | 
 | 1262 | /* | 
 | 1263 |  * format: baycom_epp=io,mode | 
 | 1264 |  * mode: fpga config options | 
 | 1265 |  */ | 
 | 1266 |  | 
 | 1267 | static int __init baycom_epp_setup(char *str) | 
 | 1268 | { | 
 | 1269 |         static unsigned __initdata nr_dev = 0; | 
 | 1270 | 	int ints[2]; | 
 | 1271 |  | 
 | 1272 |         if (nr_dev >= NR_PORTS) | 
 | 1273 |                 return 0; | 
 | 1274 | 	str = get_options(str, 2, ints); | 
 | 1275 | 	if (ints[0] < 1) | 
 | 1276 | 		return 0; | 
 | 1277 | 	mode[nr_dev] = str; | 
 | 1278 | 	iobase[nr_dev] = ints[1]; | 
 | 1279 | 	nr_dev++; | 
 | 1280 | 	return 1; | 
 | 1281 | } | 
 | 1282 |  | 
 | 1283 | __setup("baycom_epp=", baycom_epp_setup); | 
 | 1284 |  | 
 | 1285 | #endif /* MODULE */ | 
 | 1286 | /* --------------------------------------------------------------------- */ |