blob: be280871e9ac0d0b6d5cfdaf323b13b42f86697f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*****************************************************************************/
2
3/*
4 * yam.c -- YAM radio modem driver.
5 *
6 * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr)
7 * Adapted from baycom.c driver written by 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.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3
30 * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration
31 * 0.2 F6FBB 08.06.98 Added delay after FPGA programming
32 * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2
33 * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistance
34 * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics
35 * 0.6 F6FBB 25.08.98 Added 1200Bds format
36 * 0.7 F6FBB 12.09.98 Added to the kernel configuration
37 * 0.8 F6FBB 14.10.98 Fixed slottime/persistence timing bug
38 * OK1ZIA 2.09.01 Fixed "kfree_skb on hard IRQ"
39 * using dev_kfree_skb_any(). (important in 2.4 kernel)
40 *
41 */
42
43/*****************************************************************************/
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/module.h>
46#include <linux/types.h>
47#include <linux/net.h>
48#include <linux/in.h>
49#include <linux/if.h>
50#include <linux/slab.h>
51#include <linux/errno.h>
52#include <linux/bitops.h>
Ralf Baechle8b5b4672007-02-16 11:55:33 +000053#include <linux/random.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <asm/io.h>
55#include <asm/system.h>
56#include <linux/interrupt.h>
57#include <linux/ioport.h>
58
59#include <linux/netdevice.h>
60#include <linux/if_arp.h>
61#include <linux/etherdevice.h>
62#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#include <net/ax25.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include <linux/kernel.h>
66#include <linux/proc_fs.h>
67#include <linux/seq_file.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020068#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70#include <asm/uaccess.h>
71#include <linux/init.h>
72
73#include <linux/yam.h>
74#include "yam9600.h"
75#include "yam1200.h"
76
77/* --------------------------------------------------------------------- */
78
79static const char yam_drvname[] = "yam";
80static char yam_drvinfo[] __initdata = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
81
82/* --------------------------------------------------------------------- */
83
84#define YAM_9600 1
85#define YAM_1200 2
86
87#define NR_PORTS 4
88#define YAM_MAGIC 0xF10A7654
89
90/* Transmitter states */
91
92#define TX_OFF 0
93#define TX_HEAD 1
94#define TX_DATA 2
95#define TX_CRC1 3
96#define TX_CRC2 4
97#define TX_TAIL 5
98
99#define YAM_MAX_FRAME 1024
100
101#define DEFAULT_BITRATE 9600 /* bps */
102#define DEFAULT_HOLDD 10 /* sec */
103#define DEFAULT_TXD 300 /* ms */
104#define DEFAULT_TXTAIL 10 /* ms */
105#define DEFAULT_SLOT 100 /* ms */
106#define DEFAULT_PERS 64 /* 0->255 */
107
108struct yam_port {
109 int magic;
110 int bitrate;
111 int baudrate;
112 int iobase;
113 int irq;
114 int dupmode;
115
116 struct net_device *dev;
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 int nb_rxint;
119 int nb_mdint;
120
121 /* Parameters section */
122
123 int txd; /* tx delay */
124 int holdd; /* duplex ptt delay */
125 int txtail; /* txtail delay */
126 int slot; /* slottime */
127 int pers; /* persistence */
128
129 /* Tx section */
130
131 int tx_state;
132 int tx_count;
133 int slotcnt;
134 unsigned char tx_buf[YAM_MAX_FRAME];
135 int tx_len;
136 int tx_crcl, tx_crch;
137 struct sk_buff_head send_queue; /* Packets awaiting transmission */
138
139 /* Rx section */
140
141 int dcd;
142 unsigned char rx_buf[YAM_MAX_FRAME];
143 int rx_len;
144 int rx_crcl, rx_crch;
145};
146
147struct yam_mcs {
148 unsigned char bits[YAM_FPGA_SIZE];
149 int bitrate;
150 struct yam_mcs *next;
151};
152
153static struct net_device *yam_devs[NR_PORTS];
154
155static struct yam_mcs *yam_data;
156
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700157static DEFINE_TIMER(yam_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159/* --------------------------------------------------------------------- */
160
161#define RBR(iobase) (iobase+0)
162#define THR(iobase) (iobase+0)
163#define IER(iobase) (iobase+1)
164#define IIR(iobase) (iobase+2)
165#define FCR(iobase) (iobase+2)
166#define LCR(iobase) (iobase+3)
167#define MCR(iobase) (iobase+4)
168#define LSR(iobase) (iobase+5)
169#define MSR(iobase) (iobase+6)
170#define SCR(iobase) (iobase+7)
171#define DLL(iobase) (iobase+0)
172#define DLM(iobase) (iobase+1)
173
174#define YAM_EXTENT 8
175
176/* Interrupt Identification Register Bit Masks */
177#define IIR_NOPEND 1
178#define IIR_MSR 0
179#define IIR_TX 2
180#define IIR_RX 4
181#define IIR_LSR 6
182#define IIR_TIMEOUT 12 /* Fifo mode only */
183
184#define IIR_MASK 0x0F
185
186/* Interrupt Enable Register Bit Masks */
187#define IER_RX 1 /* enable rx interrupt */
188#define IER_TX 2 /* enable tx interrupt */
189#define IER_LSR 4 /* enable line status interrupts */
190#define IER_MSR 8 /* enable modem status interrupts */
191
192/* Modem Control Register Bit Masks */
193#define MCR_DTR 0x01 /* DTR output */
194#define MCR_RTS 0x02 /* RTS output */
195#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */
196#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */
197#define MCR_LOOP 0x10 /* Loopback enable */
198
199/* Modem Status Register Bit Masks */
200#define MSR_DCTS 0x01 /* Delta CTS input */
201#define MSR_DDSR 0x02 /* Delta DSR */
202#define MSR_DRIN 0x04 /* Delta RI */
203#define MSR_DDCD 0x08 /* Delta DCD */
204#define MSR_CTS 0x10 /* CTS input */
205#define MSR_DSR 0x20 /* DSR input */
206#define MSR_RING 0x40 /* RI input */
207#define MSR_DCD 0x80 /* DCD input */
208
209/* line status register bit mask */
210#define LSR_RXC 0x01
211#define LSR_OE 0x02
212#define LSR_PE 0x04
213#define LSR_FE 0x08
214#define LSR_BREAK 0x10
215#define LSR_THRE 0x20
216#define LSR_TSRE 0x40
217
218/* Line Control Register Bit Masks */
219#define LCR_DLAB 0x80
220#define LCR_BREAK 0x40
221#define LCR_PZERO 0x28
222#define LCR_PEVEN 0x18
223#define LCR_PODD 0x08
224#define LCR_STOP1 0x00
225#define LCR_STOP2 0x04
226#define LCR_BIT5 0x00
227#define LCR_BIT6 0x02
228#define LCR_BIT7 0x01
229#define LCR_BIT8 0x03
230
231/* YAM Modem <-> UART Port mapping */
232
233#define TX_RDY MSR_DCTS /* transmitter ready to send */
234#define RX_DCD MSR_DCD /* carrier detect */
235#define RX_FLAG MSR_RING /* hdlc flag received */
236#define FPGA_DONE MSR_DSR /* FPGA is configured */
237#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */
238#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */
239
240#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */
241#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */
242#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */
243
244
245/*************************************************************************
246* CRC Tables
247************************************************************************/
248
249static const unsigned char chktabl[256] =
250{0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e,
251 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64,
252 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e,
253 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50,
254 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e,
255 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44,
256 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e,
257 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38,
258 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e,
259 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24,
260 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e,
261 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10,
262 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e,
263 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04,
264 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e,
265 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9,
266 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1,
267 0x78};
268static const unsigned char chktabh[256] =
269{0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9,
270 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb,
271 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb,
272 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f,
273 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed,
274 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf,
275 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef,
276 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07,
277 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1,
278 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3,
279 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3,
280 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87,
281 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5,
282 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7,
283 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7,
284 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f,
285 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e,
286 0x0f};
287
288/*************************************************************************
289* FPGA functions
290************************************************************************/
291
292static void delay(int ms)
293{
294 unsigned long timeout = jiffies + ((ms * HZ) / 1000);
295 while (time_before(jiffies, timeout))
296 cpu_relax();
297}
298
299/*
300 * reset FPGA
301 */
302
303static void fpga_reset(int iobase)
304{
305 outb(0, IER(iobase));
306 outb(LCR_DLAB | LCR_BIT5, LCR(iobase));
307 outb(1, DLL(iobase));
308 outb(0, DLM(iobase));
309
310 outb(LCR_BIT5, LCR(iobase));
311 inb(LSR(iobase));
312 inb(MSR(iobase));
313 /* turn off FPGA supply voltage */
314 outb(MCR_OUT1 | MCR_OUT2, MCR(iobase));
315 delay(100);
316 /* turn on FPGA supply voltage again */
317 outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase));
318 delay(100);
319}
320
321/*
322 * send one byte to FPGA
323 */
324
325static int fpga_write(int iobase, unsigned char wrd)
326{
327 unsigned char bit;
328 int k;
329 unsigned long timeout = jiffies + HZ / 10;
330
331 for (k = 0; k < 8; k++) {
332 bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR;
333 outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase));
334 wrd <<= 1;
335 outb(0xfc, THR(iobase));
336 while ((inb(LSR(iobase)) & LSR_TSRE) == 0)
337 if (time_after(jiffies, timeout))
338 return -1;
339 }
340
341 return 0;
342}
343
344static unsigned char *add_mcs(unsigned char *bits, int bitrate)
345{
346 struct yam_mcs *p;
347
348 /* If it already exists, replace the bit data */
349 p = yam_data;
350 while (p) {
351 if (p->bitrate == bitrate) {
352 memcpy(p->bits, bits, YAM_FPGA_SIZE);
353 return p->bits;
354 }
355 p = p->next;
356 }
357
358 /* Allocate a new mcs */
359 if ((p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL)) == NULL) {
360 printk(KERN_WARNING "YAM: no memory to allocate mcs\n");
361 return NULL;
362 }
363 memcpy(p->bits, bits, YAM_FPGA_SIZE);
364 p->bitrate = bitrate;
365 p->next = yam_data;
366 yam_data = p;
367
368 return p->bits;
369}
370
371static unsigned char *get_mcs(int bitrate)
372{
373 struct yam_mcs *p;
374
375 p = yam_data;
376 while (p) {
377 if (p->bitrate == bitrate)
378 return p->bits;
379 p = p->next;
380 }
381
382 /* Load predefined mcs data */
383 switch (bitrate) {
384 case 1200:
385 return add_mcs(bits_1200, bitrate);
386 default:
387 return add_mcs(bits_9600, bitrate);
388 }
389}
390
391/*
392 * download bitstream to FPGA
393 * data is contained in bits[] array in yam1200.h resp. yam9600.h
394 */
395
396static int fpga_download(int iobase, int bitrate)
397{
398 int i, rc;
399 unsigned char *pbits;
400
401 pbits = get_mcs(bitrate);
402 if (pbits == NULL)
403 return -1;
404
405 fpga_reset(iobase);
406 for (i = 0; i < YAM_FPGA_SIZE; i++) {
407 if (fpga_write(iobase, pbits[i])) {
408 printk(KERN_ERR "yam: error in write cycle\n");
409 return -1; /* write... */
410 }
411 }
412
413 fpga_write(iobase, 0xFF);
414 rc = inb(MSR(iobase)); /* check DONE signal */
415
416 /* Needed for some hardwares */
417 delay(50);
418
419 return (rc & MSR_DSR) ? 0 : -1;
420}
421
422
423/************************************************************************
424* Serial port init
425************************************************************************/
426
427static void yam_set_uart(struct net_device *dev)
428{
429 struct yam_port *yp = netdev_priv(dev);
430 int divisor = 115200 / yp->baudrate;
431
432 outb(0, IER(dev->base_addr));
433 outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr));
434 outb(divisor, DLL(dev->base_addr));
435 outb(0, DLM(dev->base_addr));
436 outb(LCR_BIT8, LCR(dev->base_addr));
437 outb(PTT_OFF, MCR(dev->base_addr));
438 outb(0x00, FCR(dev->base_addr));
439
440 /* Flush pending irq */
441
442 inb(RBR(dev->base_addr));
443 inb(MSR(dev->base_addr));
444
445 /* Enable rx irq */
446
447 outb(ENABLE_RTXINT, IER(dev->base_addr));
448}
449
450
451/* --------------------------------------------------------------------- */
452
453enum uart {
454 c_uart_unknown, c_uart_8250,
455 c_uart_16450, c_uart_16550, c_uart_16550A
456};
457
458static const char *uart_str[] =
459{"unknown", "8250", "16450", "16550", "16550A"};
460
461static enum uart yam_check_uart(unsigned int iobase)
462{
463 unsigned char b1, b2, b3;
464 enum uart u;
465 enum uart uart_tab[] =
466 {c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A};
467
468 b1 = inb(MCR(iobase));
469 outb(b1 | 0x10, MCR(iobase)); /* loopback mode */
470 b2 = inb(MSR(iobase));
471 outb(0x1a, MCR(iobase));
472 b3 = inb(MSR(iobase)) & 0xf0;
473 outb(b1, MCR(iobase)); /* restore old values */
474 outb(b2, MSR(iobase));
475 if (b3 != 0x90)
476 return c_uart_unknown;
477 inb(RBR(iobase));
478 inb(RBR(iobase));
479 outb(0x01, FCR(iobase)); /* enable FIFOs */
480 u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
481 if (u == c_uart_16450) {
482 outb(0x5a, SCR(iobase));
483 b1 = inb(SCR(iobase));
484 outb(0xa5, SCR(iobase));
485 b2 = inb(SCR(iobase));
486 if ((b1 != 0x5a) || (b2 != 0xa5))
487 u = c_uart_8250;
488 }
489 return u;
490}
491
492/******************************************************************************
493* Rx Section
494******************************************************************************/
495static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp)
496{
497 if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) {
498 int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */
499 struct sk_buff *skb;
500
501 if ((yp->rx_crch & yp->rx_crcl) != 0xFF) {
502 /* Bad crc */
503 } else {
504 if (!(skb = dev_alloc_skb(pkt_len))) {
505 printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name);
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000506 ++dev->stats.rx_dropped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 } else {
508 unsigned char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 cp = skb_put(skb, pkt_len);
510 *cp++ = 0; /* KISS kludge */
511 memcpy(cp, yp->rx_buf, pkt_len - 1);
Arnaldo Carvalho de Melo56cb5152005-04-24 18:53:06 -0700512 skb->protocol = ax25_type_trans(skb, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 netif_rx(skb);
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000514 ++dev->stats.rx_packets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516 }
517 }
518 yp->rx_len = 0;
519 yp->rx_crcl = 0x21;
520 yp->rx_crch = 0xf3;
521}
522
523static inline void yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb)
524{
525 if (yp->rx_len < YAM_MAX_FRAME) {
526 unsigned char c = yp->rx_crcl;
527 yp->rx_crcl = (chktabl[c] ^ yp->rx_crch);
528 yp->rx_crch = (chktabh[c] ^ rxb);
529 yp->rx_buf[yp->rx_len++] = rxb;
530 }
531}
532
533/********************************************************************************
534* TX Section
535********************************************************************************/
536
537static void ptt_on(struct net_device *dev)
538{
539 outb(PTT_ON, MCR(dev->base_addr));
540}
541
542static void ptt_off(struct net_device *dev)
543{
544 outb(PTT_OFF, MCR(dev->base_addr));
545}
546
547static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
548{
549 struct yam_port *yp = netdev_priv(dev);
550
551 skb_queue_tail(&yp->send_queue, skb);
552 dev->trans_start = jiffies;
553 return 0;
554}
555
556static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
557{
558 if ((yp->tx_state == TX_TAIL) || (yp->txd == 0))
559 yp->tx_count = 1;
560 else
561 yp->tx_count = (yp->bitrate * yp->txd) / 8000;
562 yp->tx_state = TX_HEAD;
563 ptt_on(dev);
564}
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566static void yam_arbitrate(struct net_device *dev)
567{
568 struct yam_port *yp = netdev_priv(dev);
569
570 if (yp->magic != YAM_MAGIC || yp->tx_state != TX_OFF ||
571 skb_queue_empty(&yp->send_queue))
572 return;
573 /* tx_state is TX_OFF and there is data to send */
574
575 if (yp->dupmode) {
576 /* Full duplex mode, don't wait */
577 yam_start_tx(dev, yp);
578 return;
579 }
580 if (yp->dcd) {
581 /* DCD on, wait slotime ... */
582 yp->slotcnt = yp->slot / 10;
583 return;
584 }
585 /* Is slottime passed ? */
586 if ((--yp->slotcnt) > 0)
587 return;
588
589 yp->slotcnt = yp->slot / 10;
590
591 /* is random > persist ? */
Ralf Baechle8b5b4672007-02-16 11:55:33 +0000592 if ((random32() % 256) > yp->pers)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 return;
594
595 yam_start_tx(dev, yp);
596}
597
598static void yam_dotimer(unsigned long dummy)
599{
600 int i;
601
602 for (i = 0; i < NR_PORTS; i++) {
603 struct net_device *dev = yam_devs[i];
604 if (dev && netif_running(dev))
605 yam_arbitrate(dev);
606 }
607 yam_timer.expires = jiffies + HZ / 100;
608 add_timer(&yam_timer);
609}
610
611static void yam_tx_byte(struct net_device *dev, struct yam_port *yp)
612{
613 struct sk_buff *skb;
614 unsigned char b, temp;
615
616 switch (yp->tx_state) {
617 case TX_OFF:
618 break;
619 case TX_HEAD:
620 if (--yp->tx_count <= 0) {
621 if (!(skb = skb_dequeue(&yp->send_queue))) {
622 ptt_off(dev);
623 yp->tx_state = TX_OFF;
624 break;
625 }
626 yp->tx_state = TX_DATA;
627 if (skb->data[0] != 0) {
628/* do_kiss_params(s, skb->data, skb->len); */
629 dev_kfree_skb_any(skb);
630 break;
631 }
632 yp->tx_len = skb->len - 1; /* strip KISS byte */
633 if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) {
634 dev_kfree_skb_any(skb);
635 break;
636 }
Andrew Morton55404bc2007-04-26 00:55:53 -0700637 skb_copy_from_linear_data_offset(skb, 1,
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300638 yp->tx_buf,
639 yp->tx_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 dev_kfree_skb_any(skb);
641 yp->tx_count = 0;
642 yp->tx_crcl = 0x21;
643 yp->tx_crch = 0xf3;
644 yp->tx_state = TX_DATA;
645 }
646 break;
647 case TX_DATA:
648 b = yp->tx_buf[yp->tx_count++];
649 outb(b, THR(dev->base_addr));
650 temp = yp->tx_crcl;
651 yp->tx_crcl = chktabl[temp] ^ yp->tx_crch;
652 yp->tx_crch = chktabh[temp] ^ b;
653 if (yp->tx_count >= yp->tx_len) {
654 yp->tx_state = TX_CRC1;
655 }
656 break;
657 case TX_CRC1:
658 yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch;
659 yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff;
660 outb(yp->tx_crcl, THR(dev->base_addr));
661 yp->tx_state = TX_CRC2;
662 break;
663 case TX_CRC2:
664 outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr));
665 if (skb_queue_empty(&yp->send_queue)) {
666 yp->tx_count = (yp->bitrate * yp->txtail) / 8000;
667 if (yp->dupmode == 2)
668 yp->tx_count += (yp->bitrate * yp->holdd) / 8;
669 if (yp->tx_count == 0)
670 yp->tx_count = 1;
671 yp->tx_state = TX_TAIL;
672 } else {
673 yp->tx_count = 1;
674 yp->tx_state = TX_HEAD;
675 }
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000676 ++dev->stats.tx_packets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 break;
678 case TX_TAIL:
679 if (--yp->tx_count <= 0) {
680 yp->tx_state = TX_OFF;
681 ptt_off(dev);
682 }
683 break;
684 }
685}
686
687/***********************************************************************************
688* ISR routine
689************************************************************************************/
690
David Howells7d12e782006-10-05 14:55:46 +0100691static irqreturn_t yam_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 struct net_device *dev;
694 struct yam_port *yp;
695 unsigned char iir;
696 int counter = 100;
697 int i;
698 int handled = 0;
699
700 for (i = 0; i < NR_PORTS; i++) {
701 dev = yam_devs[i];
702 yp = netdev_priv(dev);
703
704 if (!netif_running(dev))
705 continue;
706
707 while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
708 unsigned char msr = inb(MSR(dev->base_addr));
709 unsigned char lsr = inb(LSR(dev->base_addr));
710 unsigned char rxb;
711
712 handled = 1;
713
714 if (lsr & LSR_OE)
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000715 ++dev->stats.rx_fifo_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 yp->dcd = (msr & RX_DCD) ? 1 : 0;
718
719 if (--counter <= 0) {
720 printk(KERN_ERR "%s: too many irq iir=%d\n",
721 dev->name, iir);
722 goto out;
723 }
724 if (msr & TX_RDY) {
725 ++yp->nb_mdint;
726 yam_tx_byte(dev, yp);
727 }
728 if (lsr & LSR_RXC) {
729 ++yp->nb_rxint;
730 rxb = inb(RBR(dev->base_addr));
731 if (msr & RX_FLAG)
732 yam_rx_flag(dev, yp);
733 else
734 yam_rx_byte(dev, yp, rxb);
735 }
736 }
737 }
738out:
739 return IRQ_RETVAL(handled);
740}
741
742#ifdef CONFIG_PROC_FS
743
744static void *yam_seq_start(struct seq_file *seq, loff_t *pos)
745{
746 return (*pos < NR_PORTS) ? yam_devs[*pos] : NULL;
747}
748
749static void *yam_seq_next(struct seq_file *seq, void *v, loff_t *pos)
750{
751 ++*pos;
752 return (*pos < NR_PORTS) ? yam_devs[*pos] : NULL;
753}
754
755static void yam_seq_stop(struct seq_file *seq, void *v)
756{
757}
758
759static int yam_seq_show(struct seq_file *seq, void *v)
760{
761 struct net_device *dev = v;
762 const struct yam_port *yp = netdev_priv(dev);
763
764 seq_printf(seq, "Device %s\n", dev->name);
765 seq_printf(seq, " Up %d\n", netif_running(dev));
766 seq_printf(seq, " Speed %u\n", yp->bitrate);
767 seq_printf(seq, " IoBase 0x%x\n", yp->iobase);
768 seq_printf(seq, " BaudRate %u\n", yp->baudrate);
769 seq_printf(seq, " IRQ %u\n", yp->irq);
770 seq_printf(seq, " TxState %u\n", yp->tx_state);
771 seq_printf(seq, " Duplex %u\n", yp->dupmode);
772 seq_printf(seq, " HoldDly %u\n", yp->holdd);
773 seq_printf(seq, " TxDelay %u\n", yp->txd);
774 seq_printf(seq, " TxTail %u\n", yp->txtail);
775 seq_printf(seq, " SlotTime %u\n", yp->slot);
776 seq_printf(seq, " Persist %u\n", yp->pers);
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000777 seq_printf(seq, " TxFrames %lu\n", dev->stats.tx_packets);
778 seq_printf(seq, " RxFrames %lu\n", dev->stats.rx_packets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 seq_printf(seq, " TxInt %u\n", yp->nb_mdint);
780 seq_printf(seq, " RxInt %u\n", yp->nb_rxint);
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000781 seq_printf(seq, " RxOver %lu\n", dev->stats.rx_fifo_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 seq_printf(seq, "\n");
783 return 0;
784}
785
786static struct seq_operations yam_seqops = {
787 .start = yam_seq_start,
788 .next = yam_seq_next,
789 .stop = yam_seq_stop,
790 .show = yam_seq_show,
791};
792
793static int yam_info_open(struct inode *inode, struct file *file)
794{
795 return seq_open(file, &yam_seqops);
796}
797
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800798static const struct file_operations yam_info_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 .owner = THIS_MODULE,
800 .open = yam_info_open,
801 .read = seq_read,
802 .llseek = seq_lseek,
803 .release = seq_release,
804};
805
806#endif
807
808
809/* --------------------------------------------------------------------- */
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811static int yam_open(struct net_device *dev)
812{
813 struct yam_port *yp = netdev_priv(dev);
814 enum uart u;
815 int i;
816 int ret=0;
817
818 printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq);
819
820 if (!dev || !yp->bitrate)
821 return -ENXIO;
822 if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT ||
823 dev->irq < 2 || dev->irq > 15) {
824 return -ENXIO;
825 }
826 if (!request_region(dev->base_addr, YAM_EXTENT, dev->name))
827 {
828 printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
829 return -EACCES;
830 }
831 if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) {
832 printk(KERN_ERR "%s: cannot find uart type\n", dev->name);
833 ret = -EIO;
834 goto out_release_base;
835 }
836 if (fpga_download(dev->base_addr, yp->bitrate)) {
837 printk(KERN_ERR "%s: cannot init FPGA\n", dev->name);
838 ret = -EIO;
839 goto out_release_base;
840 }
841 outb(0, IER(dev->base_addr));
Thomas Gleixner1fb9df52006-07-01 19:29:39 -0700842 if (request_irq(dev->irq, yam_interrupt, IRQF_DISABLED | IRQF_SHARED, dev->name, dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq);
844 ret = -EBUSY;
845 goto out_release_base;
846 }
847
848 yam_set_uart(dev);
849
850 netif_start_queue(dev);
851
852 yp->slotcnt = yp->slot / 10;
853
854 /* Reset overruns for all ports - FPGA programming makes overruns */
855 for (i = 0; i < NR_PORTS; i++) {
856 struct net_device *dev = yam_devs[i];
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 inb(LSR(dev->base_addr));
Stephen Hemminger3c94acb2009-01-09 13:01:37 +0000859 dev->stats.rx_fifo_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861
862 printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq,
863 uart_str[u]);
864 return 0;
865
866out_release_base:
867 release_region(dev->base_addr, YAM_EXTENT);
868 return ret;
869}
870
871/* --------------------------------------------------------------------- */
872
873static int yam_close(struct net_device *dev)
874{
875 struct sk_buff *skb;
876 struct yam_port *yp = netdev_priv(dev);
877
878 if (!dev)
879 return -EINVAL;
880
881 /*
882 * disable interrupts
883 */
884 outb(0, IER(dev->base_addr));
885 outb(1, MCR(dev->base_addr));
886 /* Remove IRQ handler if last */
887 free_irq(dev->irq,dev);
888 release_region(dev->base_addr, YAM_EXTENT);
889 netif_stop_queue(dev);
890 while ((skb = skb_dequeue(&yp->send_queue)))
891 dev_kfree_skb(skb);
892
893 printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n",
894 yam_drvname, dev->base_addr, dev->irq);
895 return 0;
896}
897
898/* --------------------------------------------------------------------- */
899
900static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
901{
902 struct yam_port *yp = netdev_priv(dev);
903 struct yamdrv_ioctl_cfg yi;
904 struct yamdrv_ioctl_mcs *ym;
905 int ioctl_cmd;
906
907 if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int)))
908 return -EFAULT;
909
910 if (yp->magic != YAM_MAGIC)
911 return -EINVAL;
912
913 if (!capable(CAP_NET_ADMIN))
914 return -EPERM;
915
916 if (cmd != SIOCDEVPRIVATE)
917 return -EINVAL;
918
919 switch (ioctl_cmd) {
920
921 case SIOCYAMRESERVED:
922 return -EINVAL; /* unused */
923
924 case SIOCYAMSMCS:
925 if (netif_running(dev))
926 return -EINVAL; /* Cannot change this parameter when up */
927 if ((ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_KERNEL)) == NULL)
928 return -ENOBUFS;
929 ym->bitrate = 9600;
930 if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs))) {
931 kfree(ym);
932 return -EFAULT;
933 }
934 if (ym->bitrate > YAM_MAXBITRATE) {
935 kfree(ym);
936 return -EINVAL;
937 }
938 add_mcs(ym->bits, ym->bitrate);
939 kfree(ym);
940 break;
941
942 case SIOCYAMSCFG:
943 if (!capable(CAP_SYS_RAWIO))
944 return -EPERM;
945 if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
946 return -EFAULT;
947
948 if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev))
949 return -EINVAL; /* Cannot change this parameter when up */
950 if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev))
951 return -EINVAL; /* Cannot change this parameter when up */
952 if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev))
953 return -EINVAL; /* Cannot change this parameter when up */
954 if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev))
955 return -EINVAL; /* Cannot change this parameter when up */
956
957 if (yi.cfg.mask & YAM_IOBASE) {
958 yp->iobase = yi.cfg.iobase;
959 dev->base_addr = yi.cfg.iobase;
960 }
961 if (yi.cfg.mask & YAM_IRQ) {
962 if (yi.cfg.irq > 15)
963 return -EINVAL;
964 yp->irq = yi.cfg.irq;
965 dev->irq = yi.cfg.irq;
966 }
967 if (yi.cfg.mask & YAM_BITRATE) {
968 if (yi.cfg.bitrate > YAM_MAXBITRATE)
969 return -EINVAL;
970 yp->bitrate = yi.cfg.bitrate;
971 }
972 if (yi.cfg.mask & YAM_BAUDRATE) {
973 if (yi.cfg.baudrate > YAM_MAXBAUDRATE)
974 return -EINVAL;
975 yp->baudrate = yi.cfg.baudrate;
976 }
977 if (yi.cfg.mask & YAM_MODE) {
978 if (yi.cfg.mode > YAM_MAXMODE)
979 return -EINVAL;
980 yp->dupmode = yi.cfg.mode;
981 }
982 if (yi.cfg.mask & YAM_HOLDDLY) {
983 if (yi.cfg.holddly > YAM_MAXHOLDDLY)
984 return -EINVAL;
985 yp->holdd = yi.cfg.holddly;
986 }
987 if (yi.cfg.mask & YAM_TXDELAY) {
988 if (yi.cfg.txdelay > YAM_MAXTXDELAY)
989 return -EINVAL;
990 yp->txd = yi.cfg.txdelay;
991 }
992 if (yi.cfg.mask & YAM_TXTAIL) {
993 if (yi.cfg.txtail > YAM_MAXTXTAIL)
994 return -EINVAL;
995 yp->txtail = yi.cfg.txtail;
996 }
997 if (yi.cfg.mask & YAM_PERSIST) {
998 if (yi.cfg.persist > YAM_MAXPERSIST)
999 return -EINVAL;
1000 yp->pers = yi.cfg.persist;
1001 }
1002 if (yi.cfg.mask & YAM_SLOTTIME) {
1003 if (yi.cfg.slottime > YAM_MAXSLOTTIME)
1004 return -EINVAL;
1005 yp->slot = yi.cfg.slottime;
1006 yp->slotcnt = yp->slot / 10;
1007 }
1008 break;
1009
1010 case SIOCYAMGCFG:
1011 yi.cfg.mask = 0xffffffff;
1012 yi.cfg.iobase = yp->iobase;
1013 yi.cfg.irq = yp->irq;
1014 yi.cfg.bitrate = yp->bitrate;
1015 yi.cfg.baudrate = yp->baudrate;
1016 yi.cfg.mode = yp->dupmode;
1017 yi.cfg.txdelay = yp->txd;
1018 yi.cfg.holddly = yp->holdd;
1019 yi.cfg.txtail = yp->txtail;
1020 yi.cfg.persist = yp->pers;
1021 yi.cfg.slottime = yp->slot;
1022 if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg)))
1023 return -EFAULT;
1024 break;
1025
1026 default:
1027 return -EINVAL;
1028
1029 }
1030
1031 return 0;
1032}
1033
1034/* --------------------------------------------------------------------- */
1035
1036static int yam_set_mac_address(struct net_device *dev, void *addr)
1037{
1038 struct sockaddr *sa = (struct sockaddr *) addr;
1039
1040 /* addr is an AX.25 shifted ASCII mac address */
1041 memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
1042 return 0;
1043}
1044
1045/* --------------------------------------------------------------------- */
1046
1047static void yam_setup(struct net_device *dev)
1048{
1049 struct yam_port *yp = netdev_priv(dev);
1050
1051 yp->magic = YAM_MAGIC;
1052 yp->bitrate = DEFAULT_BITRATE;
1053 yp->baudrate = DEFAULT_BITRATE * 2;
1054 yp->iobase = 0;
1055 yp->irq = 0;
1056 yp->dupmode = 0;
1057 yp->holdd = DEFAULT_HOLDD;
1058 yp->txd = DEFAULT_TXD;
1059 yp->txtail = DEFAULT_TXTAIL;
1060 yp->slot = DEFAULT_SLOT;
1061 yp->pers = DEFAULT_PERS;
1062 yp->dev = dev;
1063
1064 dev->base_addr = yp->iobase;
1065 dev->irq = yp->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 dev->open = yam_open;
1068 dev->stop = yam_close;
1069 dev->do_ioctl = yam_ioctl;
1070 dev->hard_start_xmit = yam_send_packet;
1071 dev->get_stats = yam_get_stats;
1072
1073 skb_queue_head_init(&yp->send_queue);
1074
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001075 dev->header_ops = &ax25_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 dev->set_mac_address = yam_set_mac_address;
1078
Ralf Baechlec4bc7ee2005-09-12 14:19:26 -07001079 dev->type = ARPHRD_AX25;
1080 dev->hard_header_len = AX25_MAX_HEADER_LEN;
1081 dev->mtu = AX25_MTU;
1082 dev->addr_len = AX25_ADDR_LEN;
Ralf Baechle15b1c0e2006-12-07 15:47:08 -08001083 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
1084 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085}
1086
1087static int __init yam_init_driver(void)
1088{
1089 struct net_device *dev;
1090 int i, err;
1091 char name[IFNAMSIZ];
1092
1093 printk(yam_drvinfo);
1094
1095 for (i = 0; i < NR_PORTS; i++) {
1096 sprintf(name, "yam%d", i);
1097
1098 dev = alloc_netdev(sizeof(struct yam_port), name,
1099 yam_setup);
1100 if (!dev) {
1101 printk(KERN_ERR "yam: cannot allocate net device %s\n",
1102 dev->name);
1103 err = -ENOMEM;
1104 goto error;
1105 }
1106
1107 err = register_netdev(dev);
1108 if (err) {
1109 printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
1110 goto error;
1111 }
1112 yam_devs[i] = dev;
1113
1114 }
1115
1116 yam_timer.function = yam_dotimer;
1117 yam_timer.expires = jiffies + HZ / 100;
1118 add_timer(&yam_timer);
1119
Eric W. Biederman457c4cb2007-09-12 12:01:34 +02001120 proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 return 0;
1122 error:
1123 while (--i >= 0) {
1124 unregister_netdev(yam_devs[i]);
1125 free_netdev(yam_devs[i]);
1126 }
1127 return err;
1128}
1129
1130/* --------------------------------------------------------------------- */
1131
1132static void __exit yam_cleanup_driver(void)
1133{
1134 struct yam_mcs *p;
1135 int i;
1136
1137 del_timer(&yam_timer);
1138 for (i = 0; i < NR_PORTS; i++) {
1139 struct net_device *dev = yam_devs[i];
1140 if (dev) {
1141 unregister_netdev(dev);
1142 free_netdev(dev);
1143 }
1144 }
1145
1146 while (yam_data) {
1147 p = yam_data;
1148 yam_data = yam_data->next;
1149 kfree(p);
1150 }
1151
Eric W. Biederman457c4cb2007-09-12 12:01:34 +02001152 proc_net_remove(&init_net, "yam");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153}
1154
1155/* --------------------------------------------------------------------- */
1156
1157MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
1158MODULE_DESCRIPTION("Yam amateur radio modem driver");
1159MODULE_LICENSE("GPL");
1160
1161module_init(yam_init_driver);
1162module_exit(yam_cleanup_driver);
1163
1164/* --------------------------------------------------------------------- */
1165