* add p cc
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / net / hamradio / yam.c
blob2c468c8c1480fd8f6d2194d1ced345ec7c6a0280
1 /*****************************************************************************/
3 /*
4 * yam.c -- YAM radio modem driver.
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)
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.
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.
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.
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.
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/persistance timing bug
40 /*****************************************************************************/
42 #include <linux/config.h>
43 #include <linux/module.h>
44 #include <linux/types.h>
45 #include <linux/net.h>
46 #include <linux/in.h>
47 #include <linux/if.h>
48 #include <linux/malloc.h>
49 #include <linux/errno.h>
50 #include <asm/bitops.h>
51 #include <asm/io.h>
52 #include <asm/system.h>
53 #include <linux/interrupt.h>
54 #include <linux/ioport.h>
56 #include <linux/netdevice.h>
57 #include <linux/if_arp.h>
58 #include <linux/etherdevice.h>
59 #include <linux/skbuff.h>
60 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
61 /* prototypes for ax25_encapsulate and ax25_rebuild_header */
62 #include <net/ax25.h>
63 #endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
65 /* make genksyms happy */
66 #include <linux/ip.h>
67 #include <linux/udp.h>
68 #include <linux/tcp.h>
70 #include <linux/kernel.h>
71 #include <linux/proc_fs.h>
73 #include <linux/yam.h>
74 #include "yam9600.h"
75 #include "yam1200.h"
77 /* --------------------------------------------------------------------- */
80 * currently this module is supposed to support both module styles, i.e.
81 * the old one present up to about 2.1.9, and the new one functioning
82 * starting with 2.1.21. The reason is I have a kit allowing to compile
83 * this module also under 2.0.x which was requested by several people.
84 * This will go in 2.2
86 #include <linux/version.h>
88 #if LINUX_VERSION_CODE >= 0x20100
89 #include <asm/uaccess.h>
90 #else
91 #include <asm/segment.h>
92 #include <linux/mm.h>
94 #undef put_user
95 #undef get_user
97 #define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
98 #define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
100 extern inline int copy_from_user(void *to, const void *from, unsigned long n)
102 int i = verify_area(VERIFY_READ, from, n);
103 if (i)
104 return i;
105 memcpy_fromfs(to, from, n);
106 return 0;
109 extern inline int copy_to_user(void *to, const void *from, unsigned long n)
111 int i = verify_area(VERIFY_WRITE, to, n);
112 if (i)
113 return i;
114 memcpy_tofs(to, from, n);
115 return 0;
117 #endif
119 #if LINUX_VERSION_CODE < 0x20115
120 extern __inline__ void dev_init_buffers(struct net_device *dev)
122 int i;
123 for (i = 0; i < DEV_NUMBUFFS; i++) {
124 skb_queue_head_init(&dev->buffs[i]);
127 #endif
129 #if LINUX_VERSION_CODE >= 0x20123
130 #include <linux/init.h>
131 #else
132 #define __init
133 #define __initdata
134 #endif
136 /* --------------------------------------------------------------------- */
138 static const char yam_drvname[] = "yam";
139 static const char yam_drvinfo[] = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
141 /* --------------------------------------------------------------------- */
143 #define YAM_9600 1
144 #define YAM_1200 2
146 #define NR_PORTS 4
147 #define YAM_MAGIC 0xF10A7654
149 /* Transmitter states */
151 #define TX_OFF 0
152 #define TX_HEAD 1
153 #define TX_DATA 2
154 #define TX_CRC1 3
155 #define TX_CRC2 4
156 #define TX_TAIL 5
158 #define YAM_MAX_FRAME 1024
160 #define DEFAULT_BITRATE 9600 /* bps */
161 #define DEFAULT_HOLDD 10 /* sec */
162 #define DEFAULT_TXD 300 /* ms */
163 #define DEFAULT_TXTAIL 10 /* ms */
164 #define DEFAULT_SLOT 100 /* ms */
165 #define DEFAULT_PERS 64 /* 0->255 */
167 struct yam_port {
168 int magic;
169 int bitrate;
170 int baudrate;
171 int iobase;
172 int irq;
173 int dupmode;
174 char name[16];
176 struct net_device dev;
178 /* Stats section */
180 #if LINUX_VERSION_CODE < 0x20119
181 struct enet_statistics stats;
182 #else
183 struct net_device_stats stats;
184 #endif
185 int nb_rxint;
186 int nb_mdint;
188 /* Parameters section */
190 int txd; /* tx delay */
191 int holdd; /* duplex ptt delay */
192 int txtail; /* txtail delay */
193 int slot; /* slottime */
194 int pers; /* persistence */
196 /* Tx section */
198 int tx_state;
199 int tx_count;
200 int slotcnt;
201 unsigned char tx_buf[YAM_MAX_FRAME];
202 int tx_len;
203 int tx_crcl, tx_crch;
204 struct sk_buff_head send_queue; /* Packets awaiting transmission */
206 /* Rx section */
208 int dcd;
209 unsigned char rx_buf[YAM_MAX_FRAME];
210 int rx_len;
211 int rx_crcl, rx_crch;
214 struct yam_mcs {
215 unsigned char bits[YAM_FPGA_SIZE];
216 int bitrate;
217 struct yam_mcs *next;
220 static struct yam_port yam_ports[NR_PORTS];
222 static struct yam_mcs *yam_data = NULL;
224 static unsigned irqs[16];
226 static char ax25_bcast[7] =
227 {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
228 static char ax25_test[7] =
229 {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
231 static struct timer_list yam_timer;
233 /* --------------------------------------------------------------------- */
235 #define RBR(iobase) (iobase+0)
236 #define THR(iobase) (iobase+0)
237 #define IER(iobase) (iobase+1)
238 #define IIR(iobase) (iobase+2)
239 #define FCR(iobase) (iobase+2)
240 #define LCR(iobase) (iobase+3)
241 #define MCR(iobase) (iobase+4)
242 #define LSR(iobase) (iobase+5)
243 #define MSR(iobase) (iobase+6)
244 #define SCR(iobase) (iobase+7)
245 #define DLL(iobase) (iobase+0)
246 #define DLM(iobase) (iobase+1)
248 #define YAM_EXTENT 8
250 /* Interrupt Identification Register Bit Masks */
251 #define IIR_NOPEND 1
252 #define IIR_MSR 0
253 #define IIR_TX 2
254 #define IIR_RX 4
255 #define IIR_LSR 6
256 #define IIR_TIMEOUT 12 /* Fifo mode only */
258 #define IIR_MASK 0x0F
260 /* Interrupt Enable Register Bit Masks */
261 #define IER_RX 1 /* enable rx interrupt */
262 #define IER_TX 2 /* enable tx interrupt */
263 #define IER_LSR 4 /* enable line status interrupts */
264 #define IER_MSR 8 /* enable modem status interrupts */
266 /* Modem Control Register Bit Masks */
267 #define MCR_DTR 0x01 /* DTR output */
268 #define MCR_RTS 0x02 /* RTS output */
269 #define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */
270 #define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */
271 #define MCR_LOOP 0x10 /* Loopback enable */
273 /* Modem Status Register Bit Masks */
274 #define MSR_DCTS 0x01 /* Delta CTS input */
275 #define MSR_DDSR 0x02 /* Delta DSR */
276 #define MSR_DRIN 0x04 /* Delta RI */
277 #define MSR_DDCD 0x08 /* Delta DCD */
278 #define MSR_CTS 0x10 /* CTS input */
279 #define MSR_DSR 0x20 /* DSR input */
280 #define MSR_RING 0x40 /* RI input */
281 #define MSR_DCD 0x80 /* DCD input */
283 /* line status register bit mask */
284 #define LSR_RXC 0x01
285 #define LSR_OE 0x02
286 #define LSR_PE 0x04
287 #define LSR_FE 0x08
288 #define LSR_BREAK 0x10
289 #define LSR_THRE 0x20
290 #define LSR_TSRE 0x40
292 /* Line Control Register Bit Masks */
293 #define LCR_DLAB 0x80
294 #define LCR_BREAK 0x40
295 #define LCR_PZERO 0x28
296 #define LCR_PEVEN 0x18
297 #define LCR_PODD 0x08
298 #define LCR_STOP1 0x00
299 #define LCR_STOP2 0x04
300 #define LCR_BIT5 0x00
301 #define LCR_BIT6 0x02
302 #define LCR_BIT7 0x01
303 #define LCR_BIT8 0x03
305 /* YAM Modem <-> UART Port mapping */
307 #define TX_RDY MSR_DCTS /* transmitter ready to send */
308 #define RX_DCD MSR_DCD /* carrier detect */
309 #define RX_FLAG MSR_RING /* hdlc flag received */
310 #define FPGA_DONE MSR_DSR /* FPGA is configured */
311 #define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */
312 #define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */
314 #define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */
315 #define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */
316 #define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */
318 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
319 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
321 /*************************************************************************
322 * CRC Tables
323 ************************************************************************/
325 static const unsigned char chktabl[256] =
326 {0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e,
327 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64,
328 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e,
329 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50,
330 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e,
331 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44,
332 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e,
333 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38,
334 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e,
335 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24,
336 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e,
337 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10,
338 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e,
339 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04,
340 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e,
341 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9,
342 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1,
343 0x78};
344 static const unsigned char chktabh[256] =
345 {0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9,
346 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb,
347 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb,
348 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f,
349 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed,
350 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf,
351 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef,
352 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07,
353 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1,
354 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3,
355 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3,
356 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87,
357 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5,
358 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7,
359 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7,
360 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f,
361 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e,
362 0x0f};
364 /*************************************************************************
365 * FPGA functions
366 ************************************************************************/
368 static void delay(int ms)
370 unsigned long timeout = jiffies + ((ms * HZ) / 1000);
371 while (jiffies < timeout);
375 * reset FPGA
378 static void fpga_reset(int iobase)
380 outb(0, IER(iobase));
381 outb(LCR_DLAB | LCR_BIT5, LCR(iobase));
382 outb(1, DLL(iobase));
383 outb(0, DLM(iobase));
385 outb(LCR_BIT5, LCR(iobase));
386 inb(LSR(iobase));
387 inb(MSR(iobase));
388 /* turn off FPGA supply voltage */
389 outb(MCR_OUT1 | MCR_OUT2, MCR(iobase));
390 delay(100);
391 /* turn on FPGA supply voltage again */
392 outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase));
393 delay(100);
397 * send one byte to FPGA
400 static int fpga_write(int iobase, unsigned char wrd)
402 unsigned char bit;
403 int k;
404 unsigned long timeout = jiffies + HZ / 10;
406 for (k = 0; k < 8; k++) {
407 bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR;
408 outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase));
409 wrd <<= 1;
410 outb(0xfc, THR(iobase));
411 while ((inb(LSR(iobase)) & LSR_TSRE) == 0)
412 if (jiffies > timeout)
413 return -1;
416 return 0;
419 #ifdef MODULE
420 static void free_mcs(void)
422 struct yam_mcs *p;
424 while (yam_data) {
425 p = yam_data;
426 yam_data = yam_data->next;
427 kfree(p);
430 #endif
432 static unsigned char *
433 add_mcs(unsigned char *bits, int bitrate)
435 struct yam_mcs *p;
437 /* If it already exists, replace the bit data */
438 p = yam_data;
439 while (p) {
440 if (p->bitrate == bitrate) {
441 memcpy(p->bits, bits, YAM_FPGA_SIZE);
442 return p->bits;
444 p = p->next;
447 /* Allocate a new mcs */
448 p = kmalloc(sizeof(struct yam_mcs), GFP_ATOMIC);
449 if (p == NULL) {
450 printk(KERN_WARNING "YAM: no memory to allocate mcs\n");
451 return NULL;
453 memcpy(p->bits, bits, YAM_FPGA_SIZE);
454 p->bitrate = bitrate;
455 p->next = yam_data;
456 yam_data = p;
458 return p->bits;
461 static unsigned char *get_mcs(int bitrate)
463 struct yam_mcs *p;
465 p = yam_data;
466 while (p) {
467 if (p->bitrate == bitrate)
468 return p->bits;
469 p = p->next;
472 /* Load predefined mcs data */
473 switch (bitrate) {
474 case 1200:
475 return add_mcs(bits_1200, bitrate);
476 default:
477 return add_mcs(bits_9600, bitrate);
482 * download bitstream to FPGA
483 * data is contained in bits[] array in fpgaconf.h
486 static int fpga_download(int iobase, int bitrate)
488 int i, rc;
489 unsigned char *pbits;
491 pbits = get_mcs(bitrate);
492 if (pbits == NULL)
493 return -1;
495 fpga_reset(iobase);
496 for (i = 0; i < YAM_FPGA_SIZE; i++) {
497 if (fpga_write(iobase, pbits[i])) {
498 printk("yam: error in write cycle\n");
499 return -1; /* write... */
503 fpga_write(iobase, 0xFF);
504 rc = inb(MSR(iobase)); /* check DONE signal */
506 /* Needed for some hardwares */
507 delay(50);
509 return (rc & MSR_DSR) ? 0 : -1;
513 /************************************************************************
514 * Serial port init
515 ************************************************************************/
517 static void yam_set_uart(struct net_device *dev)
519 struct yam_port *yp = (struct yam_port *) dev->priv;
520 int divisor = 115200 / yp->baudrate;
522 outb(0, IER(dev->base_addr));
523 outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr));
524 outb(divisor, DLL(dev->base_addr));
525 outb(0, DLM(dev->base_addr));
526 outb(LCR_BIT8, LCR(dev->base_addr));
527 outb(PTT_OFF, MCR(dev->base_addr));
528 outb(0x00, FCR(dev->base_addr));
530 /* Flush pending irq */
532 inb(RBR(dev->base_addr));
533 inb(MSR(dev->base_addr));
535 /* Enable rx irq */
537 outb(ENABLE_RTXINT, IER(dev->base_addr));
541 /* --------------------------------------------------------------------- */
543 enum uart {
544 c_uart_unknown, c_uart_8250,
545 c_uart_16450, c_uart_16550, c_uart_16550A
548 static const char *uart_str[] =
549 {"unknown", "8250", "16450", "16550", "16550A"};
551 static enum uart yam_check_uart(unsigned int iobase)
553 unsigned char b1, b2, b3;
554 enum uart u;
555 enum uart uart_tab[] =
556 {c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A};
558 b1 = inb(MCR(iobase));
559 outb(b1 | 0x10, MCR(iobase)); /* loopback mode */
560 b2 = inb(MSR(iobase));
561 outb(0x1a, MCR(iobase));
562 b3 = inb(MSR(iobase)) & 0xf0;
563 outb(b1, MCR(iobase)); /* restore old values */
564 outb(b2, MSR(iobase));
565 if (b3 != 0x90)
566 return c_uart_unknown;
567 inb(RBR(iobase));
568 inb(RBR(iobase));
569 outb(0x01, FCR(iobase)); /* enable FIFOs */
570 u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
571 if (u == c_uart_16450) {
572 outb(0x5a, SCR(iobase));
573 b1 = inb(SCR(iobase));
574 outb(0xa5, SCR(iobase));
575 b2 = inb(SCR(iobase));
576 if ((b1 != 0x5a) || (b2 != 0xa5))
577 u = c_uart_8250;
579 return u;
582 /******************************************************************************
583 * Rx Section
584 ******************************************************************************/
585 static void inline
586 yam_rx_flag(struct net_device *dev, struct yam_port *yp)
588 if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) {
589 int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */
590 struct sk_buff *skb;
592 if ((yp->rx_crch & yp->rx_crcl) != 0xFF) {
593 /* Bad crc */
594 } else {
595 if (!(skb = dev_alloc_skb(pkt_len))) {
596 printk("%s: memory squeeze, dropping packet\n", dev->name);
597 ++yp->stats.rx_dropped;
598 } else {
599 unsigned char *cp;
600 skb->dev = dev;
601 cp = skb_put(skb, pkt_len);
602 *cp++ = 0; /* KISS kludge */
603 memcpy(cp, yp->rx_buf, pkt_len - 1);
604 skb->protocol = htons(ETH_P_AX25);
605 skb->mac.raw = skb->data;
606 netif_rx(skb);
607 ++yp->stats.rx_packets;
611 yp->rx_len = 0;
612 yp->rx_crcl = 0x21;
613 yp->rx_crch = 0xf3;
616 static void inline
617 yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb)
619 if (yp->rx_len < YAM_MAX_FRAME) {
620 unsigned char c = yp->rx_crcl;
621 yp->rx_crcl = (chktabl[c] ^ yp->rx_crch);
622 yp->rx_crch = (chktabh[c] ^ rxb);
623 yp->rx_buf[yp->rx_len++] = rxb;
627 /********************************************************************************
628 * TX Section
629 ********************************************************************************/
631 static void ptt_on(struct net_device *dev)
633 outb(PTT_ON, MCR(dev->base_addr));
636 static void ptt_off(struct net_device *dev)
638 outb(PTT_OFF, MCR(dev->base_addr));
641 static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
643 struct yam_port *yp = dev->priv;
645 if (skb == NULL) {
646 return 0;
648 skb_queue_tail(&yp->send_queue, skb);
649 dev->trans_start = jiffies;
650 return 0;
653 static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
655 if ((yp->tx_state == TX_TAIL) || (yp->txd == 0))
656 yp->tx_count = 1;
657 else
658 yp->tx_count = (yp->bitrate * yp->txd) / 8000;
659 yp->tx_state = TX_HEAD;
660 ptt_on(dev);
663 static unsigned short random_seed;
665 static inline unsigned short random_num(void)
667 random_seed = 28629 * random_seed + 157;
668 return random_seed;
671 static void yam_arbitrate(struct net_device *dev)
673 struct yam_port *yp = dev->priv;
675 if (!yp || yp->magic != YAM_MAGIC
676 || yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) {
677 return;
679 /* tx_state is TX_OFF and there is data to send */
681 if (yp->dupmode) {
682 /* Full duplex mode, don't wait */
683 yam_start_tx(dev, yp);
684 return;
686 if (yp->dcd) {
687 /* DCD on, wait slotime ... */
688 yp->slotcnt = yp->slot / 10;
689 return;
691 /* Is slottime passed ? */
692 if ((--yp->slotcnt) > 0)
693 return;
695 yp->slotcnt = yp->slot / 10;
697 /* is random > persist ? */
698 if ((random_num() % 256) > yp->pers)
699 return;
701 yam_start_tx(dev, yp);
704 static void yam_dotimer(unsigned long dummy)
706 int i;
708 for (i = 0; i < NR_PORTS; i++) {
709 struct net_device *dev = &yam_ports[i].dev;
710 if (dev->start)
711 yam_arbitrate(dev);
713 yam_timer.expires = jiffies + HZ / 100;
714 add_timer(&yam_timer);
717 static void yam_tx_byte(struct net_device *dev, struct yam_port *yp)
719 struct sk_buff *skb;
720 unsigned char b, temp;
722 switch (yp->tx_state) {
723 case TX_OFF:
724 break;
725 case TX_HEAD:
726 if (--yp->tx_count <= 0) {
727 if (!(skb = skb_dequeue(&yp->send_queue))) {
728 ptt_off(dev);
729 yp->tx_state = TX_OFF;
730 break;
732 yp->tx_state = TX_DATA;
733 if (skb->data[0] != 0) {
734 /* do_kiss_params(s, skb->data, skb->len); */
735 dev_kfree_skb(skb);
736 break;
738 yp->tx_len = skb->len - 1; /* strip KISS byte */
739 if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) {
740 dev_kfree_skb(skb);
741 break;
743 memcpy(yp->tx_buf, skb->data + 1, yp->tx_len);
744 dev_kfree_skb(skb);
745 yp->tx_count = 0;
746 yp->tx_crcl = 0x21;
747 yp->tx_crch = 0xf3;
748 yp->tx_state = TX_DATA;
750 break;
751 case TX_DATA:
752 b = yp->tx_buf[yp->tx_count++];
753 outb(b, THR(dev->base_addr));
754 temp = yp->tx_crcl;
755 yp->tx_crcl = chktabl[temp] ^ yp->tx_crch;
756 yp->tx_crch = chktabh[temp] ^ b;
757 if (yp->tx_count >= yp->tx_len) {
758 yp->tx_state = TX_CRC1;
760 break;
761 case TX_CRC1:
762 yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch;
763 yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff;
764 outb(yp->tx_crcl, THR(dev->base_addr));
765 yp->tx_state = TX_CRC2;
766 break;
767 case TX_CRC2:
768 outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr));
769 if (skb_queue_empty(&yp->send_queue)) {
770 yp->tx_count = (yp->bitrate * yp->txtail) / 8000;
771 if (yp->dupmode == 2)
772 yp->tx_count += (yp->bitrate * yp->holdd) / 8;
773 if (yp->tx_count == 0)
774 yp->tx_count = 1;
775 yp->tx_state = TX_TAIL;
776 } else {
777 yp->tx_count = 1;
778 yp->tx_state = TX_HEAD;
780 ++yp->stats.tx_packets;
781 break;
782 case TX_TAIL:
783 if (--yp->tx_count <= 0) {
784 yp->tx_state = TX_OFF;
785 ptt_off(dev);
787 break;
791 /***********************************************************************************
792 * ISR routine
793 ************************************************************************************/
795 static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs)
797 struct net_device *dev;
798 struct yam_port *yp;
799 unsigned char iir;
800 int counter = 100;
801 int i;
803 sti();
805 for (i = 0; i < NR_PORTS; i++) {
806 yp = &yam_ports[i];
807 dev = &yp->dev;
809 if (!dev->start)
810 continue;
812 while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
813 unsigned char msr = inb(MSR(dev->base_addr));
814 unsigned char lsr = inb(LSR(dev->base_addr));
815 unsigned char rxb;
817 if (lsr & LSR_OE)
818 ++yp->stats.rx_fifo_errors;
820 yp->dcd = (msr & RX_DCD) ? 1 : 0;
822 if (--counter <= 0) {
823 printk("%s: too many irq iir=%d\n", dev->name, iir);
824 return;
826 if (msr & TX_RDY) {
827 ++yp->nb_mdint;
828 yam_tx_byte(dev, yp);
830 if (lsr & LSR_RXC) {
831 ++yp->nb_rxint;
832 rxb = inb(RBR(dev->base_addr));
833 if (msr & RX_FLAG)
834 yam_rx_flag(dev, yp);
835 else
836 yam_rx_byte(dev, yp, rxb);
842 static int yam_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
844 int len = 0;
845 int i;
846 off_t pos = 0;
847 off_t begin = 0;
849 cli();
851 for (i = 0; i < NR_PORTS; i++) {
852 if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
853 continue;
854 len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
855 len += sprintf(buffer + len, " Up %d\n", yam_ports[i].dev.start);
856 len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate);
857 len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase);
858 len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate);
859 len += sprintf(buffer + len, " IRQ %u\n", yam_ports[i].irq);
860 len += sprintf(buffer + len, " TxState %u\n", yam_ports[i].tx_state);
861 len += sprintf(buffer + len, " Duplex %u\n", yam_ports[i].dupmode);
862 len += sprintf(buffer + len, " HoldDly %u\n", yam_ports[i].holdd);
863 len += sprintf(buffer + len, " TxDelay %u\n", yam_ports[i].txd);
864 len += sprintf(buffer + len, " TxTail %u\n", yam_ports[i].txtail);
865 len += sprintf(buffer + len, " SlotTime %u\n", yam_ports[i].slot);
866 len += sprintf(buffer + len, " Persist %u\n", yam_ports[i].pers);
867 len += sprintf(buffer + len, " TxFrames %lu\n", yam_ports[i].stats.tx_packets);
868 len += sprintf(buffer + len, " RxFrames %lu\n", yam_ports[i].stats.rx_packets);
869 len += sprintf(buffer + len, " TxInt %u\n", yam_ports[i].nb_mdint);
870 len += sprintf(buffer + len, " RxInt %u\n", yam_ports[i].nb_rxint);
871 len += sprintf(buffer + len, " RxOver %lu\n", yam_ports[i].stats.rx_fifo_errors);
872 len += sprintf(buffer + len, "\n");
874 pos = begin + len;
876 if (pos < offset) {
877 len = 0;
878 begin = pos;
880 if (pos > offset + length)
881 break;
884 sti();
886 *start = buffer + (offset - begin);
887 len -= (offset - begin);
889 if (len > length)
890 len = length;
892 return len;
895 #ifdef CONFIG_INET
897 #ifndef PROC_NET_YAM
898 #define PROC_NET_YAM (PROC_NET_LAST+10) /* Sorry again... */
899 #endif
901 #ifdef CONFIG_PROC_FS
902 struct proc_dir_entry yam_proc_dir_entry =
904 PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0,
905 &proc_net_inode_operations, yam_net_get_info
908 #define yam_net_procfs_init() proc_net_register(&yam_proc_dir_entry);
909 #define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM);
910 #else
911 #define yam_net_procfs_init()
912 #define yam_net_procfs_remove()
913 #endif
914 #else
915 #define yam_net_procfs_init()
916 #define yam_net_procfs_remove()
917 #endif
919 /* --------------------------------------------------------------------- */
921 #if LINUX_VERSION_CODE >= 0x20119
922 static struct net_device_stats *
923 yam_get_stats(struct net_device *dev)
924 #else
925 static struct enet_statistics *
926 yam_get_stats(struct net_device *dev)
927 #endif
929 struct yam_port *yp;
931 if (!dev || !dev->priv)
932 return NULL;
934 yp = (struct yam_port *) dev->priv;
935 if (yp->magic != YAM_MAGIC)
936 return NULL;
939 * Get the current statistics. This may be called with the
940 * card open or closed.
942 return &yp->stats;
945 /* --------------------------------------------------------------------- */
947 static int yam_open(struct net_device *dev)
949 struct yam_port *yp = (struct yam_port *) dev->priv;
950 enum uart u;
951 int i;
953 printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq);
955 if (!dev || !yp || !yp->bitrate)
956 return -ENXIO;
957 if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT ||
958 dev->irq < 2 || dev->irq > 15) {
959 return -ENXIO;
961 if (check_region(dev->base_addr, YAM_EXTENT)) {
962 printk("%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
963 return -EACCES;
965 if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) {
966 printk("%s: cannot find uart type\n", dev->name);
967 return -EIO;
969 if (fpga_download(dev->base_addr, yp->bitrate)) {
970 printk("%s: cannot init FPGA\n", dev->name);
971 return -EIO;
973 outb(0, IER(dev->base_addr));
974 if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, NULL)) {
975 printk("%s: irq %d busy\n", dev->name, dev->irq);
976 return -EBUSY;
978 request_region(dev->base_addr, YAM_EXTENT, dev->name);
980 yam_set_uart(dev);
981 dev->start = 1;
982 yp->slotcnt = yp->slot / 10;
984 /* Reset overruns for all ports - FPGA programming makes overruns */
985 for (i = 0; i < NR_PORTS; i++) {
986 inb(LSR(yam_ports[i].dev.base_addr));
987 yam_ports[i].stats.rx_fifo_errors = 0;
990 printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq,
991 uart_str[u]);
992 MOD_INC_USE_COUNT;
993 return 0;
996 /* --------------------------------------------------------------------- */
998 static int yam_close(struct net_device *dev)
1000 struct sk_buff *skb;
1001 struct yam_port *yp = (struct yam_port *) dev->priv;
1003 if (!dev || !yp)
1004 return -EINVAL;
1006 * disable interrupts
1008 outb(0, IER(dev->base_addr));
1009 outb(1, MCR(dev->base_addr));
1010 /* Remove IRQ handler if last */
1011 free_irq(dev->irq, NULL);
1012 release_region(dev->base_addr, YAM_EXTENT);
1013 dev->start = 0;
1014 dev->tbusy = 1;
1015 while ((skb = skb_dequeue(&yp->send_queue)))
1016 dev_kfree_skb(skb);
1018 printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n",
1019 yam_drvname, dev->base_addr, dev->irq);
1020 MOD_DEC_USE_COUNT;
1021 return 0;
1024 /* --------------------------------------------------------------------- */
1026 static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1028 struct yam_port *yp = (struct yam_port *) dev->priv;
1029 struct yamdrv_ioctl_cfg yi;
1030 struct yamdrv_ioctl_mcs *ym;
1031 int ioctl_cmd;
1033 if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int)))
1034 return -EFAULT;
1036 if (yp == NULL || yp->magic != YAM_MAGIC)
1037 return -EINVAL;
1039 if (!suser())
1040 return -EPERM;
1042 if (cmd != SIOCDEVPRIVATE)
1043 return -EINVAL;
1045 switch (ioctl_cmd) {
1047 case SIOCYAMRESERVED:
1048 return -EINVAL; /* unused */
1050 case SIOCYAMSMCS:
1051 if (dev->start)
1052 return -EINVAL; /* Cannot change this parameter when up */
1053 ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
1054 ym->bitrate = 9600;
1055 if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs)))
1056 return -EFAULT;
1057 if (ym->bitrate > YAM_MAXBITRATE)
1058 return -EINVAL;
1059 add_mcs(ym->bits, ym->bitrate);
1060 kfree(ym);
1061 break;
1063 case SIOCYAMSCFG:
1064 if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
1065 return -EFAULT;
1067 if ((yi.cfg.mask & YAM_IOBASE) && dev->start)
1068 return -EINVAL; /* Cannot change this parameter when up */
1069 if ((yi.cfg.mask & YAM_IRQ) && dev->start)
1070 return -EINVAL; /* Cannot change this parameter when up */
1071 if ((yi.cfg.mask & YAM_BITRATE) && dev->start)
1072 return -EINVAL; /* Cannot change this parameter when up */
1073 if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start)
1074 return -EINVAL; /* Cannot change this parameter when up */
1076 if (yi.cfg.mask & YAM_IOBASE) {
1077 yp->iobase = yi.cfg.iobase;
1078 dev->base_addr = yi.cfg.iobase;
1080 if (yi.cfg.mask & YAM_IRQ) {
1081 if (yi.cfg.irq > 15)
1082 return -EINVAL;
1083 yp->irq = yi.cfg.irq;
1084 dev->irq = yi.cfg.irq;
1086 if (yi.cfg.mask & YAM_BITRATE) {
1087 if (yi.cfg.bitrate > YAM_MAXBITRATE)
1088 return -EINVAL;
1089 yp->bitrate = yi.cfg.bitrate;
1091 if (yi.cfg.mask & YAM_BAUDRATE) {
1092 if (yi.cfg.baudrate > YAM_MAXBAUDRATE)
1093 return -EINVAL;
1094 yp->baudrate = yi.cfg.baudrate;
1096 if (yi.cfg.mask & YAM_MODE) {
1097 if (yi.cfg.mode > YAM_MAXMODE)
1098 return -EINVAL;
1099 yp->dupmode = yi.cfg.mode;
1101 if (yi.cfg.mask & YAM_HOLDDLY) {
1102 if (yi.cfg.holddly > YAM_MAXHOLDDLY)
1103 return -EINVAL;
1104 yp->holdd = yi.cfg.holddly;
1106 if (yi.cfg.mask & YAM_TXDELAY) {
1107 if (yi.cfg.txdelay > YAM_MAXTXDELAY)
1108 return -EINVAL;
1109 yp->txd = yi.cfg.txdelay;
1111 if (yi.cfg.mask & YAM_TXTAIL) {
1112 if (yi.cfg.txtail > YAM_MAXTXTAIL)
1113 return -EINVAL;
1114 yp->txtail = yi.cfg.txtail;
1116 if (yi.cfg.mask & YAM_PERSIST) {
1117 if (yi.cfg.persist > YAM_MAXPERSIST)
1118 return -EINVAL;
1119 yp->pers = yi.cfg.persist;
1121 if (yi.cfg.mask & YAM_SLOTTIME) {
1122 if (yi.cfg.slottime > YAM_MAXSLOTTIME)
1123 return -EINVAL;
1124 yp->slot = yi.cfg.slottime;
1125 yp->slotcnt = yp->slot / 10;
1127 break;
1129 case SIOCYAMGCFG:
1130 yi.cfg.mask = 0xffffffff;
1131 yi.cfg.iobase = yp->iobase;
1132 yi.cfg.irq = yp->irq;
1133 yi.cfg.bitrate = yp->bitrate;
1134 yi.cfg.baudrate = yp->baudrate;
1135 yi.cfg.mode = yp->dupmode;
1136 yi.cfg.txdelay = yp->txd;
1137 yi.cfg.holddly = yp->holdd;
1138 yi.cfg.txtail = yp->txtail;
1139 yi.cfg.persist = yp->pers;
1140 yi.cfg.slottime = yp->slot;
1141 if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg)))
1142 return -EFAULT;
1143 break;
1145 default:
1146 return -EINVAL;
1150 return 0;
1153 /* --------------------------------------------------------------------- */
1155 static int yam_set_mac_address(struct net_device *dev, void *addr)
1157 struct sockaddr *sa = (struct sockaddr *) addr;
1159 /* addr is an AX.25 shifted ASCII mac address */
1160 memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
1161 return 0;
1164 /* --------------------------------------------------------------------- */
1166 static int yam_probe(struct net_device *dev)
1168 struct yam_port *yp;
1170 if (!dev)
1171 return -ENXIO;
1173 yp = (struct yam_port *) dev->priv;
1175 dev->open = yam_open;
1176 dev->stop = yam_close;
1177 dev->do_ioctl = yam_ioctl;
1178 dev->hard_start_xmit = yam_send_packet;
1179 dev->get_stats = yam_get_stats;
1181 dev_init_buffers(dev);
1182 skb_queue_head_init(&yp->send_queue);
1184 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
1185 dev->hard_header = ax25_encapsulate;
1186 dev->rebuild_header = ax25_rebuild_header;
1187 #else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
1188 dev->hard_header = NULL;
1189 dev->rebuild_header = NULL;
1190 #endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
1192 dev->set_mac_address = yam_set_mac_address;
1194 dev->type = ARPHRD_AX25; /* AF_AX25 device */
1195 dev->hard_header_len = 73; /* We do digipeaters now */
1196 dev->mtu = 256; /* AX25 is the default */
1197 dev->addr_len = 7; /* sizeof an ax.25 address */
1198 memcpy(dev->broadcast, ax25_bcast, 7);
1199 memcpy(dev->dev_addr, ax25_test, 7);
1201 /* New style flags */
1202 dev->flags = 0;
1204 return 0;
1207 /* --------------------------------------------------------------------- */
1209 int __init yam_init(struct net_device *dev)
1211 int i;
1213 printk(yam_drvinfo);
1215 /* Clears the IRQ table */
1216 memset(irqs, 0, sizeof(irqs));
1217 memset(yam_ports, 0, sizeof(yam_ports));
1219 for (i = 0; i < NR_PORTS; i++) {
1220 sprintf(yam_ports[i].name, "yam%d", i);
1221 yam_ports[i].magic = YAM_MAGIC;
1222 yam_ports[i].bitrate = DEFAULT_BITRATE;
1223 yam_ports[i].baudrate = DEFAULT_BITRATE * 2;
1224 yam_ports[i].iobase = 0;
1225 yam_ports[i].irq = 0;
1226 yam_ports[i].dupmode = 0;
1227 yam_ports[i].holdd = DEFAULT_HOLDD;
1228 yam_ports[i].txd = DEFAULT_TXD;
1229 yam_ports[i].txtail = DEFAULT_TXTAIL;
1230 yam_ports[i].slot = DEFAULT_SLOT;
1231 yam_ports[i].pers = DEFAULT_PERS;
1233 dev = &yam_ports[i].dev;
1235 dev->priv = &yam_ports[i];
1236 dev->name = yam_ports[i].name;
1237 dev->base_addr = yam_ports[i].iobase;
1238 dev->irq = yam_ports[i].irq;
1239 dev->init = yam_probe;
1240 dev->if_port = 0;
1241 dev->start = 0;
1242 dev->tbusy = 1;
1244 if (register_netdev(dev)) {
1245 printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
1246 return -ENXIO;
1250 yam_timer.function = yam_dotimer;
1251 yam_timer.expires = jiffies + HZ / 100;
1252 add_timer(&yam_timer);
1254 yam_net_procfs_init();
1256 /* do not keep this device */
1257 return 1;
1260 /* --------------------------------------------------------------------- */
1262 #ifdef MODULE
1265 * command line settable parameters
1268 #if LINUX_VERSION_CODE >= 0x20115
1270 MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
1271 MODULE_DESCRIPTION("Yam amateur radio modem driver");
1273 #endif
1275 int init_module(void)
1277 int ret = yam_init(NULL);
1279 return (ret == 1) ? 0 : ret;
1282 /* --------------------------------------------------------------------- */
1284 void cleanup_module(void)
1286 int i;
1288 del_timer(&yam_timer);
1289 for (i = 0; i < NR_PORTS; i++) {
1290 struct net_device *dev = &yam_ports[i].dev;
1291 if (!dev->priv)
1292 continue;
1293 if (dev->start)
1294 yam_close(dev);
1295 unregister_netdev(dev);
1297 free_mcs();
1298 yam_net_procfs_remove();
1301 #endif /* MODULE */
1302 /* --------------------------------------------------------------------- */