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/hdlcdrv.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/hdlcdrv.c')
-rw-r--r-- | drivers/net/hamradio/hdlcdrv.c | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c new file mode 100644 index 000000000000..b89959a596d7 --- /dev/null +++ b/drivers/net/hamradio/hdlcdrv.c | |||
@@ -0,0 +1,817 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * hdlcdrv.c -- HDLC packet radio network driver. | ||
5 | * | ||
6 | * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * Please note that the GPL allows you to use the driver, NOT the radio. | ||
23 | * In order to use the radio, you need a license from the communications | ||
24 | * authority of your country. | ||
25 | * | ||
26 | * The driver was derived from Donald Beckers skeleton.c | ||
27 | * Written 1993-94 by Donald Becker. | ||
28 | * | ||
29 | * History: | ||
30 | * 0.1 21.09.1996 Started | ||
31 | * 18.10.1996 Changed to new user space access routines | ||
32 | * (copy_{to,from}_user) | ||
33 | * 0.2 21.11.1996 various small changes | ||
34 | * 0.3 03.03.1997 fixed (hopefully) IP not working with ax.25 as a module | ||
35 | * 0.4 16.04.1997 init code/data tagged | ||
36 | * 0.5 30.07.1997 made HDLC buffers bigger (solves a problem with the | ||
37 | * soundmodem driver) | ||
38 | * 0.6 05.04.1998 add spinlocks | ||
39 | * 0.7 03.08.1999 removed some old compatibility cruft | ||
40 | * 0.8 12.02.2000 adapted to softnet driver interface | ||
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/init.h> | ||
54 | #include <linux/bitops.h> | ||
55 | #include <asm/uaccess.h> | ||
56 | |||
57 | #include <linux/netdevice.h> | ||
58 | #include <linux/if_arp.h> | ||
59 | #include <linux/etherdevice.h> | ||
60 | #include <linux/skbuff.h> | ||
61 | #include <linux/hdlcdrv.h> | ||
62 | /* prototypes for ax25_encapsulate and ax25_rebuild_header */ | ||
63 | #include <net/ax25.h> | ||
64 | |||
65 | /* make genksyms happy */ | ||
66 | #include <linux/ip.h> | ||
67 | #include <linux/udp.h> | ||
68 | #include <linux/tcp.h> | ||
69 | #include <linux/crc-ccitt.h> | ||
70 | |||
71 | /* --------------------------------------------------------------------- */ | ||
72 | |||
73 | /* | ||
74 | * The name of the card. Is used for messages and in the requests for | ||
75 | * io regions, irqs and dma channels | ||
76 | */ | ||
77 | |||
78 | static char ax25_bcast[AX25_ADDR_LEN] = | ||
79 | {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; | ||
80 | static char ax25_nocall[AX25_ADDR_LEN] = | ||
81 | {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; | ||
82 | |||
83 | /* --------------------------------------------------------------------- */ | ||
84 | |||
85 | #define KISS_VERBOSE | ||
86 | |||
87 | /* --------------------------------------------------------------------- */ | ||
88 | |||
89 | #define PARAM_TXDELAY 1 | ||
90 | #define PARAM_PERSIST 2 | ||
91 | #define PARAM_SLOTTIME 3 | ||
92 | #define PARAM_TXTAIL 4 | ||
93 | #define PARAM_FULLDUP 5 | ||
94 | #define PARAM_HARDWARE 6 | ||
95 | #define PARAM_RETURN 255 | ||
96 | |||
97 | /* --------------------------------------------------------------------- */ | ||
98 | /* | ||
99 | * the CRC routines are stolen from WAMPES | ||
100 | * by Dieter Deyke | ||
101 | */ | ||
102 | |||
103 | |||
104 | /*---------------------------------------------------------------------------*/ | ||
105 | |||
106 | static inline void append_crc_ccitt(unsigned char *buffer, int len) | ||
107 | { | ||
108 | unsigned int crc = crc_ccitt(0xffff, buffer, len) ^ 0xffff; | ||
109 | *buffer++ = crc; | ||
110 | *buffer++ = crc >> 8; | ||
111 | } | ||
112 | |||
113 | /*---------------------------------------------------------------------------*/ | ||
114 | |||
115 | static inline int check_crc_ccitt(const unsigned char *buf, int cnt) | ||
116 | { | ||
117 | return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8; | ||
118 | } | ||
119 | |||
120 | /*---------------------------------------------------------------------------*/ | ||
121 | |||
122 | #if 0 | ||
123 | static int calc_crc_ccitt(const unsigned char *buf, int cnt) | ||
124 | { | ||
125 | unsigned int crc = 0xffff; | ||
126 | |||
127 | for (; cnt > 0; cnt--) | ||
128 | crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; | ||
129 | crc ^= 0xffff; | ||
130 | return (crc & 0xffff); | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | /* ---------------------------------------------------------------------- */ | ||
135 | |||
136 | #define tenms_to_2flags(s,tenms) ((tenms * s->par.bitrate) / 100 / 16) | ||
137 | |||
138 | /* ---------------------------------------------------------------------- */ | ||
139 | /* | ||
140 | * The HDLC routines | ||
141 | */ | ||
142 | |||
143 | static int hdlc_rx_add_bytes(struct hdlcdrv_state *s, unsigned int bits, | ||
144 | int num) | ||
145 | { | ||
146 | int added = 0; | ||
147 | |||
148 | while (s->hdlcrx.rx_state && num >= 8) { | ||
149 | if (s->hdlcrx.len >= sizeof(s->hdlcrx.buffer)) { | ||
150 | s->hdlcrx.rx_state = 0; | ||
151 | return 0; | ||
152 | } | ||
153 | *s->hdlcrx.bp++ = bits >> (32-num); | ||
154 | s->hdlcrx.len++; | ||
155 | num -= 8; | ||
156 | added += 8; | ||
157 | } | ||
158 | return added; | ||
159 | } | ||
160 | |||
161 | static void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s) | ||
162 | { | ||
163 | struct sk_buff *skb; | ||
164 | int pkt_len; | ||
165 | unsigned char *cp; | ||
166 | |||
167 | if (s->hdlcrx.len < 4) | ||
168 | return; | ||
169 | if (!check_crc_ccitt(s->hdlcrx.buffer, s->hdlcrx.len)) | ||
170 | return; | ||
171 | pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */ | ||
172 | if (!(skb = dev_alloc_skb(pkt_len))) { | ||
173 | printk("%s: memory squeeze, dropping packet\n", dev->name); | ||
174 | s->stats.rx_dropped++; | ||
175 | return; | ||
176 | } | ||
177 | skb->dev = dev; | ||
178 | cp = skb_put(skb, pkt_len); | ||
179 | *cp++ = 0; /* KISS kludge */ | ||
180 | memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); | ||
181 | skb->protocol = htons(ETH_P_AX25); | ||
182 | skb->mac.raw = skb->data; | ||
183 | netif_rx(skb); | ||
184 | dev->last_rx = jiffies; | ||
185 | s->stats.rx_packets++; | ||
186 | } | ||
187 | |||
188 | void hdlcdrv_receiver(struct net_device *dev, struct hdlcdrv_state *s) | ||
189 | { | ||
190 | int i; | ||
191 | unsigned int mask1, mask2, mask3, mask4, mask5, mask6, word; | ||
192 | |||
193 | if (!s || s->magic != HDLCDRV_MAGIC) | ||
194 | return; | ||
195 | if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) | ||
196 | return; | ||
197 | |||
198 | while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { | ||
199 | word = hdlcdrv_hbuf_get(&s->hdlcrx.hbuf); | ||
200 | |||
201 | #ifdef HDLCDRV_DEBUG | ||
202 | hdlcdrv_add_bitbuffer_word(&s->bitbuf_hdlc, word); | ||
203 | #endif /* HDLCDRV_DEBUG */ | ||
204 | s->hdlcrx.bitstream >>= 16; | ||
205 | s->hdlcrx.bitstream |= word << 16; | ||
206 | s->hdlcrx.bitbuf >>= 16; | ||
207 | s->hdlcrx.bitbuf |= word << 16; | ||
208 | s->hdlcrx.numbits += 16; | ||
209 | for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00, | ||
210 | mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; | ||
211 | i >= 0; | ||
212 | i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, | ||
213 | mask5 <<= 1, mask6 = (mask6 << 1) | 1) { | ||
214 | if ((s->hdlcrx.bitstream & mask1) == mask1) | ||
215 | s->hdlcrx.rx_state = 0; /* abort received */ | ||
216 | else if ((s->hdlcrx.bitstream & mask2) == mask3) { | ||
217 | /* flag received */ | ||
218 | if (s->hdlcrx.rx_state) { | ||
219 | hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf | ||
220 | << (8+i), | ||
221 | s->hdlcrx.numbits | ||
222 | -8-i); | ||
223 | hdlc_rx_flag(dev, s); | ||
224 | } | ||
225 | s->hdlcrx.len = 0; | ||
226 | s->hdlcrx.bp = s->hdlcrx.buffer; | ||
227 | s->hdlcrx.rx_state = 1; | ||
228 | s->hdlcrx.numbits = i; | ||
229 | } else if ((s->hdlcrx.bitstream & mask4) == mask5) { | ||
230 | /* stuffed bit */ | ||
231 | s->hdlcrx.numbits--; | ||
232 | s->hdlcrx.bitbuf = (s->hdlcrx.bitbuf & (~mask6)) | | ||
233 | ((s->hdlcrx.bitbuf & mask6) << 1); | ||
234 | } | ||
235 | } | ||
236 | s->hdlcrx.numbits -= hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf, | ||
237 | s->hdlcrx.numbits); | ||
238 | } | ||
239 | clear_bit(0, &s->hdlcrx.in_hdlc_rx); | ||
240 | } | ||
241 | |||
242 | /* ---------------------------------------------------------------------- */ | ||
243 | |||
244 | static inline void do_kiss_params(struct hdlcdrv_state *s, | ||
245 | unsigned char *data, unsigned long len) | ||
246 | { | ||
247 | |||
248 | #ifdef KISS_VERBOSE | ||
249 | #define PKP(a,b) printk(KERN_INFO "hdlcdrv.c: channel params: " a "\n", b) | ||
250 | #else /* KISS_VERBOSE */ | ||
251 | #define PKP(a,b) | ||
252 | #endif /* KISS_VERBOSE */ | ||
253 | |||
254 | if (len < 2) | ||
255 | return; | ||
256 | switch(data[0]) { | ||
257 | case PARAM_TXDELAY: | ||
258 | s->ch_params.tx_delay = data[1]; | ||
259 | PKP("TX delay = %ums", 10 * s->ch_params.tx_delay); | ||
260 | break; | ||
261 | case PARAM_PERSIST: | ||
262 | s->ch_params.ppersist = data[1]; | ||
263 | PKP("p persistence = %u", s->ch_params.ppersist); | ||
264 | break; | ||
265 | case PARAM_SLOTTIME: | ||
266 | s->ch_params.slottime = data[1]; | ||
267 | PKP("slot time = %ums", s->ch_params.slottime); | ||
268 | break; | ||
269 | case PARAM_TXTAIL: | ||
270 | s->ch_params.tx_tail = data[1]; | ||
271 | PKP("TX tail = %ums", s->ch_params.tx_tail); | ||
272 | break; | ||
273 | case PARAM_FULLDUP: | ||
274 | s->ch_params.fulldup = !!data[1]; | ||
275 | PKP("%s duplex", s->ch_params.fulldup ? "full" : "half"); | ||
276 | break; | ||
277 | default: | ||
278 | break; | ||
279 | } | ||
280 | #undef PKP | ||
281 | } | ||
282 | |||
283 | /* ---------------------------------------------------------------------- */ | ||
284 | |||
285 | void hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s) | ||
286 | { | ||
287 | unsigned int mask1, mask2, mask3; | ||
288 | int i; | ||
289 | struct sk_buff *skb; | ||
290 | int pkt_len; | ||
291 | |||
292 | if (!s || s->magic != HDLCDRV_MAGIC) | ||
293 | return; | ||
294 | if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) | ||
295 | return; | ||
296 | for (;;) { | ||
297 | if (s->hdlctx.numbits >= 16) { | ||
298 | if (hdlcdrv_hbuf_full(&s->hdlctx.hbuf)) { | ||
299 | clear_bit(0, &s->hdlctx.in_hdlc_tx); | ||
300 | return; | ||
301 | } | ||
302 | hdlcdrv_hbuf_put(&s->hdlctx.hbuf, s->hdlctx.bitbuf); | ||
303 | s->hdlctx.bitbuf >>= 16; | ||
304 | s->hdlctx.numbits -= 16; | ||
305 | } | ||
306 | switch (s->hdlctx.tx_state) { | ||
307 | default: | ||
308 | clear_bit(0, &s->hdlctx.in_hdlc_tx); | ||
309 | return; | ||
310 | case 0: | ||
311 | case 1: | ||
312 | if (s->hdlctx.numflags) { | ||
313 | s->hdlctx.numflags--; | ||
314 | s->hdlctx.bitbuf |= | ||
315 | 0x7e7e << s->hdlctx.numbits; | ||
316 | s->hdlctx.numbits += 16; | ||
317 | break; | ||
318 | } | ||
319 | if (s->hdlctx.tx_state == 1) { | ||
320 | clear_bit(0, &s->hdlctx.in_hdlc_tx); | ||
321 | return; | ||
322 | } | ||
323 | if (!(skb = s->skb)) { | ||
324 | int flgs = tenms_to_2flags(s, s->ch_params.tx_tail); | ||
325 | if (flgs < 2) | ||
326 | flgs = 2; | ||
327 | s->hdlctx.tx_state = 1; | ||
328 | s->hdlctx.numflags = flgs; | ||
329 | break; | ||
330 | } | ||
331 | s->skb = NULL; | ||
332 | netif_wake_queue(dev); | ||
333 | pkt_len = skb->len-1; /* strip KISS byte */ | ||
334 | if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { | ||
335 | s->hdlctx.tx_state = 0; | ||
336 | s->hdlctx.numflags = 1; | ||
337 | dev_kfree_skb_irq(skb); | ||
338 | break; | ||
339 | } | ||
340 | memcpy(s->hdlctx.buffer, skb->data+1, pkt_len); | ||
341 | dev_kfree_skb_irq(skb); | ||
342 | s->hdlctx.bp = s->hdlctx.buffer; | ||
343 | append_crc_ccitt(s->hdlctx.buffer, pkt_len); | ||
344 | s->hdlctx.len = pkt_len+2; /* the appended CRC */ | ||
345 | s->hdlctx.tx_state = 2; | ||
346 | s->hdlctx.bitstream = 0; | ||
347 | s->stats.tx_packets++; | ||
348 | break; | ||
349 | case 2: | ||
350 | if (!s->hdlctx.len) { | ||
351 | s->hdlctx.tx_state = 0; | ||
352 | s->hdlctx.numflags = 1; | ||
353 | break; | ||
354 | } | ||
355 | s->hdlctx.len--; | ||
356 | s->hdlctx.bitbuf |= *s->hdlctx.bp << | ||
357 | s->hdlctx.numbits; | ||
358 | s->hdlctx.bitstream >>= 8; | ||
359 | s->hdlctx.bitstream |= (*s->hdlctx.bp++) << 16; | ||
360 | mask1 = 0x1f000; | ||
361 | mask2 = 0x10000; | ||
362 | mask3 = 0xffffffff >> (31-s->hdlctx.numbits); | ||
363 | s->hdlctx.numbits += 8; | ||
364 | for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, | ||
365 | mask3 = (mask3 << 1) | 1) { | ||
366 | if ((s->hdlctx.bitstream & mask1) != mask1) | ||
367 | continue; | ||
368 | s->hdlctx.bitstream &= ~mask2; | ||
369 | s->hdlctx.bitbuf = | ||
370 | (s->hdlctx.bitbuf & mask3) | | ||
371 | ((s->hdlctx.bitbuf & | ||
372 | (~mask3)) << 1); | ||
373 | s->hdlctx.numbits++; | ||
374 | mask3 = (mask3 << 1) | 1; | ||
375 | } | ||
376 | break; | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | /* ---------------------------------------------------------------------- */ | ||
382 | |||
383 | static void start_tx(struct net_device *dev, struct hdlcdrv_state *s) | ||
384 | { | ||
385 | s->hdlctx.tx_state = 0; | ||
386 | s->hdlctx.numflags = tenms_to_2flags(s, s->ch_params.tx_delay); | ||
387 | s->hdlctx.bitbuf = s->hdlctx.bitstream = s->hdlctx.numbits = 0; | ||
388 | hdlcdrv_transmitter(dev, s); | ||
389 | s->hdlctx.ptt = 1; | ||
390 | s->ptt_keyed++; | ||
391 | } | ||
392 | |||
393 | /* ---------------------------------------------------------------------- */ | ||
394 | |||
395 | static unsigned short random_seed; | ||
396 | |||
397 | static inline unsigned short random_num(void) | ||
398 | { | ||
399 | random_seed = 28629 * random_seed + 157; | ||
400 | return random_seed; | ||
401 | } | ||
402 | |||
403 | /* ---------------------------------------------------------------------- */ | ||
404 | |||
405 | void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s) | ||
406 | { | ||
407 | if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || !s->skb) | ||
408 | return; | ||
409 | if (s->ch_params.fulldup) { | ||
410 | start_tx(dev, s); | ||
411 | return; | ||
412 | } | ||
413 | if (s->hdlcrx.dcd) { | ||
414 | s->hdlctx.slotcnt = s->ch_params.slottime; | ||
415 | return; | ||
416 | } | ||
417 | if ((--s->hdlctx.slotcnt) > 0) | ||
418 | return; | ||
419 | s->hdlctx.slotcnt = s->ch_params.slottime; | ||
420 | if ((random_num() % 256) > s->ch_params.ppersist) | ||
421 | return; | ||
422 | start_tx(dev, s); | ||
423 | } | ||
424 | |||
425 | /* --------------------------------------------------------------------- */ | ||
426 | /* | ||
427 | * ===================== network driver interface ========================= | ||
428 | */ | ||
429 | |||
430 | static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
431 | { | ||
432 | struct hdlcdrv_state *sm = netdev_priv(dev); | ||
433 | |||
434 | if (skb->data[0] != 0) { | ||
435 | do_kiss_params(sm, skb->data, skb->len); | ||
436 | dev_kfree_skb(skb); | ||
437 | return 0; | ||
438 | } | ||
439 | if (sm->skb) | ||
440 | return -1; | ||
441 | netif_stop_queue(dev); | ||
442 | sm->skb = skb; | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | /* --------------------------------------------------------------------- */ | ||
447 | |||
448 | static int hdlcdrv_set_mac_address(struct net_device *dev, void *addr) | ||
449 | { | ||
450 | struct sockaddr *sa = (struct sockaddr *)addr; | ||
451 | |||
452 | /* addr is an AX.25 shifted ASCII mac address */ | ||
453 | memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | /* --------------------------------------------------------------------- */ | ||
458 | |||
459 | static struct net_device_stats *hdlcdrv_get_stats(struct net_device *dev) | ||
460 | { | ||
461 | struct hdlcdrv_state *sm = netdev_priv(dev); | ||
462 | |||
463 | /* | ||
464 | * Get the current statistics. This may be called with the | ||
465 | * card open or closed. | ||
466 | */ | ||
467 | return &sm->stats; | ||
468 | } | ||
469 | |||
470 | /* --------------------------------------------------------------------- */ | ||
471 | /* | ||
472 | * Open/initialize the board. This is called (in the current kernel) | ||
473 | * sometime after booting when the 'ifconfig' program is run. | ||
474 | * | ||
475 | * This routine should set everything up anew at each open, even | ||
476 | * registers that "should" only need to be set once at boot, so that | ||
477 | * there is non-reboot way to recover if something goes wrong. | ||
478 | */ | ||
479 | |||
480 | static int hdlcdrv_open(struct net_device *dev) | ||
481 | { | ||
482 | struct hdlcdrv_state *s = netdev_priv(dev); | ||
483 | int i; | ||
484 | |||
485 | if (!s->ops || !s->ops->open) | ||
486 | return -ENODEV; | ||
487 | |||
488 | /* | ||
489 | * initialise some variables | ||
490 | */ | ||
491 | s->opened = 1; | ||
492 | s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; | ||
493 | s->hdlcrx.in_hdlc_rx = 0; | ||
494 | s->hdlcrx.rx_state = 0; | ||
495 | |||
496 | s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; | ||
497 | s->hdlctx.in_hdlc_tx = 0; | ||
498 | s->hdlctx.tx_state = 1; | ||
499 | s->hdlctx.numflags = 0; | ||
500 | s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; | ||
501 | s->hdlctx.ptt = 0; | ||
502 | s->hdlctx.slotcnt = s->ch_params.slottime; | ||
503 | s->hdlctx.calibrate = 0; | ||
504 | |||
505 | i = s->ops->open(dev); | ||
506 | if (i) | ||
507 | return i; | ||
508 | netif_start_queue(dev); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | /* --------------------------------------------------------------------- */ | ||
513 | /* | ||
514 | * The inverse routine to hdlcdrv_open(). | ||
515 | */ | ||
516 | |||
517 | static int hdlcdrv_close(struct net_device *dev) | ||
518 | { | ||
519 | struct hdlcdrv_state *s = netdev_priv(dev); | ||
520 | int i = 0; | ||
521 | |||
522 | netif_stop_queue(dev); | ||
523 | |||
524 | if (s->ops && s->ops->close) | ||
525 | i = s->ops->close(dev); | ||
526 | if (s->skb) | ||
527 | dev_kfree_skb(s->skb); | ||
528 | s->skb = NULL; | ||
529 | s->opened = 0; | ||
530 | return i; | ||
531 | } | ||
532 | |||
533 | /* --------------------------------------------------------------------- */ | ||
534 | |||
535 | static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
536 | { | ||
537 | struct hdlcdrv_state *s = netdev_priv(dev); | ||
538 | struct hdlcdrv_ioctl bi; | ||
539 | |||
540 | if (cmd != SIOCDEVPRIVATE) { | ||
541 | if (s->ops && s->ops->ioctl) | ||
542 | return s->ops->ioctl(dev, ifr, &bi, cmd); | ||
543 | return -ENOIOCTLCMD; | ||
544 | } | ||
545 | if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) | ||
546 | return -EFAULT; | ||
547 | |||
548 | switch (bi.cmd) { | ||
549 | default: | ||
550 | if (s->ops && s->ops->ioctl) | ||
551 | return s->ops->ioctl(dev, ifr, &bi, cmd); | ||
552 | return -ENOIOCTLCMD; | ||
553 | |||
554 | case HDLCDRVCTL_GETCHANNELPAR: | ||
555 | bi.data.cp.tx_delay = s->ch_params.tx_delay; | ||
556 | bi.data.cp.tx_tail = s->ch_params.tx_tail; | ||
557 | bi.data.cp.slottime = s->ch_params.slottime; | ||
558 | bi.data.cp.ppersist = s->ch_params.ppersist; | ||
559 | bi.data.cp.fulldup = s->ch_params.fulldup; | ||
560 | break; | ||
561 | |||
562 | case HDLCDRVCTL_SETCHANNELPAR: | ||
563 | if (!capable(CAP_NET_ADMIN)) | ||
564 | return -EACCES; | ||
565 | s->ch_params.tx_delay = bi.data.cp.tx_delay; | ||
566 | s->ch_params.tx_tail = bi.data.cp.tx_tail; | ||
567 | s->ch_params.slottime = bi.data.cp.slottime; | ||
568 | s->ch_params.ppersist = bi.data.cp.ppersist; | ||
569 | s->ch_params.fulldup = bi.data.cp.fulldup; | ||
570 | s->hdlctx.slotcnt = 1; | ||
571 | return 0; | ||
572 | |||
573 | case HDLCDRVCTL_GETMODEMPAR: | ||
574 | bi.data.mp.iobase = dev->base_addr; | ||
575 | bi.data.mp.irq = dev->irq; | ||
576 | bi.data.mp.dma = dev->dma; | ||
577 | bi.data.mp.dma2 = s->ptt_out.dma2; | ||
578 | bi.data.mp.seriobase = s->ptt_out.seriobase; | ||
579 | bi.data.mp.pariobase = s->ptt_out.pariobase; | ||
580 | bi.data.mp.midiiobase = s->ptt_out.midiiobase; | ||
581 | break; | ||
582 | |||
583 | case HDLCDRVCTL_SETMODEMPAR: | ||
584 | if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev)) | ||
585 | return -EACCES; | ||
586 | dev->base_addr = bi.data.mp.iobase; | ||
587 | dev->irq = bi.data.mp.irq; | ||
588 | dev->dma = bi.data.mp.dma; | ||
589 | s->ptt_out.dma2 = bi.data.mp.dma2; | ||
590 | s->ptt_out.seriobase = bi.data.mp.seriobase; | ||
591 | s->ptt_out.pariobase = bi.data.mp.pariobase; | ||
592 | s->ptt_out.midiiobase = bi.data.mp.midiiobase; | ||
593 | return 0; | ||
594 | |||
595 | case HDLCDRVCTL_GETSTAT: | ||
596 | bi.data.cs.ptt = hdlcdrv_ptt(s); | ||
597 | bi.data.cs.dcd = s->hdlcrx.dcd; | ||
598 | bi.data.cs.ptt_keyed = s->ptt_keyed; | ||
599 | bi.data.cs.tx_packets = s->stats.tx_packets; | ||
600 | bi.data.cs.tx_errors = s->stats.tx_errors; | ||
601 | bi.data.cs.rx_packets = s->stats.rx_packets; | ||
602 | bi.data.cs.rx_errors = s->stats.rx_errors; | ||
603 | break; | ||
604 | |||
605 | case HDLCDRVCTL_OLDGETSTAT: | ||
606 | bi.data.ocs.ptt = hdlcdrv_ptt(s); | ||
607 | bi.data.ocs.dcd = s->hdlcrx.dcd; | ||
608 | bi.data.ocs.ptt_keyed = s->ptt_keyed; | ||
609 | break; | ||
610 | |||
611 | case HDLCDRVCTL_CALIBRATE: | ||
612 | if(!capable(CAP_SYS_RAWIO)) | ||
613 | return -EPERM; | ||
614 | s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; | ||
615 | return 0; | ||
616 | |||
617 | case HDLCDRVCTL_GETSAMPLES: | ||
618 | #ifndef HDLCDRV_DEBUG | ||
619 | return -EPERM; | ||
620 | #else /* HDLCDRV_DEBUG */ | ||
621 | if (s->bitbuf_channel.rd == s->bitbuf_channel.wr) | ||
622 | return -EAGAIN; | ||
623 | bi.data.bits = | ||
624 | s->bitbuf_channel.buffer[s->bitbuf_channel.rd]; | ||
625 | s->bitbuf_channel.rd = (s->bitbuf_channel.rd+1) % | ||
626 | sizeof(s->bitbuf_channel.buffer); | ||
627 | break; | ||
628 | #endif /* HDLCDRV_DEBUG */ | ||
629 | |||
630 | case HDLCDRVCTL_GETBITS: | ||
631 | #ifndef HDLCDRV_DEBUG | ||
632 | return -EPERM; | ||
633 | #else /* HDLCDRV_DEBUG */ | ||
634 | if (s->bitbuf_hdlc.rd == s->bitbuf_hdlc.wr) | ||
635 | return -EAGAIN; | ||
636 | bi.data.bits = | ||
637 | s->bitbuf_hdlc.buffer[s->bitbuf_hdlc.rd]; | ||
638 | s->bitbuf_hdlc.rd = (s->bitbuf_hdlc.rd+1) % | ||
639 | sizeof(s->bitbuf_hdlc.buffer); | ||
640 | break; | ||
641 | #endif /* HDLCDRV_DEBUG */ | ||
642 | |||
643 | case HDLCDRVCTL_DRIVERNAME: | ||
644 | if (s->ops && s->ops->drvname) { | ||
645 | strncpy(bi.data.drivername, s->ops->drvname, | ||
646 | sizeof(bi.data.drivername)); | ||
647 | break; | ||
648 | } | ||
649 | bi.data.drivername[0] = '\0'; | ||
650 | break; | ||
651 | |||
652 | } | ||
653 | if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) | ||
654 | return -EFAULT; | ||
655 | return 0; | ||
656 | |||
657 | } | ||
658 | |||
659 | /* --------------------------------------------------------------------- */ | ||
660 | |||
661 | /* | ||
662 | * Initialize fields in hdlcdrv | ||
663 | */ | ||
664 | static void hdlcdrv_setup(struct net_device *dev) | ||
665 | { | ||
666 | static const struct hdlcdrv_channel_params dflt_ch_params = { | ||
667 | 20, 2, 10, 40, 0 | ||
668 | }; | ||
669 | struct hdlcdrv_state *s = netdev_priv(dev); | ||
670 | |||
671 | /* | ||
672 | * initialize the hdlcdrv_state struct | ||
673 | */ | ||
674 | s->ch_params = dflt_ch_params; | ||
675 | s->ptt_keyed = 0; | ||
676 | |||
677 | spin_lock_init(&s->hdlcrx.hbuf.lock); | ||
678 | s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; | ||
679 | s->hdlcrx.in_hdlc_rx = 0; | ||
680 | s->hdlcrx.rx_state = 0; | ||
681 | |||
682 | spin_lock_init(&s->hdlctx.hbuf.lock); | ||
683 | s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; | ||
684 | s->hdlctx.in_hdlc_tx = 0; | ||
685 | s->hdlctx.tx_state = 1; | ||
686 | s->hdlctx.numflags = 0; | ||
687 | s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; | ||
688 | s->hdlctx.ptt = 0; | ||
689 | s->hdlctx.slotcnt = s->ch_params.slottime; | ||
690 | s->hdlctx.calibrate = 0; | ||
691 | |||
692 | #ifdef HDLCDRV_DEBUG | ||
693 | s->bitbuf_channel.rd = s->bitbuf_channel.wr = 0; | ||
694 | s->bitbuf_channel.shreg = 0x80; | ||
695 | |||
696 | s->bitbuf_hdlc.rd = s->bitbuf_hdlc.wr = 0; | ||
697 | s->bitbuf_hdlc.shreg = 0x80; | ||
698 | #endif /* HDLCDRV_DEBUG */ | ||
699 | |||
700 | /* | ||
701 | * initialize the device struct | ||
702 | */ | ||
703 | dev->open = hdlcdrv_open; | ||
704 | dev->stop = hdlcdrv_close; | ||
705 | dev->do_ioctl = hdlcdrv_ioctl; | ||
706 | dev->hard_start_xmit = hdlcdrv_send_packet; | ||
707 | dev->get_stats = hdlcdrv_get_stats; | ||
708 | |||
709 | /* Fill in the fields of the device structure */ | ||
710 | |||
711 | s->skb = NULL; | ||
712 | |||
713 | #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) | ||
714 | dev->hard_header = ax25_encapsulate; | ||
715 | dev->rebuild_header = ax25_rebuild_header; | ||
716 | #else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ | ||
717 | dev->hard_header = NULL; | ||
718 | dev->rebuild_header = NULL; | ||
719 | #endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ | ||
720 | dev->set_mac_address = hdlcdrv_set_mac_address; | ||
721 | |||
722 | dev->type = ARPHRD_AX25; /* AF_AX25 device */ | ||
723 | dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; | ||
724 | dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ | ||
725 | dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ | ||
726 | memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); | ||
727 | memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); | ||
728 | dev->tx_queue_len = 16; | ||
729 | } | ||
730 | |||
731 | /* --------------------------------------------------------------------- */ | ||
732 | struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops, | ||
733 | unsigned int privsize, const char *ifname, | ||
734 | unsigned int baseaddr, unsigned int irq, | ||
735 | unsigned int dma) | ||
736 | { | ||
737 | struct net_device *dev; | ||
738 | struct hdlcdrv_state *s; | ||
739 | int err; | ||
740 | |||
741 | BUG_ON(ops == NULL); | ||
742 | |||
743 | if (privsize < sizeof(struct hdlcdrv_state)) | ||
744 | privsize = sizeof(struct hdlcdrv_state); | ||
745 | |||
746 | dev = alloc_netdev(privsize, ifname, hdlcdrv_setup); | ||
747 | if (!dev) | ||
748 | return ERR_PTR(-ENOMEM); | ||
749 | |||
750 | /* | ||
751 | * initialize part of the hdlcdrv_state struct | ||
752 | */ | ||
753 | s = netdev_priv(dev); | ||
754 | s->magic = HDLCDRV_MAGIC; | ||
755 | s->ops = ops; | ||
756 | dev->base_addr = baseaddr; | ||
757 | dev->irq = irq; | ||
758 | dev->dma = dma; | ||
759 | |||
760 | err = register_netdev(dev); | ||
761 | if (err < 0) { | ||
762 | printk(KERN_WARNING "hdlcdrv: cannot register net " | ||
763 | "device %s\n", dev->name); | ||
764 | free_netdev(dev); | ||
765 | dev = ERR_PTR(err); | ||
766 | } | ||
767 | return dev; | ||
768 | } | ||
769 | |||
770 | /* --------------------------------------------------------------------- */ | ||
771 | |||
772 | void hdlcdrv_unregister(struct net_device *dev) | ||
773 | { | ||
774 | struct hdlcdrv_state *s = netdev_priv(dev); | ||
775 | |||
776 | BUG_ON(s->magic != HDLCDRV_MAGIC); | ||
777 | |||
778 | if (s->opened && s->ops->close) | ||
779 | s->ops->close(dev); | ||
780 | unregister_netdev(dev); | ||
781 | |||
782 | free_netdev(dev); | ||
783 | } | ||
784 | |||
785 | /* --------------------------------------------------------------------- */ | ||
786 | |||
787 | EXPORT_SYMBOL(hdlcdrv_receiver); | ||
788 | EXPORT_SYMBOL(hdlcdrv_transmitter); | ||
789 | EXPORT_SYMBOL(hdlcdrv_arbitrate); | ||
790 | EXPORT_SYMBOL(hdlcdrv_register); | ||
791 | EXPORT_SYMBOL(hdlcdrv_unregister); | ||
792 | |||
793 | /* --------------------------------------------------------------------- */ | ||
794 | |||
795 | static int __init hdlcdrv_init_driver(void) | ||
796 | { | ||
797 | printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n"); | ||
798 | printk(KERN_INFO "hdlcdrv: version 0.8 compiled " __TIME__ " " __DATE__ "\n"); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /* --------------------------------------------------------------------- */ | ||
803 | |||
804 | static void __exit hdlcdrv_cleanup_driver(void) | ||
805 | { | ||
806 | printk(KERN_INFO "hdlcdrv: cleanup\n"); | ||
807 | } | ||
808 | |||
809 | /* --------------------------------------------------------------------- */ | ||
810 | |||
811 | MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); | ||
812 | MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); | ||
813 | MODULE_LICENSE("GPL"); | ||
814 | module_init(hdlcdrv_init_driver); | ||
815 | module_exit(hdlcdrv_cleanup_driver); | ||
816 | |||
817 | /* --------------------------------------------------------------------- */ | ||