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