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 |
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')
-rw-r--r-- | drivers/net/hamradio/6pack.c | 1051 | ||||
-rw-r--r-- | drivers/net/hamradio/Kconfig | 191 | ||||
-rw-r--r-- | drivers/net/hamradio/Makefile | 22 | ||||
-rw-r--r-- | drivers/net/hamradio/baycom_epp.c | 1382 | ||||
-rw-r--r-- | drivers/net/hamradio/baycom_par.c | 576 | ||||
-rw-r--r-- | drivers/net/hamradio/baycom_ser_fdx.c | 704 | ||||
-rw-r--r-- | drivers/net/hamradio/baycom_ser_hdx.c | 740 | ||||
-rw-r--r-- | drivers/net/hamradio/bpqether.c | 643 | ||||
-rw-r--r-- | drivers/net/hamradio/dmascc.c | 1493 | ||||
-rw-r--r-- | drivers/net/hamradio/hdlcdrv.c | 817 | ||||
-rw-r--r-- | drivers/net/hamradio/mkiss.c | 951 | ||||
-rw-r--r-- | drivers/net/hamradio/mkiss.h | 62 | ||||
-rw-r--r-- | drivers/net/hamradio/scc.c | 2191 | ||||
-rw-r--r-- | drivers/net/hamradio/yam.c | 1218 | ||||
-rw-r--r-- | drivers/net/hamradio/yam1200.h | 343 | ||||
-rw-r--r-- | drivers/net/hamradio/yam9600.h | 343 | ||||
-rw-r--r-- | drivers/net/hamradio/z8530.h | 245 |
17 files changed, 12972 insertions, 0 deletions
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c new file mode 100644 index 000000000000..067b353e1cbd --- /dev/null +++ b/drivers/net/hamradio/6pack.c | |||
@@ -0,0 +1,1051 @@ | |||
1 | /* | ||
2 | * 6pack.c This module implements the 6pack protocol for kernel-based | ||
3 | * devices like TTY. It interfaces between a raw TTY and the | ||
4 | * kernel's AX.25 protocol layers. | ||
5 | * | ||
6 | * Authors: Andreas Könsgen <ajk@iehk.rwth-aachen.de> | ||
7 | * Ralf Baechle DL5RB <ralf@linux-mips.org> | ||
8 | * | ||
9 | * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by | ||
10 | * | ||
11 | * Laurence Culhane, <loz@holmes.demon.co.uk> | ||
12 | * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <asm/system.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/in.h> | ||
24 | #include <linux/tty.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <net/ax25.h> | ||
29 | #include <linux/etherdevice.h> | ||
30 | #include <linux/skbuff.h> | ||
31 | #include <linux/rtnetlink.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | #include <linux/if_arp.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/ip.h> | ||
36 | #include <linux/tcp.h> | ||
37 | #include <asm/semaphore.h> | ||
38 | #include <asm/atomic.h> | ||
39 | |||
40 | #define SIXPACK_VERSION "Revision: 0.3.0" | ||
41 | |||
42 | /* sixpack priority commands */ | ||
43 | #define SIXP_SEOF 0x40 /* start and end of a 6pack frame */ | ||
44 | #define SIXP_TX_URUN 0x48 /* transmit overrun */ | ||
45 | #define SIXP_RX_ORUN 0x50 /* receive overrun */ | ||
46 | #define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */ | ||
47 | |||
48 | #define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */ | ||
49 | |||
50 | /* masks to get certain bits out of the status bytes sent by the TNC */ | ||
51 | |||
52 | #define SIXP_CMD_MASK 0xC0 | ||
53 | #define SIXP_CHN_MASK 0x07 | ||
54 | #define SIXP_PRIO_CMD_MASK 0x80 | ||
55 | #define SIXP_STD_CMD_MASK 0x40 | ||
56 | #define SIXP_PRIO_DATA_MASK 0x38 | ||
57 | #define SIXP_TX_MASK 0x20 | ||
58 | #define SIXP_RX_MASK 0x10 | ||
59 | #define SIXP_RX_DCD_MASK 0x18 | ||
60 | #define SIXP_LEDS_ON 0x78 | ||
61 | #define SIXP_LEDS_OFF 0x60 | ||
62 | #define SIXP_CON 0x08 | ||
63 | #define SIXP_STA 0x10 | ||
64 | |||
65 | #define SIXP_FOUND_TNC 0xe9 | ||
66 | #define SIXP_CON_ON 0x68 | ||
67 | #define SIXP_DCD_MASK 0x08 | ||
68 | #define SIXP_DAMA_OFF 0 | ||
69 | |||
70 | /* default level 2 parameters */ | ||
71 | #define SIXP_TXDELAY (HZ/4) /* in 1 s */ | ||
72 | #define SIXP_PERSIST 50 /* in 256ths */ | ||
73 | #define SIXP_SLOTTIME (HZ/10) /* in 1 s */ | ||
74 | #define SIXP_INIT_RESYNC_TIMEOUT (3*HZ/2) /* in 1 s */ | ||
75 | #define SIXP_RESYNC_TIMEOUT 5*HZ /* in 1 s */ | ||
76 | |||
77 | /* 6pack configuration. */ | ||
78 | #define SIXP_NRUNIT 31 /* MAX number of 6pack channels */ | ||
79 | #define SIXP_MTU 256 /* Default MTU */ | ||
80 | |||
81 | enum sixpack_flags { | ||
82 | SIXPF_ERROR, /* Parity, etc. error */ | ||
83 | }; | ||
84 | |||
85 | struct sixpack { | ||
86 | /* Various fields. */ | ||
87 | struct tty_struct *tty; /* ptr to TTY structure */ | ||
88 | struct net_device *dev; /* easy for intr handling */ | ||
89 | |||
90 | /* These are pointers to the malloc()ed frame buffers. */ | ||
91 | unsigned char *rbuff; /* receiver buffer */ | ||
92 | int rcount; /* received chars counter */ | ||
93 | unsigned char *xbuff; /* transmitter buffer */ | ||
94 | unsigned char *xhead; /* next byte to XMIT */ | ||
95 | int xleft; /* bytes left in XMIT queue */ | ||
96 | |||
97 | unsigned char raw_buf[4]; | ||
98 | unsigned char cooked_buf[400]; | ||
99 | |||
100 | unsigned int rx_count; | ||
101 | unsigned int rx_count_cooked; | ||
102 | |||
103 | /* 6pack interface statistics. */ | ||
104 | struct net_device_stats stats; | ||
105 | |||
106 | int mtu; /* Our mtu (to spot changes!) */ | ||
107 | int buffsize; /* Max buffers sizes */ | ||
108 | |||
109 | unsigned long flags; /* Flag values/ mode etc */ | ||
110 | unsigned char mode; /* 6pack mode */ | ||
111 | |||
112 | /* 6pack stuff */ | ||
113 | unsigned char tx_delay; | ||
114 | unsigned char persistence; | ||
115 | unsigned char slottime; | ||
116 | unsigned char duplex; | ||
117 | unsigned char led_state; | ||
118 | unsigned char status; | ||
119 | unsigned char status1; | ||
120 | unsigned char status2; | ||
121 | unsigned char tx_enable; | ||
122 | unsigned char tnc_state; | ||
123 | |||
124 | struct timer_list tx_t; | ||
125 | struct timer_list resync_t; | ||
126 | atomic_t refcnt; | ||
127 | struct semaphore dead_sem; | ||
128 | spinlock_t lock; | ||
129 | }; | ||
130 | |||
131 | #define AX25_6PACK_HEADER_LEN 0 | ||
132 | |||
133 | static void sp_start_tx_timer(struct sixpack *); | ||
134 | static void sixpack_decode(struct sixpack *, unsigned char[], int); | ||
135 | static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); | ||
136 | |||
137 | /* | ||
138 | * perform the persistence/slottime algorithm for CSMA access. If the | ||
139 | * persistence check was successful, write the data to the serial driver. | ||
140 | * Note that in case of DAMA operation, the data is not sent here. | ||
141 | */ | ||
142 | |||
143 | static void sp_xmit_on_air(unsigned long channel) | ||
144 | { | ||
145 | struct sixpack *sp = (struct sixpack *) channel; | ||
146 | int actual; | ||
147 | static unsigned char random; | ||
148 | |||
149 | random = random * 17 + 41; | ||
150 | |||
151 | if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) { | ||
152 | sp->led_state = 0x70; | ||
153 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
154 | sp->tx_enable = 1; | ||
155 | actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); | ||
156 | sp->xleft -= actual; | ||
157 | sp->xhead += actual; | ||
158 | sp->led_state = 0x60; | ||
159 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
160 | sp->status2 = 0; | ||
161 | } else | ||
162 | sp_start_tx_timer(sp); | ||
163 | } | ||
164 | |||
165 | /* ----> 6pack timer interrupt handler and friends. <---- */ | ||
166 | static void sp_start_tx_timer(struct sixpack *sp) | ||
167 | { | ||
168 | int when = sp->slottime; | ||
169 | |||
170 | del_timer(&sp->tx_t); | ||
171 | sp->tx_t.data = (unsigned long) sp; | ||
172 | sp->tx_t.function = sp_xmit_on_air; | ||
173 | sp->tx_t.expires = jiffies + ((when + 1) * HZ) / 100; | ||
174 | add_timer(&sp->tx_t); | ||
175 | } | ||
176 | |||
177 | /* Encapsulate one AX.25 frame and stuff into a TTY queue. */ | ||
178 | static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) | ||
179 | { | ||
180 | unsigned char *msg, *p = icp; | ||
181 | int actual, count; | ||
182 | |||
183 | if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */ | ||
184 | msg = "oversized transmit packet!"; | ||
185 | goto out_drop; | ||
186 | } | ||
187 | |||
188 | if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */ | ||
189 | msg = "oversized transmit packet!"; | ||
190 | goto out_drop; | ||
191 | } | ||
192 | |||
193 | if (p[0] > 5) { | ||
194 | msg = "invalid KISS command"; | ||
195 | goto out_drop; | ||
196 | } | ||
197 | |||
198 | if ((p[0] != 0) && (len > 2)) { | ||
199 | msg = "KISS control packet too long"; | ||
200 | goto out_drop; | ||
201 | } | ||
202 | |||
203 | if ((p[0] == 0) && (len < 15)) { | ||
204 | msg = "bad AX.25 packet to transmit"; | ||
205 | goto out_drop; | ||
206 | } | ||
207 | |||
208 | count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay); | ||
209 | set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags); | ||
210 | |||
211 | switch (p[0]) { | ||
212 | case 1: sp->tx_delay = p[1]; | ||
213 | return; | ||
214 | case 2: sp->persistence = p[1]; | ||
215 | return; | ||
216 | case 3: sp->slottime = p[1]; | ||
217 | return; | ||
218 | case 4: /* ignored */ | ||
219 | return; | ||
220 | case 5: sp->duplex = p[1]; | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | if (p[0] != 0) | ||
225 | return; | ||
226 | |||
227 | /* | ||
228 | * In case of fullduplex or DAMA operation, we don't take care about the | ||
229 | * state of the DCD or of any timers, as the determination of the | ||
230 | * correct time to send is the job of the AX.25 layer. We send | ||
231 | * immediately after data has arrived. | ||
232 | */ | ||
233 | if (sp->duplex == 1) { | ||
234 | sp->led_state = 0x70; | ||
235 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
236 | sp->tx_enable = 1; | ||
237 | actual = sp->tty->driver->write(sp->tty, sp->xbuff, count); | ||
238 | sp->xleft = count - actual; | ||
239 | sp->xhead = sp->xbuff + actual; | ||
240 | sp->led_state = 0x60; | ||
241 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
242 | } else { | ||
243 | sp->xleft = count; | ||
244 | sp->xhead = sp->xbuff; | ||
245 | sp->status2 = count; | ||
246 | if (sp->duplex == 0) | ||
247 | sp_start_tx_timer(sp); | ||
248 | } | ||
249 | |||
250 | return; | ||
251 | |||
252 | out_drop: | ||
253 | sp->stats.tx_dropped++; | ||
254 | netif_start_queue(sp->dev); | ||
255 | if (net_ratelimit()) | ||
256 | printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg); | ||
257 | } | ||
258 | |||
259 | /* Encapsulate an IP datagram and kick it into a TTY queue. */ | ||
260 | |||
261 | static int sp_xmit(struct sk_buff *skb, struct net_device *dev) | ||
262 | { | ||
263 | struct sixpack *sp = netdev_priv(dev); | ||
264 | |||
265 | spin_lock_bh(&sp->lock); | ||
266 | /* We were not busy, so we are now... :-) */ | ||
267 | netif_stop_queue(dev); | ||
268 | sp->stats.tx_bytes += skb->len; | ||
269 | sp_encaps(sp, skb->data, skb->len); | ||
270 | spin_unlock_bh(&sp->lock); | ||
271 | |||
272 | dev_kfree_skb(skb); | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int sp_open_dev(struct net_device *dev) | ||
278 | { | ||
279 | struct sixpack *sp = netdev_priv(dev); | ||
280 | |||
281 | if (sp->tty == NULL) | ||
282 | return -ENODEV; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* Close the low-level part of the 6pack channel. */ | ||
287 | static int sp_close(struct net_device *dev) | ||
288 | { | ||
289 | struct sixpack *sp = netdev_priv(dev); | ||
290 | |||
291 | spin_lock_bh(&sp->lock); | ||
292 | if (sp->tty) { | ||
293 | /* TTY discipline is running. */ | ||
294 | clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags); | ||
295 | } | ||
296 | netif_stop_queue(dev); | ||
297 | spin_unlock_bh(&sp->lock); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* Return the frame type ID */ | ||
303 | static int sp_header(struct sk_buff *skb, struct net_device *dev, | ||
304 | unsigned short type, void *daddr, void *saddr, unsigned len) | ||
305 | { | ||
306 | #ifdef CONFIG_INET | ||
307 | if (type != htons(ETH_P_AX25)) | ||
308 | return ax25_encapsulate(skb, dev, type, daddr, saddr, len); | ||
309 | #endif | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static struct net_device_stats *sp_get_stats(struct net_device *dev) | ||
314 | { | ||
315 | struct sixpack *sp = netdev_priv(dev); | ||
316 | return &sp->stats; | ||
317 | } | ||
318 | |||
319 | static int sp_set_mac_address(struct net_device *dev, void *addr) | ||
320 | { | ||
321 | struct sockaddr_ax25 *sa = addr; | ||
322 | |||
323 | if (sa->sax25_family != AF_AX25) | ||
324 | return -EINVAL; | ||
325 | |||
326 | if (!sa->sax25_ndigis) | ||
327 | return -EINVAL; | ||
328 | |||
329 | spin_lock_irq(&dev->xmit_lock); | ||
330 | memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); | ||
331 | spin_unlock_irq(&dev->xmit_lock); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int sp_rebuild_header(struct sk_buff *skb) | ||
337 | { | ||
338 | #ifdef CONFIG_INET | ||
339 | return ax25_rebuild_header(skb); | ||
340 | #else | ||
341 | return 0; | ||
342 | #endif | ||
343 | } | ||
344 | |||
345 | static void sp_setup(struct net_device *dev) | ||
346 | { | ||
347 | static char ax25_bcast[AX25_ADDR_LEN] = | ||
348 | {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; | ||
349 | static char ax25_test[AX25_ADDR_LEN] = | ||
350 | {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; | ||
351 | |||
352 | /* Finish setting up the DEVICE info. */ | ||
353 | dev->mtu = SIXP_MTU; | ||
354 | dev->hard_start_xmit = sp_xmit; | ||
355 | dev->open = sp_open_dev; | ||
356 | dev->destructor = free_netdev; | ||
357 | dev->stop = sp_close; | ||
358 | dev->hard_header = sp_header; | ||
359 | dev->get_stats = sp_get_stats; | ||
360 | dev->set_mac_address = sp_set_mac_address; | ||
361 | dev->hard_header_len = AX25_MAX_HEADER_LEN; | ||
362 | dev->addr_len = AX25_ADDR_LEN; | ||
363 | dev->type = ARPHRD_AX25; | ||
364 | dev->tx_queue_len = 10; | ||
365 | dev->rebuild_header = sp_rebuild_header; | ||
366 | dev->tx_timeout = NULL; | ||
367 | |||
368 | /* Only activated in AX.25 mode */ | ||
369 | memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); | ||
370 | memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); | ||
371 | |||
372 | SET_MODULE_OWNER(dev); | ||
373 | |||
374 | dev->flags = 0; | ||
375 | } | ||
376 | |||
377 | /* Send one completely decapsulated IP datagram to the IP layer. */ | ||
378 | |||
379 | /* | ||
380 | * This is the routine that sends the received data to the kernel AX.25. | ||
381 | * 'cmd' is the KISS command. For AX.25 data, it is zero. | ||
382 | */ | ||
383 | |||
384 | static void sp_bump(struct sixpack *sp, char cmd) | ||
385 | { | ||
386 | struct sk_buff *skb; | ||
387 | int count; | ||
388 | unsigned char *ptr; | ||
389 | |||
390 | count = sp->rcount + 1; | ||
391 | |||
392 | sp->stats.rx_bytes += count; | ||
393 | |||
394 | if ((skb = dev_alloc_skb(count)) == NULL) | ||
395 | goto out_mem; | ||
396 | |||
397 | skb->dev = sp->dev; | ||
398 | ptr = skb_put(skb, count); | ||
399 | *ptr++ = cmd; /* KISS command */ | ||
400 | |||
401 | memcpy(ptr, sp->cooked_buf + 1, count); | ||
402 | skb->mac.raw = skb->data; | ||
403 | skb->protocol = htons(ETH_P_AX25); | ||
404 | netif_rx(skb); | ||
405 | sp->dev->last_rx = jiffies; | ||
406 | sp->stats.rx_packets++; | ||
407 | |||
408 | return; | ||
409 | |||
410 | out_mem: | ||
411 | sp->stats.rx_dropped++; | ||
412 | } | ||
413 | |||
414 | |||
415 | /* ----------------------------------------------------------------------- */ | ||
416 | |||
417 | /* | ||
418 | * We have a potential race on dereferencing tty->disc_data, because the tty | ||
419 | * layer provides no locking at all - thus one cpu could be running | ||
420 | * sixpack_receive_buf while another calls sixpack_close, which zeroes | ||
421 | * tty->disc_data and frees the memory that sixpack_receive_buf is using. The | ||
422 | * best way to fix this is to use a rwlock in the tty struct, but for now we | ||
423 | * use a single global rwlock for all ttys in ppp line discipline. | ||
424 | */ | ||
425 | static DEFINE_RWLOCK(disc_data_lock); | ||
426 | |||
427 | static struct sixpack *sp_get(struct tty_struct *tty) | ||
428 | { | ||
429 | struct sixpack *sp; | ||
430 | |||
431 | read_lock(&disc_data_lock); | ||
432 | sp = tty->disc_data; | ||
433 | if (sp) | ||
434 | atomic_inc(&sp->refcnt); | ||
435 | read_unlock(&disc_data_lock); | ||
436 | |||
437 | return sp; | ||
438 | } | ||
439 | |||
440 | static void sp_put(struct sixpack *sp) | ||
441 | { | ||
442 | if (atomic_dec_and_test(&sp->refcnt)) | ||
443 | up(&sp->dead_sem); | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * Called by the TTY driver when there's room for more data. If we have | ||
448 | * more packets to send, we send them here. | ||
449 | */ | ||
450 | static void sixpack_write_wakeup(struct tty_struct *tty) | ||
451 | { | ||
452 | struct sixpack *sp = sp_get(tty); | ||
453 | int actual; | ||
454 | |||
455 | if (!sp) | ||
456 | return; | ||
457 | if (sp->xleft <= 0) { | ||
458 | /* Now serial buffer is almost free & we can start | ||
459 | * transmission of another packet */ | ||
460 | sp->stats.tx_packets++; | ||
461 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
462 | sp->tx_enable = 0; | ||
463 | netif_wake_queue(sp->dev); | ||
464 | goto out; | ||
465 | } | ||
466 | |||
467 | if (sp->tx_enable) { | ||
468 | actual = tty->driver->write(tty, sp->xhead, sp->xleft); | ||
469 | sp->xleft -= actual; | ||
470 | sp->xhead += actual; | ||
471 | } | ||
472 | |||
473 | out: | ||
474 | sp_put(sp); | ||
475 | } | ||
476 | |||
477 | /* ----------------------------------------------------------------------- */ | ||
478 | |||
479 | static int sixpack_receive_room(struct tty_struct *tty) | ||
480 | { | ||
481 | return 65536; /* We can handle an infinite amount of data. :-) */ | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Handle the 'receiver data ready' interrupt. | ||
486 | * This function is called by the 'tty_io' module in the kernel when | ||
487 | * a block of 6pack data has been received, which can now be decapsulated | ||
488 | * and sent on to some IP layer for further processing. | ||
489 | */ | ||
490 | static void sixpack_receive_buf(struct tty_struct *tty, | ||
491 | const unsigned char *cp, char *fp, int count) | ||
492 | { | ||
493 | struct sixpack *sp; | ||
494 | unsigned char buf[512]; | ||
495 | int count1; | ||
496 | |||
497 | if (!count) | ||
498 | return; | ||
499 | |||
500 | sp = sp_get(tty); | ||
501 | if (!sp) | ||
502 | return; | ||
503 | |||
504 | memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf)); | ||
505 | |||
506 | /* Read the characters out of the buffer */ | ||
507 | |||
508 | count1 = count; | ||
509 | while (count) { | ||
510 | count--; | ||
511 | if (fp && *fp++) { | ||
512 | if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) | ||
513 | sp->stats.rx_errors++; | ||
514 | continue; | ||
515 | } | ||
516 | } | ||
517 | sixpack_decode(sp, buf, count1); | ||
518 | |||
519 | sp_put(sp); | ||
520 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) | ||
521 | && tty->driver->unthrottle) | ||
522 | tty->driver->unthrottle(tty); | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * Try to resync the TNC. Called by the resync timer defined in | ||
527 | * decode_prio_command | ||
528 | */ | ||
529 | |||
530 | #define TNC_UNINITIALIZED 0 | ||
531 | #define TNC_UNSYNC_STARTUP 1 | ||
532 | #define TNC_UNSYNCED 2 | ||
533 | #define TNC_IN_SYNC 3 | ||
534 | |||
535 | static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state) | ||
536 | { | ||
537 | char *msg; | ||
538 | |||
539 | switch (new_tnc_state) { | ||
540 | default: /* gcc oh piece-o-crap ... */ | ||
541 | case TNC_UNSYNC_STARTUP: | ||
542 | msg = "Synchronizing with TNC"; | ||
543 | break; | ||
544 | case TNC_UNSYNCED: | ||
545 | msg = "Lost synchronization with TNC\n"; | ||
546 | break; | ||
547 | case TNC_IN_SYNC: | ||
548 | msg = "Found TNC"; | ||
549 | break; | ||
550 | } | ||
551 | |||
552 | sp->tnc_state = new_tnc_state; | ||
553 | printk(KERN_INFO "%s: %s\n", sp->dev->name, msg); | ||
554 | } | ||
555 | |||
556 | static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state) | ||
557 | { | ||
558 | int old_tnc_state = sp->tnc_state; | ||
559 | |||
560 | if (old_tnc_state != new_tnc_state) | ||
561 | __tnc_set_sync_state(sp, new_tnc_state); | ||
562 | } | ||
563 | |||
564 | static void resync_tnc(unsigned long channel) | ||
565 | { | ||
566 | struct sixpack *sp = (struct sixpack *) channel; | ||
567 | static char resync_cmd = 0xe8; | ||
568 | |||
569 | /* clear any data that might have been received */ | ||
570 | |||
571 | sp->rx_count = 0; | ||
572 | sp->rx_count_cooked = 0; | ||
573 | |||
574 | /* reset state machine */ | ||
575 | |||
576 | sp->status = 1; | ||
577 | sp->status1 = 1; | ||
578 | sp->status2 = 0; | ||
579 | |||
580 | /* resync the TNC */ | ||
581 | |||
582 | sp->led_state = 0x60; | ||
583 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
584 | sp->tty->driver->write(sp->tty, &resync_cmd, 1); | ||
585 | |||
586 | |||
587 | /* Start resync timer again -- the TNC might be still absent */ | ||
588 | |||
589 | del_timer(&sp->resync_t); | ||
590 | sp->resync_t.data = (unsigned long) sp; | ||
591 | sp->resync_t.function = resync_tnc; | ||
592 | sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; | ||
593 | add_timer(&sp->resync_t); | ||
594 | } | ||
595 | |||
596 | static inline int tnc_init(struct sixpack *sp) | ||
597 | { | ||
598 | unsigned char inbyte = 0xe8; | ||
599 | |||
600 | tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP); | ||
601 | |||
602 | sp->tty->driver->write(sp->tty, &inbyte, 1); | ||
603 | |||
604 | del_timer(&sp->resync_t); | ||
605 | sp->resync_t.data = (unsigned long) sp; | ||
606 | sp->resync_t.function = resync_tnc; | ||
607 | sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; | ||
608 | add_timer(&sp->resync_t); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | /* | ||
614 | * Open the high-level part of the 6pack channel. | ||
615 | * This function is called by the TTY module when the | ||
616 | * 6pack line discipline is called for. Because we are | ||
617 | * sure the tty line exists, we only have to link it to | ||
618 | * a free 6pcack channel... | ||
619 | */ | ||
620 | static int sixpack_open(struct tty_struct *tty) | ||
621 | { | ||
622 | char *rbuff = NULL, *xbuff = NULL; | ||
623 | struct net_device *dev; | ||
624 | struct sixpack *sp; | ||
625 | unsigned long len; | ||
626 | int err = 0; | ||
627 | |||
628 | if (!capable(CAP_NET_ADMIN)) | ||
629 | return -EPERM; | ||
630 | |||
631 | dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup); | ||
632 | if (!dev) { | ||
633 | err = -ENOMEM; | ||
634 | goto out; | ||
635 | } | ||
636 | |||
637 | sp = netdev_priv(dev); | ||
638 | sp->dev = dev; | ||
639 | |||
640 | spin_lock_init(&sp->lock); | ||
641 | atomic_set(&sp->refcnt, 1); | ||
642 | init_MUTEX_LOCKED(&sp->dead_sem); | ||
643 | |||
644 | /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */ | ||
645 | |||
646 | len = dev->mtu * 2; | ||
647 | |||
648 | rbuff = kmalloc(len + 4, GFP_KERNEL); | ||
649 | xbuff = kmalloc(len + 4, GFP_KERNEL); | ||
650 | |||
651 | if (rbuff == NULL || xbuff == NULL) { | ||
652 | err = -ENOBUFS; | ||
653 | goto out_free; | ||
654 | } | ||
655 | |||
656 | spin_lock_bh(&sp->lock); | ||
657 | |||
658 | sp->tty = tty; | ||
659 | |||
660 | sp->rbuff = rbuff; | ||
661 | sp->xbuff = xbuff; | ||
662 | |||
663 | sp->mtu = AX25_MTU + 73; | ||
664 | sp->buffsize = len; | ||
665 | sp->rcount = 0; | ||
666 | sp->rx_count = 0; | ||
667 | sp->rx_count_cooked = 0; | ||
668 | sp->xleft = 0; | ||
669 | |||
670 | sp->flags = 0; /* Clear ESCAPE & ERROR flags */ | ||
671 | |||
672 | sp->duplex = 0; | ||
673 | sp->tx_delay = SIXP_TXDELAY; | ||
674 | sp->persistence = SIXP_PERSIST; | ||
675 | sp->slottime = SIXP_SLOTTIME; | ||
676 | sp->led_state = 0x60; | ||
677 | sp->status = 1; | ||
678 | sp->status1 = 1; | ||
679 | sp->status2 = 0; | ||
680 | sp->tx_enable = 0; | ||
681 | |||
682 | netif_start_queue(dev); | ||
683 | |||
684 | init_timer(&sp->tx_t); | ||
685 | init_timer(&sp->resync_t); | ||
686 | |||
687 | spin_unlock_bh(&sp->lock); | ||
688 | |||
689 | /* Done. We have linked the TTY line to a channel. */ | ||
690 | tty->disc_data = sp; | ||
691 | |||
692 | /* Now we're ready to register. */ | ||
693 | if (register_netdev(dev)) | ||
694 | goto out_free; | ||
695 | |||
696 | tnc_init(sp); | ||
697 | |||
698 | return 0; | ||
699 | |||
700 | out_free: | ||
701 | kfree(xbuff); | ||
702 | kfree(rbuff); | ||
703 | |||
704 | if (dev) | ||
705 | free_netdev(dev); | ||
706 | |||
707 | out: | ||
708 | return err; | ||
709 | } | ||
710 | |||
711 | |||
712 | /* | ||
713 | * Close down a 6pack channel. | ||
714 | * This means flushing out any pending queues, and then restoring the | ||
715 | * TTY line discipline to what it was before it got hooked to 6pack | ||
716 | * (which usually is TTY again). | ||
717 | */ | ||
718 | static void sixpack_close(struct tty_struct *tty) | ||
719 | { | ||
720 | struct sixpack *sp; | ||
721 | |||
722 | write_lock(&disc_data_lock); | ||
723 | sp = tty->disc_data; | ||
724 | tty->disc_data = NULL; | ||
725 | write_unlock(&disc_data_lock); | ||
726 | if (sp == 0) | ||
727 | return; | ||
728 | |||
729 | /* | ||
730 | * We have now ensured that nobody can start using ap from now on, but | ||
731 | * we have to wait for all existing users to finish. | ||
732 | */ | ||
733 | if (!atomic_dec_and_test(&sp->refcnt)) | ||
734 | down(&sp->dead_sem); | ||
735 | |||
736 | unregister_netdev(sp->dev); | ||
737 | |||
738 | del_timer(&sp->tx_t); | ||
739 | del_timer(&sp->resync_t); | ||
740 | |||
741 | /* Free all 6pack frame buffers. */ | ||
742 | kfree(sp->rbuff); | ||
743 | kfree(sp->xbuff); | ||
744 | } | ||
745 | |||
746 | /* Perform I/O control on an active 6pack channel. */ | ||
747 | static int sixpack_ioctl(struct tty_struct *tty, struct file *file, | ||
748 | unsigned int cmd, unsigned long arg) | ||
749 | { | ||
750 | struct sixpack *sp = sp_get(tty); | ||
751 | struct net_device *dev = sp->dev; | ||
752 | unsigned int tmp, err; | ||
753 | |||
754 | if (!sp) | ||
755 | return -ENXIO; | ||
756 | |||
757 | switch(cmd) { | ||
758 | case SIOCGIFNAME: | ||
759 | err = copy_to_user((void __user *) arg, dev->name, | ||
760 | strlen(dev->name) + 1) ? -EFAULT : 0; | ||
761 | break; | ||
762 | |||
763 | case SIOCGIFENCAP: | ||
764 | err = put_user(0, (int __user *) arg); | ||
765 | break; | ||
766 | |||
767 | case SIOCSIFENCAP: | ||
768 | if (get_user(tmp, (int __user *) arg)) { | ||
769 | err = -EFAULT; | ||
770 | break; | ||
771 | } | ||
772 | |||
773 | sp->mode = tmp; | ||
774 | dev->addr_len = AX25_ADDR_LEN; | ||
775 | dev->hard_header_len = AX25_KISS_HEADER_LEN + | ||
776 | AX25_MAX_HEADER_LEN + 3; | ||
777 | dev->type = ARPHRD_AX25; | ||
778 | |||
779 | err = 0; | ||
780 | break; | ||
781 | |||
782 | case SIOCSIFHWADDR: { | ||
783 | char addr[AX25_ADDR_LEN]; | ||
784 | |||
785 | if (copy_from_user(&addr, | ||
786 | (void __user *) arg, AX25_ADDR_LEN)) { | ||
787 | err = -EFAULT; | ||
788 | break; | ||
789 | } | ||
790 | |||
791 | spin_lock_irq(&dev->xmit_lock); | ||
792 | memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN); | ||
793 | spin_unlock_irq(&dev->xmit_lock); | ||
794 | |||
795 | err = 0; | ||
796 | break; | ||
797 | } | ||
798 | |||
799 | /* Allow stty to read, but not set, the serial port */ | ||
800 | case TCGETS: | ||
801 | case TCGETA: | ||
802 | err = n_tty_ioctl(tty, (struct file *) file, cmd, arg); | ||
803 | break; | ||
804 | |||
805 | default: | ||
806 | err = -ENOIOCTLCMD; | ||
807 | } | ||
808 | |||
809 | sp_put(sp); | ||
810 | |||
811 | return err; | ||
812 | } | ||
813 | |||
814 | static struct tty_ldisc sp_ldisc = { | ||
815 | .owner = THIS_MODULE, | ||
816 | .magic = TTY_LDISC_MAGIC, | ||
817 | .name = "6pack", | ||
818 | .open = sixpack_open, | ||
819 | .close = sixpack_close, | ||
820 | .ioctl = sixpack_ioctl, | ||
821 | .receive_buf = sixpack_receive_buf, | ||
822 | .receive_room = sixpack_receive_room, | ||
823 | .write_wakeup = sixpack_write_wakeup, | ||
824 | }; | ||
825 | |||
826 | /* Initialize 6pack control device -- register 6pack line discipline */ | ||
827 | |||
828 | static char msg_banner[] __initdata = KERN_INFO \ | ||
829 | "AX.25: 6pack driver, " SIXPACK_VERSION "\n"; | ||
830 | static char msg_regfail[] __initdata = KERN_ERR \ | ||
831 | "6pack: can't register line discipline (err = %d)\n"; | ||
832 | |||
833 | static int __init sixpack_init_driver(void) | ||
834 | { | ||
835 | int status; | ||
836 | |||
837 | printk(msg_banner); | ||
838 | |||
839 | /* Register the provided line protocol discipline */ | ||
840 | if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) | ||
841 | printk(msg_regfail, status); | ||
842 | |||
843 | return status; | ||
844 | } | ||
845 | |||
846 | static const char msg_unregfail[] __exitdata = KERN_ERR \ | ||
847 | "6pack: can't unregister line discipline (err = %d)\n"; | ||
848 | |||
849 | static void __exit sixpack_exit_driver(void) | ||
850 | { | ||
851 | int ret; | ||
852 | |||
853 | if ((ret = tty_register_ldisc(N_6PACK, NULL))) | ||
854 | printk(msg_unregfail, ret); | ||
855 | } | ||
856 | |||
857 | /* encode an AX.25 packet into 6pack */ | ||
858 | |||
859 | static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, | ||
860 | int length, unsigned char tx_delay) | ||
861 | { | ||
862 | int count = 0; | ||
863 | unsigned char checksum = 0, buf[400]; | ||
864 | int raw_count = 0; | ||
865 | |||
866 | tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK; | ||
867 | tx_buf_raw[raw_count++] = SIXP_SEOF; | ||
868 | |||
869 | buf[0] = tx_delay; | ||
870 | for (count = 1; count < length; count++) | ||
871 | buf[count] = tx_buf[count]; | ||
872 | |||
873 | for (count = 0; count < length; count++) | ||
874 | checksum += buf[count]; | ||
875 | buf[length] = (unsigned char) 0xff - checksum; | ||
876 | |||
877 | for (count = 0; count <= length; count++) { | ||
878 | if ((count % 3) == 0) { | ||
879 | tx_buf_raw[raw_count++] = (buf[count] & 0x3f); | ||
880 | tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30); | ||
881 | } else if ((count % 3) == 1) { | ||
882 | tx_buf_raw[raw_count++] |= (buf[count] & 0x0f); | ||
883 | tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c); | ||
884 | } else { | ||
885 | tx_buf_raw[raw_count++] |= (buf[count] & 0x03); | ||
886 | tx_buf_raw[raw_count++] = (buf[count] >> 2); | ||
887 | } | ||
888 | } | ||
889 | if ((length % 3) != 2) | ||
890 | raw_count++; | ||
891 | tx_buf_raw[raw_count++] = SIXP_SEOF; | ||
892 | return raw_count; | ||
893 | } | ||
894 | |||
895 | /* decode 4 sixpack-encoded bytes into 3 data bytes */ | ||
896 | |||
897 | static void decode_data(struct sixpack *sp, unsigned char inbyte) | ||
898 | { | ||
899 | unsigned char *buf; | ||
900 | |||
901 | if (sp->rx_count != 3) { | ||
902 | sp->raw_buf[sp->rx_count++] = inbyte; | ||
903 | |||
904 | return; | ||
905 | } | ||
906 | |||
907 | buf = sp->raw_buf; | ||
908 | sp->cooked_buf[sp->rx_count_cooked++] = | ||
909 | buf[0] | ((buf[1] << 2) & 0xc0); | ||
910 | sp->cooked_buf[sp->rx_count_cooked++] = | ||
911 | (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); | ||
912 | sp->cooked_buf[sp->rx_count_cooked++] = | ||
913 | (buf[2] & 0x03) | (inbyte << 2); | ||
914 | sp->rx_count = 0; | ||
915 | } | ||
916 | |||
917 | /* identify and execute a 6pack priority command byte */ | ||
918 | |||
919 | static void decode_prio_command(struct sixpack *sp, unsigned char cmd) | ||
920 | { | ||
921 | unsigned char channel; | ||
922 | int actual; | ||
923 | |||
924 | channel = cmd & SIXP_CHN_MASK; | ||
925 | if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ | ||
926 | |||
927 | /* RX and DCD flags can only be set in the same prio command, | ||
928 | if the DCD flag has been set without the RX flag in the previous | ||
929 | prio command. If DCD has not been set before, something in the | ||
930 | transmission has gone wrong. In this case, RX and DCD are | ||
931 | cleared in order to prevent the decode_data routine from | ||
932 | reading further data that might be corrupt. */ | ||
933 | |||
934 | if (((sp->status & SIXP_DCD_MASK) == 0) && | ||
935 | ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { | ||
936 | if (sp->status != 1) | ||
937 | printk(KERN_DEBUG "6pack: protocol violation\n"); | ||
938 | else | ||
939 | sp->status = 0; | ||
940 | cmd &= !SIXP_RX_DCD_MASK; | ||
941 | } | ||
942 | sp->status = cmd & SIXP_PRIO_DATA_MASK; | ||
943 | } else { /* output watchdog char if idle */ | ||
944 | if ((sp->status2 != 0) && (sp->duplex == 1)) { | ||
945 | sp->led_state = 0x70; | ||
946 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
947 | sp->tx_enable = 1; | ||
948 | actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); | ||
949 | sp->xleft -= actual; | ||
950 | sp->xhead += actual; | ||
951 | sp->led_state = 0x60; | ||
952 | sp->status2 = 0; | ||
953 | |||
954 | } | ||
955 | } | ||
956 | |||
957 | /* needed to trigger the TNC watchdog */ | ||
958 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
959 | |||
960 | /* if the state byte has been received, the TNC is present, | ||
961 | so the resync timer can be reset. */ | ||
962 | |||
963 | if (sp->tnc_state == TNC_IN_SYNC) { | ||
964 | del_timer(&sp->resync_t); | ||
965 | sp->resync_t.data = (unsigned long) sp; | ||
966 | sp->resync_t.function = resync_tnc; | ||
967 | sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; | ||
968 | add_timer(&sp->resync_t); | ||
969 | } | ||
970 | |||
971 | sp->status1 = cmd & SIXP_PRIO_DATA_MASK; | ||
972 | } | ||
973 | |||
974 | /* identify and execute a standard 6pack command byte */ | ||
975 | |||
976 | static void decode_std_command(struct sixpack *sp, unsigned char cmd) | ||
977 | { | ||
978 | unsigned char checksum = 0, rest = 0, channel; | ||
979 | short i; | ||
980 | |||
981 | channel = cmd & SIXP_CHN_MASK; | ||
982 | switch (cmd & SIXP_CMD_MASK) { /* normal command */ | ||
983 | case SIXP_SEOF: | ||
984 | if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { | ||
985 | if ((sp->status & SIXP_RX_DCD_MASK) == | ||
986 | SIXP_RX_DCD_MASK) { | ||
987 | sp->led_state = 0x68; | ||
988 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
989 | } | ||
990 | } else { | ||
991 | sp->led_state = 0x60; | ||
992 | /* fill trailing bytes with zeroes */ | ||
993 | sp->tty->driver->write(sp->tty, &sp->led_state, 1); | ||
994 | rest = sp->rx_count; | ||
995 | if (rest != 0) | ||
996 | for (i = rest; i <= 3; i++) | ||
997 | decode_data(sp, 0); | ||
998 | if (rest == 2) | ||
999 | sp->rx_count_cooked -= 2; | ||
1000 | else if (rest == 3) | ||
1001 | sp->rx_count_cooked -= 1; | ||
1002 | for (i = 0; i < sp->rx_count_cooked; i++) | ||
1003 | checksum += sp->cooked_buf[i]; | ||
1004 | if (checksum != SIXP_CHKSUM) { | ||
1005 | printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); | ||
1006 | } else { | ||
1007 | sp->rcount = sp->rx_count_cooked-2; | ||
1008 | sp_bump(sp, 0); | ||
1009 | } | ||
1010 | sp->rx_count_cooked = 0; | ||
1011 | } | ||
1012 | break; | ||
1013 | case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); | ||
1014 | break; | ||
1015 | case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); | ||
1016 | break; | ||
1017 | case SIXP_RX_BUF_OVL: | ||
1018 | printk(KERN_DEBUG "6pack: RX buffer overflow\n"); | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | /* decode a 6pack packet */ | ||
1023 | |||
1024 | static void | ||
1025 | sixpack_decode(struct sixpack *sp, unsigned char *pre_rbuff, int count) | ||
1026 | { | ||
1027 | unsigned char inbyte; | ||
1028 | int count1; | ||
1029 | |||
1030 | for (count1 = 0; count1 < count; count1++) { | ||
1031 | inbyte = pre_rbuff[count1]; | ||
1032 | if (inbyte == SIXP_FOUND_TNC) { | ||
1033 | tnc_set_sync_state(sp, TNC_IN_SYNC); | ||
1034 | del_timer(&sp->resync_t); | ||
1035 | } | ||
1036 | if ((inbyte & SIXP_PRIO_CMD_MASK) != 0) | ||
1037 | decode_prio_command(sp, inbyte); | ||
1038 | else if ((inbyte & SIXP_STD_CMD_MASK) != 0) | ||
1039 | decode_std_command(sp, inbyte); | ||
1040 | else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) | ||
1041 | decode_data(sp, inbyte); | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>"); | ||
1046 | MODULE_DESCRIPTION("6pack driver for AX.25"); | ||
1047 | MODULE_LICENSE("GPL"); | ||
1048 | MODULE_ALIAS_LDISC(N_6PACK); | ||
1049 | |||
1050 | module_init(sixpack_init_driver); | ||
1051 | module_exit(sixpack_exit_driver); | ||
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig new file mode 100644 index 000000000000..34068f81d45e --- /dev/null +++ b/drivers/net/hamradio/Kconfig | |||
@@ -0,0 +1,191 @@ | |||
1 | config MKISS | ||
2 | tristate "Serial port KISS driver" | ||
3 | depends on AX25 && BROKEN_ON_SMP | ||
4 | ---help--- | ||
5 | KISS is a protocol used for the exchange of data between a computer | ||
6 | and a Terminal Node Controller (a small embedded system commonly | ||
7 | used for networking over AX.25 amateur radio connections; it | ||
8 | connects the computer's serial port with the radio's microphone | ||
9 | input and speaker output). | ||
10 | |||
11 | Although KISS is less advanced than the 6pack protocol, it has | ||
12 | the advantage that it is already supported by most modern TNCs | ||
13 | without the need for a firmware upgrade. | ||
14 | |||
15 | To compile this driver as a module, choose M here: the module | ||
16 | will be called mkiss. | ||
17 | |||
18 | config 6PACK | ||
19 | tristate "Serial port 6PACK driver" | ||
20 | depends on AX25 && BROKEN_ON_SMP | ||
21 | ---help--- | ||
22 | 6pack is a transmission protocol for the data exchange between your | ||
23 | PC and your TNC (the Terminal Node Controller acts as a kind of | ||
24 | modem connecting your computer's serial port to your radio's | ||
25 | microphone input and speaker output). This protocol can be used as | ||
26 | an alternative to KISS for networking over AX.25 amateur radio | ||
27 | connections, but it has some extended functionality. | ||
28 | |||
29 | Note that this driver is still experimental and might cause | ||
30 | problems. For details about the features and the usage of the | ||
31 | driver, read <file:Documentation/networking/6pack.txt>. | ||
32 | |||
33 | To compile this driver as a module, choose M here: the module | ||
34 | will be called 6pack. | ||
35 | |||
36 | config BPQETHER | ||
37 | tristate "BPQ Ethernet driver" | ||
38 | depends on AX25 | ||
39 | help | ||
40 | AX.25 is the protocol used for computer communication over amateur | ||
41 | radio. If you say Y here, you will be able to send and receive AX.25 | ||
42 | traffic over Ethernet (also called "BPQ AX.25"), which could be | ||
43 | useful if some other computer on your local network has a direct | ||
44 | amateur radio connection. | ||
45 | |||
46 | config DMASCC | ||
47 | tristate "High-speed (DMA) SCC driver for AX.25" | ||
48 | depends on ISA && AX25 && BROKEN_ON_SMP | ||
49 | ---help--- | ||
50 | This is a driver for high-speed SCC boards, i.e. those supporting | ||
51 | DMA on one port. You usually use those boards to connect your | ||
52 | computer to an amateur radio modem (such as the WA4DSY 56kbps | ||
53 | modem), in order to send and receive AX.25 packet radio network | ||
54 | traffic. | ||
55 | |||
56 | Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis | ||
57 | PackeTwin, and S5SCC/DMA boards. They are detected automatically. | ||
58 | If you have one of these cards, say Y here and read the AX25-HOWTO, | ||
59 | available from <http://www.tldp.org/docs.html#howto>. | ||
60 | |||
61 | This driver can operate multiple boards simultaneously. If you | ||
62 | compile it as a module (by saying M instead of Y), it will be called | ||
63 | dmascc. If you don't pass any parameter to the driver, all | ||
64 | possible I/O addresses are probed. This could irritate other devices | ||
65 | that are currently not in use. You may specify the list of addresses | ||
66 | to be probed by "dmascc=addr1,addr2,..." (when compiled into the | ||
67 | kernel image) or "io=addr1,addr2,..." (when loaded as a module). The | ||
68 | network interfaces will be called dmascc0 and dmascc1 for the board | ||
69 | detected first, dmascc2 and dmascc3 for the second one, and so on. | ||
70 | |||
71 | Before you configure each interface with ifconfig, you MUST set | ||
72 | certain parameters, such as channel access timing, clock mode, and | ||
73 | DMA channel. This is accomplished with a small utility program, | ||
74 | dmascc_cfg, available at | ||
75 | <http://cacofonix.nt.tuwien.ac.at/~oe1kib/Linux/>. Please be sure to | ||
76 | get at least version 1.27 of dmascc_cfg, as older versions will not | ||
77 | work with the current driver. | ||
78 | |||
79 | config SCC | ||
80 | tristate "Z8530 SCC driver" | ||
81 | depends on ISA && AX25 | ||
82 | ---help--- | ||
83 | These cards are used to connect your Linux box to an amateur radio | ||
84 | in order to communicate with other computers. If you want to use | ||
85 | this, read <file:Documentation/networking/z8530drv.txt> and the | ||
86 | AX25-HOWTO, available from | ||
87 | <http://www.tldp.org/docs.html#howto>. Also make sure to say Y | ||
88 | to "Amateur Radio AX.25 Level 2" support. | ||
89 | |||
90 | To compile this driver as a module, choose M here: the module | ||
91 | will be called scc. | ||
92 | |||
93 | config SCC_DELAY | ||
94 | bool "additional delay for PA0HZP OptoSCC compatible boards" | ||
95 | depends on SCC | ||
96 | help | ||
97 | Say Y here if you experience problems with the SCC driver not | ||
98 | working properly; please read | ||
99 | <file:Documentation/networking/z8530drv.txt> for details. | ||
100 | |||
101 | If unsure, say N. | ||
102 | |||
103 | config SCC_TRXECHO | ||
104 | bool "support for TRX that feedback the tx signal to rx" | ||
105 | depends on SCC | ||
106 | help | ||
107 | Some transmitters feed the transmitted signal back to the receive | ||
108 | line. Say Y here to foil this by explicitly disabling the receiver | ||
109 | during data transmission. | ||
110 | |||
111 | If in doubt, say Y. | ||
112 | |||
113 | config BAYCOM_SER_FDX | ||
114 | tristate "BAYCOM ser12 fullduplex driver for AX.25" | ||
115 | depends on AX25 | ||
116 | select CRC_CCITT | ||
117 | ---help--- | ||
118 | This is one of two drivers for Baycom style simple amateur radio | ||
119 | modems that connect to a serial interface. The driver supports the | ||
120 | ser12 design in full-duplex mode. In addition, it allows the | ||
121 | baudrate to be set between 300 and 4800 baud (however not all modems | ||
122 | support all baudrates). This is the preferred driver. The next | ||
123 | driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old | ||
124 | driver and still provided in case this driver does not work with | ||
125 | your serial interface chip. To configure the driver, use the sethdlc | ||
126 | utility available in the standard ax25 utilities package. For | ||
127 | information on the modems, see <http://www.baycom.de/> and | ||
128 | <file:Documentation/networking/baycom.txt>. | ||
129 | |||
130 | To compile this driver as a module, choose M here: the module | ||
131 | will be called baycom_ser_fdx. This is recommended. | ||
132 | |||
133 | config BAYCOM_SER_HDX | ||
134 | tristate "BAYCOM ser12 halfduplex driver for AX.25" | ||
135 | depends on AX25 | ||
136 | select CRC_CCITT | ||
137 | ---help--- | ||
138 | This is one of two drivers for Baycom style simple amateur radio | ||
139 | modems that connect to a serial interface. The driver supports the | ||
140 | ser12 design in full-duplex mode. This is the old driver. It is | ||
141 | still provided in case your serial interface chip does not work with | ||
142 | the full-duplex driver. This driver is depreciated. To configure | ||
143 | the driver, use the sethdlc utility available in the standard ax25 | ||
144 | utilities package. For information on the modems, see | ||
145 | <http://www.baycom.de/> and | ||
146 | <file:Documentation/networking/baycom.txt>. | ||
147 | |||
148 | To compile this driver as a module, choose M here: the module | ||
149 | will be called baycom_ser_hdx. This is recommended. | ||
150 | |||
151 | config BAYCOM_PAR | ||
152 | tristate "BAYCOM picpar and par96 driver for AX.25" | ||
153 | depends on PARPORT && AX25 | ||
154 | select CRC_CCITT | ||
155 | ---help--- | ||
156 | This is a driver for Baycom style simple amateur radio modems that | ||
157 | connect to a parallel interface. The driver supports the picpar and | ||
158 | par96 designs. To configure the driver, use the sethdlc utility | ||
159 | available in the standard ax25 utilities package. For information on | ||
160 | the modems, see <http://www.baycom.de/> and the file | ||
161 | <file:Documentation/networking/baycom.txt>. | ||
162 | |||
163 | To compile this driver as a module, choose M here: the module | ||
164 | will be called baycom_par. This is recommended. | ||
165 | |||
166 | config BAYCOM_EPP | ||
167 | tristate "BAYCOM epp driver for AX.25" | ||
168 | depends on PARPORT && AX25 && !64BIT | ||
169 | select CRC_CCITT | ||
170 | ---help--- | ||
171 | This is a driver for Baycom style simple amateur radio modems that | ||
172 | connect to a parallel interface. The driver supports the EPP | ||
173 | designs. To configure the driver, use the sethdlc utility available | ||
174 | in the standard ax25 utilities package. For information on the | ||
175 | modems, see <http://www.baycom.de/> and the file | ||
176 | <file:Documentation/networking/baycom.txt>. | ||
177 | |||
178 | To compile this driver as a module, choose M here: the module | ||
179 | will be called baycom_epp. This is recommended. | ||
180 | |||
181 | config YAM | ||
182 | tristate "YAM driver for AX.25" | ||
183 | depends on AX25 | ||
184 | help | ||
185 | The YAM is a modem for packet radio which connects to the serial | ||
186 | port and includes some of the functions of a Terminal Node | ||
187 | Controller. If you have one of those, say Y here. | ||
188 | |||
189 | To compile this driver as a module, choose M here: the module | ||
190 | will be called yam. | ||
191 | |||
diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile new file mode 100644 index 000000000000..9def86704a91 --- /dev/null +++ b/drivers/net/hamradio/Makefile | |||
@@ -0,0 +1,22 @@ | |||
1 | # | ||
2 | # Makefile for the Linux AX.25 and HFMODEM device drivers. | ||
3 | # | ||
4 | # | ||
5 | # 19971130 Moved the amateur radio related network drivers from | ||
6 | # drivers/net/ to drivers/hamradio for easier maintainance. | ||
7 | # Joerg Reuter DL1BKE <jreuter@yaina.de> | ||
8 | # | ||
9 | # 20000806 Rewritten to use lists instead of if-statements. | ||
10 | # Christoph Hellwig <hch@infradead.org> | ||
11 | # | ||
12 | |||
13 | obj-$(CONFIG_DMASCC) += dmascc.o | ||
14 | obj-$(CONFIG_SCC) += scc.o | ||
15 | obj-$(CONFIG_MKISS) += mkiss.o | ||
16 | obj-$(CONFIG_6PACK) += 6pack.o | ||
17 | obj-$(CONFIG_YAM) += yam.o | ||
18 | obj-$(CONFIG_BPQETHER) += bpqether.o | ||
19 | obj-$(CONFIG_BAYCOM_SER_FDX) += baycom_ser_fdx.o hdlcdrv.o | ||
20 | obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o | ||
21 | obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o | ||
22 | obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o | ||
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c new file mode 100644 index 000000000000..e8cb87d906fc --- /dev/null +++ b/drivers/net/hamradio/baycom_epp.c | |||
@@ -0,0 +1,1382 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * baycom_epp.c -- baycom epp radio modem driver. | ||
5 | * | ||
6 | * Copyright (C) 1998-2000 | ||
7 | * Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | * Please note that the GPL allows you to use the driver, NOT the radio. | ||
24 | * In order to use the radio, you need a license from the communications | ||
25 | * authority of your country. | ||
26 | * | ||
27 | * | ||
28 | * History: | ||
29 | * 0.1 xx.xx.1998 Initial version by Matthias Welwarsky (dg2fef) | ||
30 | * 0.2 21.04.1998 Massive rework by Thomas Sailer | ||
31 | * Integrated FPGA EPP modem configuration routines | ||
32 | * 0.3 11.05.1998 Took FPGA config out and moved it into a separate program | ||
33 | * 0.4 26.07.1999 Adapted to new lowlevel parport driver interface | ||
34 | * 0.5 03.08.1999 adapt to Linus' new __setup/__initcall | ||
35 | * removed some pre-2.2 kernel compatibility cruft | ||
36 | * 0.6 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts | ||
37 | * 0.7 12.02.2000 adapted to softnet driver interface | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | /*****************************************************************************/ | ||
42 | |||
43 | #include <linux/config.h> | ||
44 | #include <linux/module.h> | ||
45 | #include <linux/kernel.h> | ||
46 | #include <linux/init.h> | ||
47 | #include <linux/string.h> | ||
48 | #include <linux/workqueue.h> | ||
49 | #include <linux/fs.h> | ||
50 | #include <linux/parport.h> | ||
51 | #include <linux/smp_lock.h> | ||
52 | #include <asm/uaccess.h> | ||
53 | #include <linux/if_arp.h> | ||
54 | #include <linux/kmod.h> | ||
55 | #include <linux/hdlcdrv.h> | ||
56 | #include <linux/baycom.h> | ||
57 | #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) | ||
58 | /* prototypes for ax25_encapsulate and ax25_rebuild_header */ | ||
59 | #include <net/ax25.h> | ||
60 | #endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ | ||
61 | #include <linux/crc-ccitt.h> | ||
62 | |||
63 | /* --------------------------------------------------------------------- */ | ||
64 | |||
65 | #define BAYCOM_DEBUG | ||
66 | #define BAYCOM_MAGIC 19730510 | ||
67 | |||
68 | /* --------------------------------------------------------------------- */ | ||
69 | |||
70 | static const char paranoia_str[] = KERN_ERR | ||
71 | "baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n"; | ||
72 | |||
73 | static const char bc_drvname[] = "baycom_epp"; | ||
74 | static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n" | ||
75 | KERN_INFO "baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n"; | ||
76 | |||
77 | /* --------------------------------------------------------------------- */ | ||
78 | |||
79 | #define NR_PORTS 4 | ||
80 | |||
81 | static struct net_device *baycom_device[NR_PORTS]; | ||
82 | |||
83 | /* --------------------------------------------------------------------- */ | ||
84 | |||
85 | /* EPP status register */ | ||
86 | #define EPP_DCDBIT 0x80 | ||
87 | #define EPP_PTTBIT 0x08 | ||
88 | #define EPP_NREF 0x01 | ||
89 | #define EPP_NRAEF 0x02 | ||
90 | #define EPP_NRHF 0x04 | ||
91 | #define EPP_NTHF 0x20 | ||
92 | #define EPP_NTAEF 0x10 | ||
93 | #define EPP_NTEF EPP_PTTBIT | ||
94 | |||
95 | /* EPP control register */ | ||
96 | #define EPP_TX_FIFO_ENABLE 0x10 | ||
97 | #define EPP_RX_FIFO_ENABLE 0x08 | ||
98 | #define EPP_MODEM_ENABLE 0x20 | ||
99 | #define EPP_LEDS 0xC0 | ||
100 | #define EPP_IRQ_ENABLE 0x10 | ||
101 | |||
102 | /* LPT registers */ | ||
103 | #define LPTREG_ECONTROL 0x402 | ||
104 | #define LPTREG_CONFIGB 0x401 | ||
105 | #define LPTREG_CONFIGA 0x400 | ||
106 | #define LPTREG_EPPDATA 0x004 | ||
107 | #define LPTREG_EPPADDR 0x003 | ||
108 | #define LPTREG_CONTROL 0x002 | ||
109 | #define LPTREG_STATUS 0x001 | ||
110 | #define LPTREG_DATA 0x000 | ||
111 | |||
112 | /* LPT control register */ | ||
113 | #define LPTCTRL_PROGRAM 0x04 /* 0 to reprogram */ | ||
114 | #define LPTCTRL_WRITE 0x01 | ||
115 | #define LPTCTRL_ADDRSTB 0x08 | ||
116 | #define LPTCTRL_DATASTB 0x02 | ||
117 | #define LPTCTRL_INTEN 0x10 | ||
118 | |||
119 | /* LPT status register */ | ||
120 | #define LPTSTAT_SHIFT_NINTR 6 | ||
121 | #define LPTSTAT_WAIT 0x80 | ||
122 | #define LPTSTAT_NINTR (1<<LPTSTAT_SHIFT_NINTR) | ||
123 | #define LPTSTAT_PE 0x20 | ||
124 | #define LPTSTAT_DONE 0x10 | ||
125 | #define LPTSTAT_NERROR 0x08 | ||
126 | #define LPTSTAT_EPPTIMEOUT 0x01 | ||
127 | |||
128 | /* LPT data register */ | ||
129 | #define LPTDATA_SHIFT_TDI 0 | ||
130 | #define LPTDATA_SHIFT_TMS 2 | ||
131 | #define LPTDATA_TDI (1<<LPTDATA_SHIFT_TDI) | ||
132 | #define LPTDATA_TCK 0x02 | ||
133 | #define LPTDATA_TMS (1<<LPTDATA_SHIFT_TMS) | ||
134 | #define LPTDATA_INITBIAS 0x80 | ||
135 | |||
136 | |||
137 | /* EPP modem config/status bits */ | ||
138 | #define EPP_DCDBIT 0x80 | ||
139 | #define EPP_PTTBIT 0x08 | ||
140 | #define EPP_RXEBIT 0x01 | ||
141 | #define EPP_RXAEBIT 0x02 | ||
142 | #define EPP_RXHFULL 0x04 | ||
143 | |||
144 | #define EPP_NTHF 0x20 | ||
145 | #define EPP_NTAEF 0x10 | ||
146 | #define EPP_NTEF EPP_PTTBIT | ||
147 | |||
148 | #define EPP_TX_FIFO_ENABLE 0x10 | ||
149 | #define EPP_RX_FIFO_ENABLE 0x08 | ||
150 | #define EPP_MODEM_ENABLE 0x20 | ||
151 | #define EPP_LEDS 0xC0 | ||
152 | #define EPP_IRQ_ENABLE 0x10 | ||
153 | |||
154 | /* Xilinx 4k JTAG instructions */ | ||
155 | #define XC4K_IRLENGTH 3 | ||
156 | #define XC4K_EXTEST 0 | ||
157 | #define XC4K_PRELOAD 1 | ||
158 | #define XC4K_CONFIGURE 5 | ||
159 | #define XC4K_BYPASS 7 | ||
160 | |||
161 | #define EPP_CONVENTIONAL 0 | ||
162 | #define EPP_FPGA 1 | ||
163 | #define EPP_FPGAEXTSTATUS 2 | ||
164 | |||
165 | #define TXBUFFER_SIZE ((HDLCDRV_MAXFLEN*6/5)+8) | ||
166 | |||
167 | /* ---------------------------------------------------------------------- */ | ||
168 | /* | ||
169 | * Information that need to be kept for each board. | ||
170 | */ | ||
171 | |||
172 | struct baycom_state { | ||
173 | int magic; | ||
174 | |||
175 | struct pardevice *pdev; | ||
176 | unsigned int work_running; | ||
177 | struct work_struct run_work; | ||
178 | unsigned int modem; | ||
179 | unsigned int bitrate; | ||
180 | unsigned char stat; | ||
181 | |||
182 | struct { | ||
183 | unsigned int intclk; | ||
184 | unsigned int fclk; | ||
185 | unsigned int bps; | ||
186 | unsigned int extmodem; | ||
187 | unsigned int loopback; | ||
188 | } cfg; | ||
189 | |||
190 | struct hdlcdrv_channel_params ch_params; | ||
191 | |||
192 | struct { | ||
193 | unsigned int bitbuf, bitstream, numbits, state; | ||
194 | unsigned char *bufptr; | ||
195 | int bufcnt; | ||
196 | unsigned char buf[TXBUFFER_SIZE]; | ||
197 | } hdlcrx; | ||
198 | |||
199 | struct { | ||
200 | int calibrate; | ||
201 | int slotcnt; | ||
202 | int flags; | ||
203 | enum { tx_idle = 0, tx_keyup, tx_data, tx_tail } state; | ||
204 | unsigned char *bufptr; | ||
205 | int bufcnt; | ||
206 | unsigned char buf[TXBUFFER_SIZE]; | ||
207 | } hdlctx; | ||
208 | |||
209 | struct net_device_stats stats; | ||
210 | unsigned int ptt_keyed; | ||
211 | struct sk_buff *skb; /* next transmit packet */ | ||
212 | |||
213 | #ifdef BAYCOM_DEBUG | ||
214 | struct debug_vals { | ||
215 | unsigned long last_jiffies; | ||
216 | unsigned cur_intcnt; | ||
217 | unsigned last_intcnt; | ||
218 | int cur_pllcorr; | ||
219 | int last_pllcorr; | ||
220 | unsigned int mod_cycles; | ||
221 | unsigned int demod_cycles; | ||
222 | } debug_vals; | ||
223 | #endif /* BAYCOM_DEBUG */ | ||
224 | }; | ||
225 | |||
226 | /* --------------------------------------------------------------------- */ | ||
227 | |||
228 | #define KISS_VERBOSE | ||
229 | |||
230 | /* --------------------------------------------------------------------- */ | ||
231 | |||
232 | #define PARAM_TXDELAY 1 | ||
233 | #define PARAM_PERSIST 2 | ||
234 | #define PARAM_SLOTTIME 3 | ||
235 | #define PARAM_TXTAIL 4 | ||
236 | #define PARAM_FULLDUP 5 | ||
237 | #define PARAM_HARDWARE 6 | ||
238 | #define PARAM_RETURN 255 | ||
239 | |||
240 | /* --------------------------------------------------------------------- */ | ||
241 | /* | ||
242 | * the CRC routines are stolen from WAMPES | ||
243 | * by Dieter Deyke | ||
244 | */ | ||
245 | |||
246 | |||
247 | /*---------------------------------------------------------------------------*/ | ||
248 | |||
249 | #if 0 | ||
250 | static inline void append_crc_ccitt(unsigned char *buffer, int len) | ||
251 | { | ||
252 | unsigned int crc = 0xffff; | ||
253 | |||
254 | for (;len>0;len--) | ||
255 | crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff]; | ||
256 | crc ^= 0xffff; | ||
257 | *buffer++ = crc; | ||
258 | *buffer++ = crc >> 8; | ||
259 | } | ||
260 | #endif | ||
261 | |||
262 | /*---------------------------------------------------------------------------*/ | ||
263 | |||
264 | static inline int check_crc_ccitt(const unsigned char *buf, int cnt) | ||
265 | { | ||
266 | return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8; | ||
267 | } | ||
268 | |||
269 | /*---------------------------------------------------------------------------*/ | ||
270 | |||
271 | static inline int calc_crc_ccitt(const unsigned char *buf, int cnt) | ||
272 | { | ||
273 | return (crc_ccitt(0xffff, buf, cnt) ^ 0xffff) & 0xffff; | ||
274 | } | ||
275 | |||
276 | /* ---------------------------------------------------------------------- */ | ||
277 | |||
278 | #define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800) | ||
279 | |||
280 | /* --------------------------------------------------------------------- */ | ||
281 | |||
282 | static inline void baycom_int_freq(struct baycom_state *bc) | ||
283 | { | ||
284 | #ifdef BAYCOM_DEBUG | ||
285 | unsigned long cur_jiffies = jiffies; | ||
286 | /* | ||
287 | * measure the interrupt frequency | ||
288 | */ | ||
289 | bc->debug_vals.cur_intcnt++; | ||
290 | if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { | ||
291 | bc->debug_vals.last_jiffies = cur_jiffies; | ||
292 | bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; | ||
293 | bc->debug_vals.cur_intcnt = 0; | ||
294 | bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; | ||
295 | bc->debug_vals.cur_pllcorr = 0; | ||
296 | } | ||
297 | #endif /* BAYCOM_DEBUG */ | ||
298 | } | ||
299 | |||
300 | /* ---------------------------------------------------------------------- */ | ||
301 | /* | ||
302 | * eppconfig_path should be setable via /proc/sys. | ||
303 | */ | ||
304 | |||
305 | static char eppconfig_path[256] = "/usr/sbin/eppfpga"; | ||
306 | |||
307 | static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; | ||
308 | |||
309 | /* eppconfig: called during ifconfig up to configure the modem */ | ||
310 | static int eppconfig(struct baycom_state *bc) | ||
311 | { | ||
312 | char modearg[256]; | ||
313 | char portarg[16]; | ||
314 | char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, | ||
315 | NULL }; | ||
316 | |||
317 | /* set up arguments */ | ||
318 | sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", | ||
319 | bc->cfg.intclk ? "int" : "ext", | ||
320 | bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, | ||
321 | (bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps), | ||
322 | bc->cfg.loopback ? ",loopback" : ""); | ||
323 | sprintf(portarg, "%ld", bc->pdev->port->base); | ||
324 | printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); | ||
325 | |||
326 | return call_usermodehelper(eppconfig_path, argv, envp, 1); | ||
327 | } | ||
328 | |||
329 | /* ---------------------------------------------------------------------- */ | ||
330 | |||
331 | static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
332 | { | ||
333 | } | ||
334 | |||
335 | /* ---------------------------------------------------------------------- */ | ||
336 | |||
337 | static inline void do_kiss_params(struct baycom_state *bc, | ||
338 | unsigned char *data, unsigned long len) | ||
339 | { | ||
340 | |||
341 | #ifdef KISS_VERBOSE | ||
342 | #define PKP(a,b) printk(KERN_INFO "baycomm_epp: channel params: " a "\n", b) | ||
343 | #else /* KISS_VERBOSE */ | ||
344 | #define PKP(a,b) | ||
345 | #endif /* KISS_VERBOSE */ | ||
346 | |||
347 | if (len < 2) | ||
348 | return; | ||
349 | switch(data[0]) { | ||
350 | case PARAM_TXDELAY: | ||
351 | bc->ch_params.tx_delay = data[1]; | ||
352 | PKP("TX delay = %ums", 10 * bc->ch_params.tx_delay); | ||
353 | break; | ||
354 | case PARAM_PERSIST: | ||
355 | bc->ch_params.ppersist = data[1]; | ||
356 | PKP("p persistence = %u", bc->ch_params.ppersist); | ||
357 | break; | ||
358 | case PARAM_SLOTTIME: | ||
359 | bc->ch_params.slottime = data[1]; | ||
360 | PKP("slot time = %ums", bc->ch_params.slottime); | ||
361 | break; | ||
362 | case PARAM_TXTAIL: | ||
363 | bc->ch_params.tx_tail = data[1]; | ||
364 | PKP("TX tail = %ums", bc->ch_params.tx_tail); | ||
365 | break; | ||
366 | case PARAM_FULLDUP: | ||
367 | bc->ch_params.fulldup = !!data[1]; | ||
368 | PKP("%s duplex", bc->ch_params.fulldup ? "full" : "half"); | ||
369 | break; | ||
370 | default: | ||
371 | break; | ||
372 | } | ||
373 | #undef PKP | ||
374 | } | ||
375 | |||
376 | /* --------------------------------------------------------------------- */ | ||
377 | /* | ||
378 | * high performance HDLC encoder | ||
379 | * yes, it's ugly, but generates pretty good code | ||
380 | */ | ||
381 | |||
382 | #define ENCODEITERA(j) \ | ||
383 | ({ \ | ||
384 | if (!(notbitstream & (0x1f0 << j))) \ | ||
385 | goto stuff##j; \ | ||
386 | encodeend##j: ; \ | ||
387 | }) | ||
388 | |||
389 | #define ENCODEITERB(j) \ | ||
390 | ({ \ | ||
391 | stuff##j: \ | ||
392 | bitstream &= ~(0x100 << j); \ | ||
393 | bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | \ | ||
394 | ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); \ | ||
395 | numbit++; \ | ||
396 | notbitstream = ~bitstream; \ | ||
397 | goto encodeend##j; \ | ||
398 | }) | ||
399 | |||
400 | |||
401 | static void encode_hdlc(struct baycom_state *bc) | ||
402 | { | ||
403 | struct sk_buff *skb; | ||
404 | unsigned char *wp, *bp; | ||
405 | int pkt_len; | ||
406 | unsigned bitstream, notbitstream, bitbuf, numbit, crc; | ||
407 | unsigned char crcarr[2]; | ||
408 | |||
409 | if (bc->hdlctx.bufcnt > 0) | ||
410 | return; | ||
411 | skb = bc->skb; | ||
412 | if (!skb) | ||
413 | return; | ||
414 | bc->skb = NULL; | ||
415 | pkt_len = skb->len-1; /* strip KISS byte */ | ||
416 | wp = bc->hdlctx.buf; | ||
417 | bp = skb->data+1; | ||
418 | crc = calc_crc_ccitt(bp, pkt_len); | ||
419 | crcarr[0] = crc; | ||
420 | crcarr[1] = crc >> 8; | ||
421 | *wp++ = 0x7e; | ||
422 | bitstream = bitbuf = numbit = 0; | ||
423 | while (pkt_len > -2) { | ||
424 | bitstream >>= 8; | ||
425 | bitstream |= ((unsigned int)*bp) << 8; | ||
426 | bitbuf |= ((unsigned int)*bp) << numbit; | ||
427 | notbitstream = ~bitstream; | ||
428 | bp++; | ||
429 | pkt_len--; | ||
430 | if (!pkt_len) | ||
431 | bp = crcarr; | ||
432 | ENCODEITERA(0); | ||
433 | ENCODEITERA(1); | ||
434 | ENCODEITERA(2); | ||
435 | ENCODEITERA(3); | ||
436 | ENCODEITERA(4); | ||
437 | ENCODEITERA(5); | ||
438 | ENCODEITERA(6); | ||
439 | ENCODEITERA(7); | ||
440 | goto enditer; | ||
441 | ENCODEITERB(0); | ||
442 | ENCODEITERB(1); | ||
443 | ENCODEITERB(2); | ||
444 | ENCODEITERB(3); | ||
445 | ENCODEITERB(4); | ||
446 | ENCODEITERB(5); | ||
447 | ENCODEITERB(6); | ||
448 | ENCODEITERB(7); | ||
449 | enditer: | ||
450 | numbit += 8; | ||
451 | while (numbit >= 8) { | ||
452 | *wp++ = bitbuf; | ||
453 | bitbuf >>= 8; | ||
454 | numbit -= 8; | ||
455 | } | ||
456 | } | ||
457 | bitbuf |= 0x7e7e << numbit; | ||
458 | numbit += 16; | ||
459 | while (numbit >= 8) { | ||
460 | *wp++ = bitbuf; | ||
461 | bitbuf >>= 8; | ||
462 | numbit -= 8; | ||
463 | } | ||
464 | bc->hdlctx.bufptr = bc->hdlctx.buf; | ||
465 | bc->hdlctx.bufcnt = wp - bc->hdlctx.buf; | ||
466 | dev_kfree_skb(skb); | ||
467 | bc->stats.tx_packets++; | ||
468 | } | ||
469 | |||
470 | /* ---------------------------------------------------------------------- */ | ||
471 | |||
472 | static unsigned short random_seed; | ||
473 | |||
474 | static inline unsigned short random_num(void) | ||
475 | { | ||
476 | random_seed = 28629 * random_seed + 157; | ||
477 | return random_seed; | ||
478 | } | ||
479 | |||
480 | /* ---------------------------------------------------------------------- */ | ||
481 | |||
482 | static int transmit(struct baycom_state *bc, int cnt, unsigned char stat) | ||
483 | { | ||
484 | struct parport *pp = bc->pdev->port; | ||
485 | unsigned char tmp[128]; | ||
486 | int i, j; | ||
487 | |||
488 | if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT)) | ||
489 | bc->hdlctx.state = tx_idle; | ||
490 | if (bc->hdlctx.state == tx_idle && bc->hdlctx.calibrate <= 0) { | ||
491 | if (bc->hdlctx.bufcnt <= 0) | ||
492 | encode_hdlc(bc); | ||
493 | if (bc->hdlctx.bufcnt <= 0) | ||
494 | return 0; | ||
495 | if (!bc->ch_params.fulldup) { | ||
496 | if (!(stat & EPP_DCDBIT)) { | ||
497 | bc->hdlctx.slotcnt = bc->ch_params.slottime; | ||
498 | return 0; | ||
499 | } | ||
500 | if ((--bc->hdlctx.slotcnt) > 0) | ||
501 | return 0; | ||
502 | bc->hdlctx.slotcnt = bc->ch_params.slottime; | ||
503 | if ((random_num() % 256) > bc->ch_params.ppersist) | ||
504 | return 0; | ||
505 | } | ||
506 | } | ||
507 | if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) { | ||
508 | bc->hdlctx.state = tx_keyup; | ||
509 | bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_delay); | ||
510 | bc->ptt_keyed++; | ||
511 | } | ||
512 | while (cnt > 0) { | ||
513 | switch (bc->hdlctx.state) { | ||
514 | case tx_keyup: | ||
515 | i = min_t(int, cnt, bc->hdlctx.flags); | ||
516 | cnt -= i; | ||
517 | bc->hdlctx.flags -= i; | ||
518 | if (bc->hdlctx.flags <= 0) | ||
519 | bc->hdlctx.state = tx_data; | ||
520 | memset(tmp, 0x7e, sizeof(tmp)); | ||
521 | while (i > 0) { | ||
522 | j = (i > sizeof(tmp)) ? sizeof(tmp) : i; | ||
523 | if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) | ||
524 | return -1; | ||
525 | i -= j; | ||
526 | } | ||
527 | break; | ||
528 | |||
529 | case tx_data: | ||
530 | if (bc->hdlctx.bufcnt <= 0) { | ||
531 | encode_hdlc(bc); | ||
532 | if (bc->hdlctx.bufcnt <= 0) { | ||
533 | bc->hdlctx.state = tx_tail; | ||
534 | bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_tail); | ||
535 | break; | ||
536 | } | ||
537 | } | ||
538 | i = min_t(int, cnt, bc->hdlctx.bufcnt); | ||
539 | bc->hdlctx.bufcnt -= i; | ||
540 | cnt -= i; | ||
541 | if (i != pp->ops->epp_write_data(pp, bc->hdlctx.bufptr, i, 0)) | ||
542 | return -1; | ||
543 | bc->hdlctx.bufptr += i; | ||
544 | break; | ||
545 | |||
546 | case tx_tail: | ||
547 | encode_hdlc(bc); | ||
548 | if (bc->hdlctx.bufcnt > 0) { | ||
549 | bc->hdlctx.state = tx_data; | ||
550 | break; | ||
551 | } | ||
552 | i = min_t(int, cnt, bc->hdlctx.flags); | ||
553 | if (i) { | ||
554 | cnt -= i; | ||
555 | bc->hdlctx.flags -= i; | ||
556 | memset(tmp, 0x7e, sizeof(tmp)); | ||
557 | while (i > 0) { | ||
558 | j = (i > sizeof(tmp)) ? sizeof(tmp) : i; | ||
559 | if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) | ||
560 | return -1; | ||
561 | i -= j; | ||
562 | } | ||
563 | break; | ||
564 | } | ||
565 | |||
566 | default: /* fall through */ | ||
567 | if (bc->hdlctx.calibrate <= 0) | ||
568 | return 0; | ||
569 | i = min_t(int, cnt, bc->hdlctx.calibrate); | ||
570 | cnt -= i; | ||
571 | bc->hdlctx.calibrate -= i; | ||
572 | memset(tmp, 0, sizeof(tmp)); | ||
573 | while (i > 0) { | ||
574 | j = (i > sizeof(tmp)) ? sizeof(tmp) : i; | ||
575 | if (j != pp->ops->epp_write_data(pp, tmp, j, 0)) | ||
576 | return -1; | ||
577 | i -= j; | ||
578 | } | ||
579 | break; | ||
580 | } | ||
581 | } | ||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | /* ---------------------------------------------------------------------- */ | ||
586 | |||
587 | static void do_rxpacket(struct net_device *dev) | ||
588 | { | ||
589 | struct baycom_state *bc = netdev_priv(dev); | ||
590 | struct sk_buff *skb; | ||
591 | unsigned char *cp; | ||
592 | unsigned pktlen; | ||
593 | |||
594 | if (bc->hdlcrx.bufcnt < 4) | ||
595 | return; | ||
596 | if (!check_crc_ccitt(bc->hdlcrx.buf, bc->hdlcrx.bufcnt)) | ||
597 | return; | ||
598 | pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */ | ||
599 | if (!(skb = dev_alloc_skb(pktlen))) { | ||
600 | printk("%s: memory squeeze, dropping packet\n", dev->name); | ||
601 | bc->stats.rx_dropped++; | ||
602 | return; | ||
603 | } | ||
604 | skb->dev = dev; | ||
605 | cp = skb_put(skb, pktlen); | ||
606 | *cp++ = 0; /* KISS kludge */ | ||
607 | memcpy(cp, bc->hdlcrx.buf, pktlen - 1); | ||
608 | skb->protocol = htons(ETH_P_AX25); | ||
609 | skb->mac.raw = skb->data; | ||
610 | netif_rx(skb); | ||
611 | dev->last_rx = jiffies; | ||
612 | bc->stats.rx_packets++; | ||
613 | } | ||
614 | |||
615 | #define DECODEITERA(j) \ | ||
616 | ({ \ | ||
617 | if (!(notbitstream & (0x0fc << j))) /* flag or abort */ \ | ||
618 | goto flgabrt##j; \ | ||
619 | if ((bitstream & (0x1f8 << j)) == (0xf8 << j)) /* stuffed bit */ \ | ||
620 | goto stuff##j; \ | ||
621 | enditer##j: ; \ | ||
622 | }) | ||
623 | |||
624 | #define DECODEITERB(j) \ | ||
625 | ({ \ | ||
626 | flgabrt##j: \ | ||
627 | if (!(notbitstream & (0x1fc << j))) { /* abort received */ \ | ||
628 | state = 0; \ | ||
629 | goto enditer##j; \ | ||
630 | } \ | ||
631 | if ((bitstream & (0x1fe << j)) != (0x0fc << j)) /* flag received */ \ | ||
632 | goto enditer##j; \ | ||
633 | if (state) \ | ||
634 | do_rxpacket(dev); \ | ||
635 | bc->hdlcrx.bufcnt = 0; \ | ||
636 | bc->hdlcrx.bufptr = bc->hdlcrx.buf; \ | ||
637 | state = 1; \ | ||
638 | numbits = 7-j; \ | ||
639 | goto enditer##j; \ | ||
640 | stuff##j: \ | ||
641 | numbits--; \ | ||
642 | bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1); \ | ||
643 | goto enditer##j; \ | ||
644 | }) | ||
645 | |||
646 | static int receive(struct net_device *dev, int cnt) | ||
647 | { | ||
648 | struct baycom_state *bc = netdev_priv(dev); | ||
649 | struct parport *pp = bc->pdev->port; | ||
650 | unsigned int bitbuf, notbitstream, bitstream, numbits, state; | ||
651 | unsigned char tmp[128]; | ||
652 | unsigned char *cp; | ||
653 | int cnt2, ret = 0; | ||
654 | |||
655 | numbits = bc->hdlcrx.numbits; | ||
656 | state = bc->hdlcrx.state; | ||
657 | bitstream = bc->hdlcrx.bitstream; | ||
658 | bitbuf = bc->hdlcrx.bitbuf; | ||
659 | while (cnt > 0) { | ||
660 | cnt2 = (cnt > sizeof(tmp)) ? sizeof(tmp) : cnt; | ||
661 | cnt -= cnt2; | ||
662 | if (cnt2 != pp->ops->epp_read_data(pp, tmp, cnt2, 0)) { | ||
663 | ret = -1; | ||
664 | break; | ||
665 | } | ||
666 | cp = tmp; | ||
667 | for (; cnt2 > 0; cnt2--, cp++) { | ||
668 | bitstream >>= 8; | ||
669 | bitstream |= (*cp) << 8; | ||
670 | bitbuf >>= 8; | ||
671 | bitbuf |= (*cp) << 8; | ||
672 | numbits += 8; | ||
673 | notbitstream = ~bitstream; | ||
674 | DECODEITERA(0); | ||
675 | DECODEITERA(1); | ||
676 | DECODEITERA(2); | ||
677 | DECODEITERA(3); | ||
678 | DECODEITERA(4); | ||
679 | DECODEITERA(5); | ||
680 | DECODEITERA(6); | ||
681 | DECODEITERA(7); | ||
682 | goto enddec; | ||
683 | DECODEITERB(0); | ||
684 | DECODEITERB(1); | ||
685 | DECODEITERB(2); | ||
686 | DECODEITERB(3); | ||
687 | DECODEITERB(4); | ||
688 | DECODEITERB(5); | ||
689 | DECODEITERB(6); | ||
690 | DECODEITERB(7); | ||
691 | enddec: | ||
692 | while (state && numbits >= 8) { | ||
693 | if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) { | ||
694 | state = 0; | ||
695 | } else { | ||
696 | *(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits); | ||
697 | bc->hdlcrx.bufcnt++; | ||
698 | numbits -= 8; | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | bc->hdlcrx.numbits = numbits; | ||
704 | bc->hdlcrx.state = state; | ||
705 | bc->hdlcrx.bitstream = bitstream; | ||
706 | bc->hdlcrx.bitbuf = bitbuf; | ||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | /* --------------------------------------------------------------------- */ | ||
711 | |||
712 | #ifdef __i386__ | ||
713 | #include <asm/msr.h> | ||
714 | #define GETTICK(x) \ | ||
715 | ({ \ | ||
716 | if (cpu_has_tsc) \ | ||
717 | rdtscl(x); \ | ||
718 | }) | ||
719 | #else /* __i386__ */ | ||
720 | #define GETTICK(x) | ||
721 | #endif /* __i386__ */ | ||
722 | |||
723 | static void epp_bh(struct net_device *dev) | ||
724 | { | ||
725 | struct baycom_state *bc; | ||
726 | struct parport *pp; | ||
727 | unsigned char stat; | ||
728 | unsigned char tmp[2]; | ||
729 | unsigned int time1 = 0, time2 = 0, time3 = 0; | ||
730 | int cnt, cnt2; | ||
731 | |||
732 | bc = netdev_priv(dev); | ||
733 | if (!bc->work_running) | ||
734 | return; | ||
735 | baycom_int_freq(bc); | ||
736 | pp = bc->pdev->port; | ||
737 | /* update status */ | ||
738 | if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | ||
739 | goto epptimeout; | ||
740 | bc->stat = stat; | ||
741 | bc->debug_vals.last_pllcorr = stat; | ||
742 | GETTICK(time1); | ||
743 | if (bc->modem == EPP_FPGAEXTSTATUS) { | ||
744 | /* get input count */ | ||
745 | tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1; | ||
746 | if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | ||
747 | goto epptimeout; | ||
748 | if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) | ||
749 | goto epptimeout; | ||
750 | cnt = tmp[0] | (tmp[1] << 8); | ||
751 | cnt &= 0x7fff; | ||
752 | /* get output count */ | ||
753 | tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2; | ||
754 | if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | ||
755 | goto epptimeout; | ||
756 | if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2) | ||
757 | goto epptimeout; | ||
758 | cnt2 = tmp[0] | (tmp[1] << 8); | ||
759 | cnt2 = 16384 - (cnt2 & 0x7fff); | ||
760 | /* return to normal */ | ||
761 | tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; | ||
762 | if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | ||
763 | goto epptimeout; | ||
764 | if (transmit(bc, cnt2, stat)) | ||
765 | goto epptimeout; | ||
766 | GETTICK(time2); | ||
767 | if (receive(dev, cnt)) | ||
768 | goto epptimeout; | ||
769 | if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | ||
770 | goto epptimeout; | ||
771 | bc->stat = stat; | ||
772 | } else { | ||
773 | /* try to tx */ | ||
774 | switch (stat & (EPP_NTAEF|EPP_NTHF)) { | ||
775 | case EPP_NTHF: | ||
776 | cnt = 2048 - 256; | ||
777 | break; | ||
778 | |||
779 | case EPP_NTAEF: | ||
780 | cnt = 2048 - 1793; | ||
781 | break; | ||
782 | |||
783 | case 0: | ||
784 | cnt = 0; | ||
785 | break; | ||
786 | |||
787 | default: | ||
788 | cnt = 2048 - 1025; | ||
789 | break; | ||
790 | } | ||
791 | if (transmit(bc, cnt, stat)) | ||
792 | goto epptimeout; | ||
793 | GETTICK(time2); | ||
794 | /* do receiver */ | ||
795 | while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) { | ||
796 | switch (stat & (EPP_NRAEF|EPP_NRHF)) { | ||
797 | case EPP_NRAEF: | ||
798 | cnt = 1025; | ||
799 | break; | ||
800 | |||
801 | case 0: | ||
802 | cnt = 1793; | ||
803 | break; | ||
804 | |||
805 | default: | ||
806 | cnt = 256; | ||
807 | break; | ||
808 | } | ||
809 | if (receive(dev, cnt)) | ||
810 | goto epptimeout; | ||
811 | if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | ||
812 | goto epptimeout; | ||
813 | } | ||
814 | cnt = 0; | ||
815 | if (bc->bitrate < 50000) | ||
816 | cnt = 256; | ||
817 | else if (bc->bitrate < 100000) | ||
818 | cnt = 128; | ||
819 | while (cnt > 0 && stat & EPP_NREF) { | ||
820 | if (receive(dev, 1)) | ||
821 | goto epptimeout; | ||
822 | cnt--; | ||
823 | if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | ||
824 | goto epptimeout; | ||
825 | } | ||
826 | } | ||
827 | GETTICK(time3); | ||
828 | #ifdef BAYCOM_DEBUG | ||
829 | bc->debug_vals.mod_cycles = time2 - time1; | ||
830 | bc->debug_vals.demod_cycles = time3 - time2; | ||
831 | #endif /* BAYCOM_DEBUG */ | ||
832 | schedule_delayed_work(&bc->run_work, 1); | ||
833 | if (!bc->skb) | ||
834 | netif_wake_queue(dev); | ||
835 | return; | ||
836 | epptimeout: | ||
837 | printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname); | ||
838 | } | ||
839 | |||
840 | /* ---------------------------------------------------------------------- */ | ||
841 | /* | ||
842 | * ===================== network driver interface ========================= | ||
843 | */ | ||
844 | |||
845 | static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
846 | { | ||
847 | struct baycom_state *bc = netdev_priv(dev); | ||
848 | |||
849 | if (skb->data[0] != 0) { | ||
850 | do_kiss_params(bc, skb->data, skb->len); | ||
851 | dev_kfree_skb(skb); | ||
852 | return 0; | ||
853 | } | ||
854 | if (bc->skb) | ||
855 | return -1; | ||
856 | /* strip KISS byte */ | ||
857 | if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { | ||
858 | dev_kfree_skb(skb); | ||
859 | return 0; | ||
860 | } | ||
861 | netif_stop_queue(dev); | ||
862 | bc->skb = skb; | ||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | /* --------------------------------------------------------------------- */ | ||
867 | |||
868 | static int baycom_set_mac_address(struct net_device *dev, void *addr) | ||
869 | { | ||
870 | struct sockaddr *sa = (struct sockaddr *)addr; | ||
871 | |||
872 | /* addr is an AX.25 shifted ASCII mac address */ | ||
873 | memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); | ||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | /* --------------------------------------------------------------------- */ | ||
878 | |||
879 | static struct net_device_stats *baycom_get_stats(struct net_device *dev) | ||
880 | { | ||
881 | struct baycom_state *bc = netdev_priv(dev); | ||
882 | |||
883 | /* | ||
884 | * Get the current statistics. This may be called with the | ||
885 | * card open or closed. | ||
886 | */ | ||
887 | return &bc->stats; | ||
888 | } | ||
889 | |||
890 | /* --------------------------------------------------------------------- */ | ||
891 | |||
892 | static void epp_wakeup(void *handle) | ||
893 | { | ||
894 | struct net_device *dev = (struct net_device *)handle; | ||
895 | struct baycom_state *bc = netdev_priv(dev); | ||
896 | |||
897 | printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name); | ||
898 | if (!parport_claim(bc->pdev)) | ||
899 | printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name); | ||
900 | } | ||
901 | |||
902 | /* --------------------------------------------------------------------- */ | ||
903 | |||
904 | /* | ||
905 | * Open/initialize the board. This is called (in the current kernel) | ||
906 | * sometime after booting when the 'ifconfig' program is run. | ||
907 | * | ||
908 | * This routine should set everything up anew at each open, even | ||
909 | * registers that "should" only need to be set once at boot, so that | ||
910 | * there is non-reboot way to recover if something goes wrong. | ||
911 | */ | ||
912 | |||
913 | static int epp_open(struct net_device *dev) | ||
914 | { | ||
915 | struct baycom_state *bc = netdev_priv(dev); | ||
916 | struct parport *pp = parport_find_base(dev->base_addr); | ||
917 | unsigned int i, j; | ||
918 | unsigned char tmp[128]; | ||
919 | unsigned char stat; | ||
920 | unsigned long tstart; | ||
921 | |||
922 | if (!pp) { | ||
923 | printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr); | ||
924 | return -ENXIO; | ||
925 | } | ||
926 | #if 0 | ||
927 | if (pp->irq < 0) { | ||
928 | printk(KERN_ERR "%s: parport at 0x%lx has no irq\n", bc_drvname, pp->base); | ||
929 | parport_put_port(pp); | ||
930 | return -ENXIO; | ||
931 | } | ||
932 | #endif | ||
933 | if ((~pp->modes) & (PARPORT_MODE_TRISTATE | PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { | ||
934 | printk(KERN_ERR "%s: parport at 0x%lx cannot be used\n", | ||
935 | bc_drvname, pp->base); | ||
936 | parport_put_port(pp); | ||
937 | return -EIO; | ||
938 | } | ||
939 | memset(&bc->modem, 0, sizeof(bc->modem)); | ||
940 | bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup, | ||
941 | epp_interrupt, PARPORT_DEV_EXCL, dev); | ||
942 | parport_put_port(pp); | ||
943 | if (!bc->pdev) { | ||
944 | printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base); | ||
945 | return -ENXIO; | ||
946 | } | ||
947 | if (parport_claim(bc->pdev)) { | ||
948 | printk(KERN_ERR "%s: parport at 0x%lx busy\n", bc_drvname, pp->base); | ||
949 | parport_unregister_device(bc->pdev); | ||
950 | return -EBUSY; | ||
951 | } | ||
952 | dev->irq = /*pp->irq*/ 0; | ||
953 | INIT_WORK(&bc->run_work, (void *)(void *)epp_bh, dev); | ||
954 | bc->work_running = 1; | ||
955 | bc->modem = EPP_CONVENTIONAL; | ||
956 | if (eppconfig(bc)) | ||
957 | printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname); | ||
958 | else | ||
959 | bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS; | ||
960 | parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */ | ||
961 | /* reset the modem */ | ||
962 | tmp[0] = 0; | ||
963 | tmp[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE; | ||
964 | if (pp->ops->epp_write_addr(pp, tmp, 2, 0) != 2) | ||
965 | goto epptimeout; | ||
966 | /* autoprobe baud rate */ | ||
967 | tstart = jiffies; | ||
968 | i = 0; | ||
969 | while ((signed)(jiffies-tstart-HZ/3) < 0) { | ||
970 | if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | ||
971 | goto epptimeout; | ||
972 | if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) { | ||
973 | schedule(); | ||
974 | continue; | ||
975 | } | ||
976 | if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) | ||
977 | goto epptimeout; | ||
978 | if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128) | ||
979 | goto epptimeout; | ||
980 | i += 256; | ||
981 | } | ||
982 | for (j = 0; j < 256; j++) { | ||
983 | if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) | ||
984 | goto epptimeout; | ||
985 | if (!(stat & EPP_NREF)) | ||
986 | break; | ||
987 | if (pp->ops->epp_read_data(pp, tmp, 1, 0) != 1) | ||
988 | goto epptimeout; | ||
989 | i++; | ||
990 | } | ||
991 | tstart = jiffies - tstart; | ||
992 | bc->bitrate = i * (8 * HZ) / tstart; | ||
993 | j = 1; | ||
994 | i = bc->bitrate >> 3; | ||
995 | while (j < 7 && i > 150) { | ||
996 | j++; | ||
997 | i >>= 1; | ||
998 | } | ||
999 | printk(KERN_INFO "%s: autoprobed bitrate: %d int divider: %d int rate: %d\n", | ||
1000 | bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2)); | ||
1001 | tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/; | ||
1002 | if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1) | ||
1003 | goto epptimeout; | ||
1004 | /* | ||
1005 | * initialise hdlc variables | ||
1006 | */ | ||
1007 | bc->hdlcrx.state = 0; | ||
1008 | bc->hdlcrx.numbits = 0; | ||
1009 | bc->hdlctx.state = tx_idle; | ||
1010 | bc->hdlctx.bufcnt = 0; | ||
1011 | bc->hdlctx.slotcnt = bc->ch_params.slottime; | ||
1012 | bc->hdlctx.calibrate = 0; | ||
1013 | /* start the bottom half stuff */ | ||
1014 | schedule_delayed_work(&bc->run_work, 1); | ||
1015 | netif_start_queue(dev); | ||
1016 | return 0; | ||
1017 | |||
1018 | epptimeout: | ||
1019 | printk(KERN_ERR "%s: epp timeout during bitrate probe\n", bc_drvname); | ||
1020 | parport_write_control(pp, 0); /* reset the adapter */ | ||
1021 | parport_release(bc->pdev); | ||
1022 | parport_unregister_device(bc->pdev); | ||
1023 | return -EIO; | ||
1024 | } | ||
1025 | |||
1026 | /* --------------------------------------------------------------------- */ | ||
1027 | |||
1028 | static int epp_close(struct net_device *dev) | ||
1029 | { | ||
1030 | struct baycom_state *bc = netdev_priv(dev); | ||
1031 | struct parport *pp = bc->pdev->port; | ||
1032 | unsigned char tmp[1]; | ||
1033 | |||
1034 | bc->work_running = 0; | ||
1035 | flush_scheduled_work(); | ||
1036 | bc->stat = EPP_DCDBIT; | ||
1037 | tmp[0] = 0; | ||
1038 | pp->ops->epp_write_addr(pp, tmp, 1, 0); | ||
1039 | parport_write_control(pp, 0); /* reset the adapter */ | ||
1040 | parport_release(bc->pdev); | ||
1041 | parport_unregister_device(bc->pdev); | ||
1042 | if (bc->skb) | ||
1043 | dev_kfree_skb(bc->skb); | ||
1044 | bc->skb = NULL; | ||
1045 | printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n", | ||
1046 | bc_drvname, dev->base_addr, dev->irq); | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | /* --------------------------------------------------------------------- */ | ||
1051 | |||
1052 | static int baycom_setmode(struct baycom_state *bc, const char *modestr) | ||
1053 | { | ||
1054 | const char *cp; | ||
1055 | |||
1056 | if (strstr(modestr,"intclk")) | ||
1057 | bc->cfg.intclk = 1; | ||
1058 | if (strstr(modestr,"extclk")) | ||
1059 | bc->cfg.intclk = 0; | ||
1060 | if (strstr(modestr,"intmodem")) | ||
1061 | bc->cfg.extmodem = 0; | ||
1062 | if (strstr(modestr,"extmodem")) | ||
1063 | bc->cfg.extmodem = 1; | ||
1064 | if (strstr(modestr,"noloopback")) | ||
1065 | bc->cfg.loopback = 0; | ||
1066 | if (strstr(modestr,"loopback")) | ||
1067 | bc->cfg.loopback = 1; | ||
1068 | if ((cp = strstr(modestr,"fclk="))) { | ||
1069 | bc->cfg.fclk = simple_strtoul(cp+5, NULL, 0); | ||
1070 | if (bc->cfg.fclk < 1000000) | ||
1071 | bc->cfg.fclk = 1000000; | ||
1072 | if (bc->cfg.fclk > 25000000) | ||
1073 | bc->cfg.fclk = 25000000; | ||
1074 | } | ||
1075 | if ((cp = strstr(modestr,"bps="))) { | ||
1076 | bc->cfg.bps = simple_strtoul(cp+4, NULL, 0); | ||
1077 | if (bc->cfg.bps < 1000) | ||
1078 | bc->cfg.bps = 1000; | ||
1079 | if (bc->cfg.bps > 1500000) | ||
1080 | bc->cfg.bps = 1500000; | ||
1081 | } | ||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | /* --------------------------------------------------------------------- */ | ||
1086 | |||
1087 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1088 | { | ||
1089 | struct baycom_state *bc = netdev_priv(dev); | ||
1090 | struct hdlcdrv_ioctl hi; | ||
1091 | |||
1092 | if (cmd != SIOCDEVPRIVATE) | ||
1093 | return -ENOIOCTLCMD; | ||
1094 | |||
1095 | if (copy_from_user(&hi, ifr->ifr_data, sizeof(hi))) | ||
1096 | return -EFAULT; | ||
1097 | switch (hi.cmd) { | ||
1098 | default: | ||
1099 | return -ENOIOCTLCMD; | ||
1100 | |||
1101 | case HDLCDRVCTL_GETCHANNELPAR: | ||
1102 | hi.data.cp.tx_delay = bc->ch_params.tx_delay; | ||
1103 | hi.data.cp.tx_tail = bc->ch_params.tx_tail; | ||
1104 | hi.data.cp.slottime = bc->ch_params.slottime; | ||
1105 | hi.data.cp.ppersist = bc->ch_params.ppersist; | ||
1106 | hi.data.cp.fulldup = bc->ch_params.fulldup; | ||
1107 | break; | ||
1108 | |||
1109 | case HDLCDRVCTL_SETCHANNELPAR: | ||
1110 | if (!capable(CAP_NET_ADMIN)) | ||
1111 | return -EACCES; | ||
1112 | bc->ch_params.tx_delay = hi.data.cp.tx_delay; | ||
1113 | bc->ch_params.tx_tail = hi.data.cp.tx_tail; | ||
1114 | bc->ch_params.slottime = hi.data.cp.slottime; | ||
1115 | bc->ch_params.ppersist = hi.data.cp.ppersist; | ||
1116 | bc->ch_params.fulldup = hi.data.cp.fulldup; | ||
1117 | bc->hdlctx.slotcnt = 1; | ||
1118 | return 0; | ||
1119 | |||
1120 | case HDLCDRVCTL_GETMODEMPAR: | ||
1121 | hi.data.mp.iobase = dev->base_addr; | ||
1122 | hi.data.mp.irq = dev->irq; | ||
1123 | hi.data.mp.dma = dev->dma; | ||
1124 | hi.data.mp.dma2 = 0; | ||
1125 | hi.data.mp.seriobase = 0; | ||
1126 | hi.data.mp.pariobase = 0; | ||
1127 | hi.data.mp.midiiobase = 0; | ||
1128 | break; | ||
1129 | |||
1130 | case HDLCDRVCTL_SETMODEMPAR: | ||
1131 | if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev)) | ||
1132 | return -EACCES; | ||
1133 | dev->base_addr = hi.data.mp.iobase; | ||
1134 | dev->irq = /*hi.data.mp.irq*/0; | ||
1135 | dev->dma = /*hi.data.mp.dma*/0; | ||
1136 | return 0; | ||
1137 | |||
1138 | case HDLCDRVCTL_GETSTAT: | ||
1139 | hi.data.cs.ptt = !!(bc->stat & EPP_PTTBIT); | ||
1140 | hi.data.cs.dcd = !(bc->stat & EPP_DCDBIT); | ||
1141 | hi.data.cs.ptt_keyed = bc->ptt_keyed; | ||
1142 | hi.data.cs.tx_packets = bc->stats.tx_packets; | ||
1143 | hi.data.cs.tx_errors = bc->stats.tx_errors; | ||
1144 | hi.data.cs.rx_packets = bc->stats.rx_packets; | ||
1145 | hi.data.cs.rx_errors = bc->stats.rx_errors; | ||
1146 | break; | ||
1147 | |||
1148 | case HDLCDRVCTL_OLDGETSTAT: | ||
1149 | hi.data.ocs.ptt = !!(bc->stat & EPP_PTTBIT); | ||
1150 | hi.data.ocs.dcd = !(bc->stat & EPP_DCDBIT); | ||
1151 | hi.data.ocs.ptt_keyed = bc->ptt_keyed; | ||
1152 | break; | ||
1153 | |||
1154 | case HDLCDRVCTL_CALIBRATE: | ||
1155 | if (!capable(CAP_SYS_RAWIO)) | ||
1156 | return -EACCES; | ||
1157 | bc->hdlctx.calibrate = hi.data.calibrate * bc->bitrate / 8; | ||
1158 | return 0; | ||
1159 | |||
1160 | case HDLCDRVCTL_DRIVERNAME: | ||
1161 | strncpy(hi.data.drivername, "baycom_epp", sizeof(hi.data.drivername)); | ||
1162 | break; | ||
1163 | |||
1164 | case HDLCDRVCTL_GETMODE: | ||
1165 | sprintf(hi.data.modename, "%sclk,%smodem,fclk=%d,bps=%d%s", | ||
1166 | bc->cfg.intclk ? "int" : "ext", | ||
1167 | bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps, | ||
1168 | bc->cfg.loopback ? ",loopback" : ""); | ||
1169 | break; | ||
1170 | |||
1171 | case HDLCDRVCTL_SETMODE: | ||
1172 | if (!capable(CAP_NET_ADMIN) || netif_running(dev)) | ||
1173 | return -EACCES; | ||
1174 | hi.data.modename[sizeof(hi.data.modename)-1] = '\0'; | ||
1175 | return baycom_setmode(bc, hi.data.modename); | ||
1176 | |||
1177 | case HDLCDRVCTL_MODELIST: | ||
1178 | strncpy(hi.data.modename, "intclk,extclk,intmodem,extmodem,divider=x", | ||
1179 | sizeof(hi.data.modename)); | ||
1180 | break; | ||
1181 | |||
1182 | case HDLCDRVCTL_MODEMPARMASK: | ||
1183 | return HDLCDRV_PARMASK_IOBASE; | ||
1184 | |||
1185 | } | ||
1186 | if (copy_to_user(ifr->ifr_data, &hi, sizeof(hi))) | ||
1187 | return -EFAULT; | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | /* --------------------------------------------------------------------- */ | ||
1192 | |||
1193 | /* | ||
1194 | * Check for a network adaptor of this type, and return '0' if one exists. | ||
1195 | * If dev->base_addr == 0, probe all likely locations. | ||
1196 | * If dev->base_addr == 1, always return failure. | ||
1197 | * If dev->base_addr == 2, allocate space for the device and return success | ||
1198 | * (detachable devices only). | ||
1199 | */ | ||
1200 | static void baycom_probe(struct net_device *dev) | ||
1201 | { | ||
1202 | static char ax25_bcast[AX25_ADDR_LEN] = { | ||
1203 | 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1 | ||
1204 | }; | ||
1205 | static char ax25_nocall[AX25_ADDR_LEN] = { | ||
1206 | 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1 | ||
1207 | }; | ||
1208 | const struct hdlcdrv_channel_params dflt_ch_params = { | ||
1209 | 20, 2, 10, 40, 0 | ||
1210 | }; | ||
1211 | struct baycom_state *bc; | ||
1212 | |||
1213 | /* | ||
1214 | * not a real probe! only initialize data structures | ||
1215 | */ | ||
1216 | bc = netdev_priv(dev); | ||
1217 | /* | ||
1218 | * initialize the baycom_state struct | ||
1219 | */ | ||
1220 | bc->ch_params = dflt_ch_params; | ||
1221 | bc->ptt_keyed = 0; | ||
1222 | |||
1223 | /* | ||
1224 | * initialize the device struct | ||
1225 | */ | ||
1226 | dev->open = epp_open; | ||
1227 | dev->stop = epp_close; | ||
1228 | dev->do_ioctl = baycom_ioctl; | ||
1229 | dev->hard_start_xmit = baycom_send_packet; | ||
1230 | dev->get_stats = baycom_get_stats; | ||
1231 | |||
1232 | /* Fill in the fields of the device structure */ | ||
1233 | bc->skb = NULL; | ||
1234 | |||
1235 | #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) | ||
1236 | dev->hard_header = ax25_encapsulate; | ||
1237 | dev->rebuild_header = ax25_rebuild_header; | ||
1238 | #else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ | ||
1239 | dev->hard_header = NULL; | ||
1240 | dev->rebuild_header = NULL; | ||
1241 | #endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ | ||
1242 | dev->set_mac_address = baycom_set_mac_address; | ||
1243 | |||
1244 | dev->type = ARPHRD_AX25; /* AF_AX25 device */ | ||
1245 | dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; | ||
1246 | dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ | ||
1247 | dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ | ||
1248 | memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); | ||
1249 | memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); | ||
1250 | dev->tx_queue_len = 16; | ||
1251 | |||
1252 | /* New style flags */ | ||
1253 | dev->flags = 0; | ||
1254 | } | ||
1255 | |||
1256 | /* --------------------------------------------------------------------- */ | ||
1257 | |||
1258 | /* | ||
1259 | * command line settable parameters | ||
1260 | */ | ||
1261 | static const char *mode[NR_PORTS] = { "", }; | ||
1262 | static int iobase[NR_PORTS] = { 0x378, }; | ||
1263 | |||
1264 | module_param_array(mode, charp, NULL, 0); | ||
1265 | MODULE_PARM_DESC(mode, "baycom operating mode"); | ||
1266 | module_param_array(iobase, int, NULL, 0); | ||
1267 | MODULE_PARM_DESC(iobase, "baycom io base address"); | ||
1268 | |||
1269 | MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); | ||
1270 | MODULE_DESCRIPTION("Baycom epp amateur radio modem driver"); | ||
1271 | MODULE_LICENSE("GPL"); | ||
1272 | |||
1273 | /* --------------------------------------------------------------------- */ | ||
1274 | |||
1275 | static void __init baycom_epp_dev_setup(struct net_device *dev) | ||
1276 | { | ||
1277 | struct baycom_state *bc = netdev_priv(dev); | ||
1278 | |||
1279 | /* | ||
1280 | * initialize part of the baycom_state struct | ||
1281 | */ | ||
1282 | bc->magic = BAYCOM_MAGIC; | ||
1283 | bc->cfg.fclk = 19666600; | ||
1284 | bc->cfg.bps = 9600; | ||
1285 | /* | ||
1286 | * initialize part of the device struct | ||
1287 | */ | ||
1288 | baycom_probe(dev); | ||
1289 | } | ||
1290 | |||
1291 | static int __init init_baycomepp(void) | ||
1292 | { | ||
1293 | int i, found = 0; | ||
1294 | char set_hw = 1; | ||
1295 | |||
1296 | printk(bc_drvinfo); | ||
1297 | /* | ||
1298 | * register net devices | ||
1299 | */ | ||
1300 | for (i = 0; i < NR_PORTS; i++) { | ||
1301 | struct net_device *dev; | ||
1302 | |||
1303 | dev = alloc_netdev(sizeof(struct baycom_state), "bce%d", | ||
1304 | baycom_epp_dev_setup); | ||
1305 | |||
1306 | if (!dev) { | ||
1307 | printk(KERN_WARNING "bce%d : out of memory\n", i); | ||
1308 | return found ? 0 : -ENOMEM; | ||
1309 | } | ||
1310 | |||
1311 | sprintf(dev->name, "bce%d", i); | ||
1312 | dev->base_addr = iobase[i]; | ||
1313 | |||
1314 | if (!mode[i]) | ||
1315 | set_hw = 0; | ||
1316 | if (!set_hw) | ||
1317 | iobase[i] = 0; | ||
1318 | |||
1319 | if (register_netdev(dev)) { | ||
1320 | printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name); | ||
1321 | free_netdev(dev); | ||
1322 | break; | ||
1323 | } | ||
1324 | if (set_hw && baycom_setmode(netdev_priv(dev), mode[i])) | ||
1325 | set_hw = 0; | ||
1326 | baycom_device[i] = dev; | ||
1327 | found++; | ||
1328 | } | ||
1329 | |||
1330 | return found ? 0 : -ENXIO; | ||
1331 | } | ||
1332 | |||
1333 | static void __exit cleanup_baycomepp(void) | ||
1334 | { | ||
1335 | int i; | ||
1336 | |||
1337 | for(i = 0; i < NR_PORTS; i++) { | ||
1338 | struct net_device *dev = baycom_device[i]; | ||
1339 | |||
1340 | if (dev) { | ||
1341 | struct baycom_state *bc = netdev_priv(dev); | ||
1342 | if (bc->magic == BAYCOM_MAGIC) { | ||
1343 | unregister_netdev(dev); | ||
1344 | free_netdev(dev); | ||
1345 | } else | ||
1346 | printk(paranoia_str, "cleanup_module"); | ||
1347 | } | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | module_init(init_baycomepp); | ||
1352 | module_exit(cleanup_baycomepp); | ||
1353 | |||
1354 | /* --------------------------------------------------------------------- */ | ||
1355 | |||
1356 | #ifndef MODULE | ||
1357 | |||
1358 | /* | ||
1359 | * format: baycom_epp=io,mode | ||
1360 | * mode: fpga config options | ||
1361 | */ | ||
1362 | |||
1363 | static int __init baycom_epp_setup(char *str) | ||
1364 | { | ||
1365 | static unsigned __initdata nr_dev = 0; | ||
1366 | int ints[2]; | ||
1367 | |||
1368 | if (nr_dev >= NR_PORTS) | ||
1369 | return 0; | ||
1370 | str = get_options(str, 2, ints); | ||
1371 | if (ints[0] < 1) | ||
1372 | return 0; | ||
1373 | mode[nr_dev] = str; | ||
1374 | iobase[nr_dev] = ints[1]; | ||
1375 | nr_dev++; | ||
1376 | return 1; | ||
1377 | } | ||
1378 | |||
1379 | __setup("baycom_epp=", baycom_epp_setup); | ||
1380 | |||
1381 | #endif /* MODULE */ | ||
1382 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c new file mode 100644 index 000000000000..612ad452bee0 --- /dev/null +++ b/drivers/net/hamradio/baycom_par.c | |||
@@ -0,0 +1,576 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * baycom_par.c -- baycom par96 and picpar radio modem 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 | * | ||
27 | * Supported modems | ||
28 | * | ||
29 | * par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard. | ||
30 | * The modem does all the filtering and regenerates the receiver clock. | ||
31 | * Data is transferred from and to the PC via a shift register. | ||
32 | * The shift register is filled with 16 bits and an interrupt is | ||
33 | * signalled. The PC then empties the shift register in a burst. This | ||
34 | * modem connects to the parallel port, hence the name. The modem | ||
35 | * leaves the implementation of the HDLC protocol and the scrambler | ||
36 | * polynomial to the PC. This modem is no longer available (at least | ||
37 | * from Baycom) and has been replaced by the PICPAR modem (see below). | ||
38 | * You may however still build one from the schematics published in | ||
39 | * cq-DL :-). | ||
40 | * | ||
41 | * picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The | ||
42 | * modem is protocol compatible to par96, but uses only three low | ||
43 | * power ICs and can therefore be fed from the parallel port and | ||
44 | * does not require an additional power supply. It features | ||
45 | * built in DCD circuitry. The driver should therefore be configured | ||
46 | * for hardware DCD. | ||
47 | * | ||
48 | * | ||
49 | * Command line options (insmod command line) | ||
50 | * | ||
51 | * mode driver mode string. Valid choices are par96 and picpar. | ||
52 | * iobase base address of the port; common values are 0x378, 0x278, 0x3bc | ||
53 | * | ||
54 | * | ||
55 | * History: | ||
56 | * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface | ||
57 | * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) | ||
58 | * 0.3 26.04.1997 init code/data tagged | ||
59 | * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) | ||
60 | * 0.5 11.11.1997 split into separate files for ser12/par96 | ||
61 | * 0.6 03.08.1999 adapt to Linus' new __setup/__initcall | ||
62 | * removed some pre-2.2 kernel compatibility cruft | ||
63 | * 0.7 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts | ||
64 | * 0.8 12.02.2000 adapted to softnet driver interface | ||
65 | * removed direct parport access, uses parport driver methods | ||
66 | * 0.9 03.07.2000 fix interface name handling | ||
67 | */ | ||
68 | |||
69 | /*****************************************************************************/ | ||
70 | |||
71 | #include <linux/module.h> | ||
72 | #include <linux/kernel.h> | ||
73 | #include <linux/types.h> | ||
74 | #include <linux/fcntl.h> | ||
75 | #include <linux/interrupt.h> | ||
76 | #include <linux/ioport.h> | ||
77 | #include <linux/in.h> | ||
78 | #include <linux/string.h> | ||
79 | #include <linux/init.h> | ||
80 | #include <linux/delay.h> | ||
81 | #include <linux/errno.h> | ||
82 | #include <linux/netdevice.h> | ||
83 | #include <linux/hdlcdrv.h> | ||
84 | #include <linux/baycom.h> | ||
85 | #include <linux/parport.h> | ||
86 | #include <linux/bitops.h> | ||
87 | |||
88 | #include <asm/bug.h> | ||
89 | #include <asm/system.h> | ||
90 | #include <asm/uaccess.h> | ||
91 | |||
92 | /* --------------------------------------------------------------------- */ | ||
93 | |||
94 | #define BAYCOM_DEBUG | ||
95 | |||
96 | /* | ||
97 | * modem options; bit mask | ||
98 | */ | ||
99 | #define BAYCOM_OPTIONS_SOFTDCD 1 | ||
100 | |||
101 | /* --------------------------------------------------------------------- */ | ||
102 | |||
103 | static const char bc_drvname[] = "baycom_par"; | ||
104 | static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" | ||
105 | KERN_INFO "baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n"; | ||
106 | |||
107 | /* --------------------------------------------------------------------- */ | ||
108 | |||
109 | #define NR_PORTS 4 | ||
110 | |||
111 | static struct net_device *baycom_device[NR_PORTS]; | ||
112 | |||
113 | /* --------------------------------------------------------------------- */ | ||
114 | |||
115 | #define PAR96_BURSTBITS 16 | ||
116 | #define PAR96_BURST 4 | ||
117 | #define PAR96_PTT 2 | ||
118 | #define PAR96_TXBIT 1 | ||
119 | #define PAR96_ACK 0x40 | ||
120 | #define PAR96_RXBIT 0x20 | ||
121 | #define PAR96_DCD 0x10 | ||
122 | #define PAR97_POWER 0xf8 | ||
123 | |||
124 | /* ---------------------------------------------------------------------- */ | ||
125 | /* | ||
126 | * Information that need to be kept for each board. | ||
127 | */ | ||
128 | |||
129 | struct baycom_state { | ||
130 | struct hdlcdrv_state hdrv; | ||
131 | |||
132 | struct pardevice *pdev; | ||
133 | unsigned int options; | ||
134 | |||
135 | struct modem_state { | ||
136 | short arb_divider; | ||
137 | unsigned char flags; | ||
138 | unsigned int shreg; | ||
139 | struct modem_state_par96 { | ||
140 | int dcd_count; | ||
141 | unsigned int dcd_shreg; | ||
142 | unsigned long descram; | ||
143 | unsigned long scram; | ||
144 | } par96; | ||
145 | } modem; | ||
146 | |||
147 | #ifdef BAYCOM_DEBUG | ||
148 | struct debug_vals { | ||
149 | unsigned long last_jiffies; | ||
150 | unsigned cur_intcnt; | ||
151 | unsigned last_intcnt; | ||
152 | int cur_pllcorr; | ||
153 | int last_pllcorr; | ||
154 | } debug_vals; | ||
155 | #endif /* BAYCOM_DEBUG */ | ||
156 | }; | ||
157 | |||
158 | /* --------------------------------------------------------------------- */ | ||
159 | |||
160 | static void __inline__ baycom_int_freq(struct baycom_state *bc) | ||
161 | { | ||
162 | #ifdef BAYCOM_DEBUG | ||
163 | unsigned long cur_jiffies = jiffies; | ||
164 | /* | ||
165 | * measure the interrupt frequency | ||
166 | */ | ||
167 | bc->debug_vals.cur_intcnt++; | ||
168 | if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { | ||
169 | bc->debug_vals.last_jiffies = cur_jiffies; | ||
170 | bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; | ||
171 | bc->debug_vals.cur_intcnt = 0; | ||
172 | bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; | ||
173 | bc->debug_vals.cur_pllcorr = 0; | ||
174 | } | ||
175 | #endif /* BAYCOM_DEBUG */ | ||
176 | } | ||
177 | |||
178 | /* --------------------------------------------------------------------- */ | ||
179 | /* | ||
180 | * ===================== PAR96 specific routines ========================= | ||
181 | */ | ||
182 | |||
183 | #define PAR96_DESCRAM_TAP1 0x20000 | ||
184 | #define PAR96_DESCRAM_TAP2 0x01000 | ||
185 | #define PAR96_DESCRAM_TAP3 0x00001 | ||
186 | |||
187 | #define PAR96_DESCRAM_TAPSH1 17 | ||
188 | #define PAR96_DESCRAM_TAPSH2 12 | ||
189 | #define PAR96_DESCRAM_TAPSH3 0 | ||
190 | |||
191 | #define PAR96_SCRAM_TAP1 0x20000 /* X^17 */ | ||
192 | #define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */ | ||
193 | |||
194 | /* --------------------------------------------------------------------- */ | ||
195 | |||
196 | static __inline__ void par96_tx(struct net_device *dev, struct baycom_state *bc) | ||
197 | { | ||
198 | int i; | ||
199 | unsigned int data = hdlcdrv_getbits(&bc->hdrv); | ||
200 | struct parport *pp = bc->pdev->port; | ||
201 | |||
202 | for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) { | ||
203 | unsigned char val = PAR97_POWER; | ||
204 | bc->modem.par96.scram = ((bc->modem.par96.scram << 1) | | ||
205 | (bc->modem.par96.scram & 1)); | ||
206 | if (!(data & 1)) | ||
207 | bc->modem.par96.scram ^= 1; | ||
208 | if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1)) | ||
209 | bc->modem.par96.scram ^= | ||
210 | (PAR96_SCRAM_TAPN << 1); | ||
211 | if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2)) | ||
212 | val |= PAR96_TXBIT; | ||
213 | pp->ops->write_data(pp, val); | ||
214 | pp->ops->write_data(pp, val | PAR96_BURST); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | /* --------------------------------------------------------------------- */ | ||
219 | |||
220 | static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc) | ||
221 | { | ||
222 | int i; | ||
223 | unsigned int data, mask, mask2, descx; | ||
224 | struct parport *pp = bc->pdev->port; | ||
225 | |||
226 | /* | ||
227 | * do receiver; differential decode and descramble on the fly | ||
228 | */ | ||
229 | for(data = i = 0; i < PAR96_BURSTBITS; i++) { | ||
230 | bc->modem.par96.descram = (bc->modem.par96.descram << 1); | ||
231 | if (pp->ops->read_status(pp) & PAR96_RXBIT) | ||
232 | bc->modem.par96.descram |= 1; | ||
233 | descx = bc->modem.par96.descram ^ | ||
234 | (bc->modem.par96.descram >> 1); | ||
235 | /* now the diff decoded data is inverted in descram */ | ||
236 | pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT); | ||
237 | descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ | ||
238 | (descx >> PAR96_DESCRAM_TAPSH2)); | ||
239 | data >>= 1; | ||
240 | if (!(descx & 1)) | ||
241 | data |= 0x8000; | ||
242 | pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT | PAR96_BURST); | ||
243 | } | ||
244 | hdlcdrv_putbits(&bc->hdrv, data); | ||
245 | /* | ||
246 | * do DCD algorithm | ||
247 | */ | ||
248 | if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { | ||
249 | bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16) | ||
250 | | (data << 16); | ||
251 | /* search for flags and set the dcd counter appropriately */ | ||
252 | for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; | ||
253 | i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) | ||
254 | if ((bc->modem.par96.dcd_shreg & mask) == mask2) | ||
255 | bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4; | ||
256 | /* check for abort/noise sequences */ | ||
257 | for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; | ||
258 | i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) | ||
259 | if (((bc->modem.par96.dcd_shreg & mask) == mask2) && | ||
260 | (bc->modem.par96.dcd_count >= 0)) | ||
261 | bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10; | ||
262 | /* decrement and set the dcd variable */ | ||
263 | if (bc->modem.par96.dcd_count >= 0) | ||
264 | bc->modem.par96.dcd_count -= 2; | ||
265 | hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0); | ||
266 | } else { | ||
267 | hdlcdrv_setdcd(&bc->hdrv, !!(pp->ops->read_status(pp) & PAR96_DCD)); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* --------------------------------------------------------------------- */ | ||
272 | |||
273 | static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
274 | { | ||
275 | struct net_device *dev = (struct net_device *)dev_id; | ||
276 | struct baycom_state *bc = netdev_priv(dev); | ||
277 | |||
278 | baycom_int_freq(bc); | ||
279 | /* | ||
280 | * check if transmitter active | ||
281 | */ | ||
282 | if (hdlcdrv_ptt(&bc->hdrv)) | ||
283 | par96_tx(dev, bc); | ||
284 | else { | ||
285 | par96_rx(dev, bc); | ||
286 | if (--bc->modem.arb_divider <= 0) { | ||
287 | bc->modem.arb_divider = 6; | ||
288 | local_irq_enable(); | ||
289 | hdlcdrv_arbitrate(dev, &bc->hdrv); | ||
290 | } | ||
291 | } | ||
292 | local_irq_enable(); | ||
293 | hdlcdrv_transmitter(dev, &bc->hdrv); | ||
294 | hdlcdrv_receiver(dev, &bc->hdrv); | ||
295 | local_irq_disable(); | ||
296 | } | ||
297 | |||
298 | /* --------------------------------------------------------------------- */ | ||
299 | |||
300 | static void par96_wakeup(void *handle) | ||
301 | { | ||
302 | struct net_device *dev = (struct net_device *)handle; | ||
303 | struct baycom_state *bc = netdev_priv(dev); | ||
304 | |||
305 | printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name); | ||
306 | if (!parport_claim(bc->pdev)) | ||
307 | printk(KERN_DEBUG "baycom_par: %s: I'm broken.\n", dev->name); | ||
308 | } | ||
309 | |||
310 | /* --------------------------------------------------------------------- */ | ||
311 | |||
312 | static int par96_open(struct net_device *dev) | ||
313 | { | ||
314 | struct baycom_state *bc = netdev_priv(dev); | ||
315 | struct parport *pp; | ||
316 | |||
317 | if (!dev || !bc) | ||
318 | return -ENXIO; | ||
319 | pp = parport_find_base(dev->base_addr); | ||
320 | if (!pp) { | ||
321 | printk(KERN_ERR "baycom_par: parport at 0x%lx unknown\n", dev->base_addr); | ||
322 | return -ENXIO; | ||
323 | } | ||
324 | if (pp->irq < 0) { | ||
325 | printk(KERN_ERR "baycom_par: parport at 0x%lx has no irq\n", pp->base); | ||
326 | parport_put_port(pp); | ||
327 | return -ENXIO; | ||
328 | } | ||
329 | if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) { | ||
330 | printk(KERN_ERR "baycom_par: parport at 0x%lx cannot be used\n", pp->base); | ||
331 | parport_put_port(pp); | ||
332 | return -ENXIO; | ||
333 | } | ||
334 | memset(&bc->modem, 0, sizeof(bc->modem)); | ||
335 | bc->hdrv.par.bitrate = 9600; | ||
336 | bc->pdev = parport_register_device(pp, dev->name, NULL, par96_wakeup, | ||
337 | par96_interrupt, PARPORT_DEV_EXCL, dev); | ||
338 | parport_put_port(pp); | ||
339 | if (!bc->pdev) { | ||
340 | printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", dev->base_addr); | ||
341 | return -ENXIO; | ||
342 | } | ||
343 | if (parport_claim(bc->pdev)) { | ||
344 | printk(KERN_ERR "baycom_par: parport at 0x%lx busy\n", pp->base); | ||
345 | parport_unregister_device(bc->pdev); | ||
346 | return -EBUSY; | ||
347 | } | ||
348 | pp = bc->pdev->port; | ||
349 | dev->irq = pp->irq; | ||
350 | pp->ops->data_forward(pp); | ||
351 | bc->hdrv.par.bitrate = 9600; | ||
352 | pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER); /* switch off PTT */ | ||
353 | pp->ops->enable_irq(pp); | ||
354 | printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n", | ||
355 | bc_drvname, dev->base_addr, dev->irq, bc->options); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /* --------------------------------------------------------------------- */ | ||
360 | |||
361 | static int par96_close(struct net_device *dev) | ||
362 | { | ||
363 | struct baycom_state *bc = netdev_priv(dev); | ||
364 | struct parport *pp; | ||
365 | |||
366 | if (!dev || !bc) | ||
367 | return -EINVAL; | ||
368 | pp = bc->pdev->port; | ||
369 | /* disable interrupt */ | ||
370 | pp->ops->disable_irq(pp); | ||
371 | /* switch off PTT */ | ||
372 | pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER); | ||
373 | parport_release(bc->pdev); | ||
374 | parport_unregister_device(bc->pdev); | ||
375 | printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n", | ||
376 | bc_drvname, dev->base_addr, dev->irq); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /* --------------------------------------------------------------------- */ | ||
381 | /* | ||
382 | * ===================== hdlcdrv driver interface ========================= | ||
383 | */ | ||
384 | |||
385 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, | ||
386 | struct hdlcdrv_ioctl *hi, int cmd); | ||
387 | |||
388 | /* --------------------------------------------------------------------- */ | ||
389 | |||
390 | static struct hdlcdrv_ops par96_ops = { | ||
391 | .drvname = bc_drvname, | ||
392 | .drvinfo = bc_drvinfo, | ||
393 | .open = par96_open, | ||
394 | .close = par96_close, | ||
395 | .ioctl = baycom_ioctl | ||
396 | }; | ||
397 | |||
398 | /* --------------------------------------------------------------------- */ | ||
399 | |||
400 | static int baycom_setmode(struct baycom_state *bc, const char *modestr) | ||
401 | { | ||
402 | if (!strncmp(modestr, "picpar", 6)) | ||
403 | bc->options = 0; | ||
404 | else if (!strncmp(modestr, "par96", 5)) | ||
405 | bc->options = BAYCOM_OPTIONS_SOFTDCD; | ||
406 | else | ||
407 | bc->options = !!strchr(modestr, '*'); | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /* --------------------------------------------------------------------- */ | ||
412 | |||
413 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, | ||
414 | struct hdlcdrv_ioctl *hi, int cmd) | ||
415 | { | ||
416 | struct baycom_state *bc; | ||
417 | struct baycom_ioctl bi; | ||
418 | |||
419 | if (!dev) | ||
420 | return -EINVAL; | ||
421 | |||
422 | bc = netdev_priv(dev); | ||
423 | BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); | ||
424 | |||
425 | if (cmd != SIOCDEVPRIVATE) | ||
426 | return -ENOIOCTLCMD; | ||
427 | switch (hi->cmd) { | ||
428 | default: | ||
429 | break; | ||
430 | |||
431 | case HDLCDRVCTL_GETMODE: | ||
432 | strcpy(hi->data.modename, bc->options ? "par96" : "picpar"); | ||
433 | if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) | ||
434 | return -EFAULT; | ||
435 | return 0; | ||
436 | |||
437 | case HDLCDRVCTL_SETMODE: | ||
438 | if (netif_running(dev) || !capable(CAP_NET_ADMIN)) | ||
439 | return -EACCES; | ||
440 | hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; | ||
441 | return baycom_setmode(bc, hi->data.modename); | ||
442 | |||
443 | case HDLCDRVCTL_MODELIST: | ||
444 | strcpy(hi->data.modename, "par96,picpar"); | ||
445 | if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) | ||
446 | return -EFAULT; | ||
447 | return 0; | ||
448 | |||
449 | case HDLCDRVCTL_MODEMPARMASK: | ||
450 | return HDLCDRV_PARMASK_IOBASE; | ||
451 | |||
452 | } | ||
453 | |||
454 | if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) | ||
455 | return -EFAULT; | ||
456 | switch (bi.cmd) { | ||
457 | default: | ||
458 | return -ENOIOCTLCMD; | ||
459 | |||
460 | #ifdef BAYCOM_DEBUG | ||
461 | case BAYCOMCTL_GETDEBUG: | ||
462 | bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; | ||
463 | bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; | ||
464 | bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; | ||
465 | break; | ||
466 | #endif /* BAYCOM_DEBUG */ | ||
467 | |||
468 | } | ||
469 | if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) | ||
470 | return -EFAULT; | ||
471 | return 0; | ||
472 | |||
473 | } | ||
474 | |||
475 | /* --------------------------------------------------------------------- */ | ||
476 | |||
477 | /* | ||
478 | * command line settable parameters | ||
479 | */ | ||
480 | static const char *mode[NR_PORTS] = { "picpar", }; | ||
481 | static int iobase[NR_PORTS] = { 0x378, }; | ||
482 | |||
483 | module_param_array(mode, charp, NULL, 0); | ||
484 | MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar"); | ||
485 | module_param_array(iobase, int, NULL, 0); | ||
486 | MODULE_PARM_DESC(iobase, "baycom io base address"); | ||
487 | |||
488 | MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); | ||
489 | MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver"); | ||
490 | MODULE_LICENSE("GPL"); | ||
491 | |||
492 | /* --------------------------------------------------------------------- */ | ||
493 | |||
494 | static int __init init_baycompar(void) | ||
495 | { | ||
496 | int i, found = 0; | ||
497 | char set_hw = 1; | ||
498 | |||
499 | printk(bc_drvinfo); | ||
500 | /* | ||
501 | * register net devices | ||
502 | */ | ||
503 | for (i = 0; i < NR_PORTS; i++) { | ||
504 | struct net_device *dev; | ||
505 | struct baycom_state *bc; | ||
506 | char ifname[IFNAMSIZ]; | ||
507 | |||
508 | sprintf(ifname, "bcp%d", i); | ||
509 | |||
510 | if (!mode[i]) | ||
511 | set_hw = 0; | ||
512 | if (!set_hw) | ||
513 | iobase[i] = 0; | ||
514 | |||
515 | dev = hdlcdrv_register(&par96_ops, | ||
516 | sizeof(struct baycom_state), | ||
517 | ifname, iobase[i], 0, 0); | ||
518 | if (IS_ERR(dev)) | ||
519 | break; | ||
520 | |||
521 | bc = netdev_priv(dev); | ||
522 | if (set_hw && baycom_setmode(bc, mode[i])) | ||
523 | set_hw = 0; | ||
524 | found++; | ||
525 | baycom_device[i] = dev; | ||
526 | } | ||
527 | |||
528 | if (!found) | ||
529 | return -ENXIO; | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static void __exit cleanup_baycompar(void) | ||
534 | { | ||
535 | int i; | ||
536 | |||
537 | for(i = 0; i < NR_PORTS; i++) { | ||
538 | struct net_device *dev = baycom_device[i]; | ||
539 | |||
540 | if (dev) | ||
541 | hdlcdrv_unregister(dev); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | module_init(init_baycompar); | ||
546 | module_exit(cleanup_baycompar); | ||
547 | |||
548 | /* --------------------------------------------------------------------- */ | ||
549 | |||
550 | #ifndef MODULE | ||
551 | |||
552 | /* | ||
553 | * format: baycom_par=io,mode | ||
554 | * mode: par96,picpar | ||
555 | */ | ||
556 | |||
557 | static int __init baycom_par_setup(char *str) | ||
558 | { | ||
559 | static unsigned nr_dev; | ||
560 | int ints[2]; | ||
561 | |||
562 | if (nr_dev >= NR_PORTS) | ||
563 | return 0; | ||
564 | str = get_options(str, 2, ints); | ||
565 | if (ints[0] < 1) | ||
566 | return 0; | ||
567 | mode[nr_dev] = str; | ||
568 | iobase[nr_dev] = ints[1]; | ||
569 | nr_dev++; | ||
570 | return 1; | ||
571 | } | ||
572 | |||
573 | __setup("baycom_par=", baycom_par_setup); | ||
574 | |||
575 | #endif /* MODULE */ | ||
576 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c new file mode 100644 index 000000000000..25f270b05378 --- /dev/null +++ b/drivers/net/hamradio/baycom_ser_fdx.c | |||
@@ -0,0 +1,704 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem 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 | * | ||
27 | * Supported modems | ||
28 | * | ||
29 | * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only | ||
30 | * of a modulator/demodulator chip, usually a TI TCM3105. The computer | ||
31 | * is responsible for regenerating the receiver bit clock, as well as | ||
32 | * for handling the HDLC protocol. The modem connects to a serial port, | ||
33 | * hence the name. Since the serial port is not used as an async serial | ||
34 | * port, the kernel driver for serial ports cannot be used, and this | ||
35 | * driver only supports standard serial hardware (8250, 16450, 16550A) | ||
36 | * | ||
37 | * This modem usually draws its supply current out of the otherwise unused | ||
38 | * TXD pin of the serial port. Thus a contignuous stream of 0x00-bytes | ||
39 | * is transmitted to achieve a positive supply voltage. | ||
40 | * | ||
41 | * hsk: This is a 4800 baud FSK modem, designed for TNC use. It works fine | ||
42 | * in 'baycom-mode' :-) In contrast to the TCM3105 modem, power is | ||
43 | * externally supplied. So there's no need to provide the 0x00-byte-stream | ||
44 | * when receiving or idle, which drastically reduces interrupt load. | ||
45 | * | ||
46 | * Command line options (insmod command line) | ||
47 | * | ||
48 | * mode ser# hardware DCD | ||
49 | * ser#* software DCD | ||
50 | * ser#+ hardware DCD, inverted signal at DCD pin | ||
51 | * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' | ||
52 | * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 | ||
53 | * baud baud rate (between 300 and 4800) | ||
54 | * irq interrupt line of the port; common values are 4,3 | ||
55 | * | ||
56 | * | ||
57 | * History: | ||
58 | * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface | ||
59 | * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) | ||
60 | * 0.3 26.04.1997 init code/data tagged | ||
61 | * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) | ||
62 | * 0.5 11.11.1997 ser12/par96 split into separate files | ||
63 | * 0.6 24.01.1998 Thorsten Kranzkowski, dl8bcu and Thomas Sailer: | ||
64 | * reduced interrupt load in transmit case | ||
65 | * reworked receiver | ||
66 | * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall | ||
67 | * 0.8 10.08.1999 use module_init/module_exit | ||
68 | * 0.9 12.02.2000 adapted to softnet driver interface | ||
69 | * 0.10 03.07.2000 fix interface name handling | ||
70 | */ | ||
71 | |||
72 | /*****************************************************************************/ | ||
73 | |||
74 | #include <linux/module.h> | ||
75 | #include <linux/ioport.h> | ||
76 | #include <linux/string.h> | ||
77 | #include <linux/init.h> | ||
78 | #include <asm/uaccess.h> | ||
79 | #include <asm/io.h> | ||
80 | #include <linux/hdlcdrv.h> | ||
81 | #include <linux/baycom.h> | ||
82 | |||
83 | /* --------------------------------------------------------------------- */ | ||
84 | |||
85 | #define BAYCOM_DEBUG | ||
86 | |||
87 | /* --------------------------------------------------------------------- */ | ||
88 | |||
89 | static const char bc_drvname[] = "baycom_ser_fdx"; | ||
90 | static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" | ||
91 | KERN_INFO "baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n"; | ||
92 | |||
93 | /* --------------------------------------------------------------------- */ | ||
94 | |||
95 | #define NR_PORTS 4 | ||
96 | |||
97 | static struct net_device *baycom_device[NR_PORTS]; | ||
98 | |||
99 | /* --------------------------------------------------------------------- */ | ||
100 | |||
101 | #define RBR(iobase) (iobase+0) | ||
102 | #define THR(iobase) (iobase+0) | ||
103 | #define IER(iobase) (iobase+1) | ||
104 | #define IIR(iobase) (iobase+2) | ||
105 | #define FCR(iobase) (iobase+2) | ||
106 | #define LCR(iobase) (iobase+3) | ||
107 | #define MCR(iobase) (iobase+4) | ||
108 | #define LSR(iobase) (iobase+5) | ||
109 | #define MSR(iobase) (iobase+6) | ||
110 | #define SCR(iobase) (iobase+7) | ||
111 | #define DLL(iobase) (iobase+0) | ||
112 | #define DLM(iobase) (iobase+1) | ||
113 | |||
114 | #define SER12_EXTENT 8 | ||
115 | |||
116 | /* ---------------------------------------------------------------------- */ | ||
117 | /* | ||
118 | * Information that need to be kept for each board. | ||
119 | */ | ||
120 | |||
121 | struct baycom_state { | ||
122 | struct hdlcdrv_state hdrv; | ||
123 | |||
124 | unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout; | ||
125 | int opt_dcd; | ||
126 | |||
127 | struct modem_state { | ||
128 | unsigned char flags; | ||
129 | unsigned char ptt; | ||
130 | unsigned int shreg; | ||
131 | struct modem_state_ser12 { | ||
132 | unsigned char tx_bit; | ||
133 | unsigned char last_rxbit; | ||
134 | int dcd_sum0, dcd_sum1, dcd_sum2; | ||
135 | int dcd_time; | ||
136 | unsigned int pll_time; | ||
137 | unsigned int txshreg; | ||
138 | } ser12; | ||
139 | } modem; | ||
140 | |||
141 | #ifdef BAYCOM_DEBUG | ||
142 | struct debug_vals { | ||
143 | unsigned long last_jiffies; | ||
144 | unsigned cur_intcnt; | ||
145 | unsigned last_intcnt; | ||
146 | int cur_pllcorr; | ||
147 | int last_pllcorr; | ||
148 | } debug_vals; | ||
149 | #endif /* BAYCOM_DEBUG */ | ||
150 | }; | ||
151 | |||
152 | /* --------------------------------------------------------------------- */ | ||
153 | |||
154 | static inline void baycom_int_freq(struct baycom_state *bc) | ||
155 | { | ||
156 | #ifdef BAYCOM_DEBUG | ||
157 | unsigned long cur_jiffies = jiffies; | ||
158 | /* | ||
159 | * measure the interrupt frequency | ||
160 | */ | ||
161 | bc->debug_vals.cur_intcnt++; | ||
162 | if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { | ||
163 | bc->debug_vals.last_jiffies = cur_jiffies; | ||
164 | bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; | ||
165 | bc->debug_vals.cur_intcnt = 0; | ||
166 | bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; | ||
167 | bc->debug_vals.cur_pllcorr = 0; | ||
168 | } | ||
169 | #endif /* BAYCOM_DEBUG */ | ||
170 | } | ||
171 | |||
172 | /* --------------------------------------------------------------------- */ | ||
173 | /* | ||
174 | * ===================== SER12 specific routines ========================= | ||
175 | */ | ||
176 | |||
177 | /* --------------------------------------------------------------------- */ | ||
178 | |||
179 | static inline void ser12_set_divisor(struct net_device *dev, | ||
180 | unsigned int divisor) | ||
181 | { | ||
182 | outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ | ||
183 | outb(divisor, DLL(dev->base_addr)); | ||
184 | outb(divisor >> 8, DLM(dev->base_addr)); | ||
185 | outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ | ||
186 | /* | ||
187 | * make sure the next interrupt is generated; | ||
188 | * 0 must be used to power the modem; the modem draws its | ||
189 | * power from the TxD line | ||
190 | */ | ||
191 | outb(0x00, THR(dev->base_addr)); | ||
192 | /* | ||
193 | * it is important not to set the divider while transmitting; | ||
194 | * this reportedly makes some UARTs generating interrupts | ||
195 | * in the hundredthousands per second region | ||
196 | * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno) | ||
197 | */ | ||
198 | } | ||
199 | |||
200 | /* --------------------------------------------------------------------- */ | ||
201 | |||
202 | #if 0 | ||
203 | static inline unsigned int hweight16(unsigned int w) | ||
204 | __attribute__ ((unused)); | ||
205 | static inline unsigned int hweight8(unsigned int w) | ||
206 | __attribute__ ((unused)); | ||
207 | |||
208 | static inline unsigned int hweight16(unsigned int w) | ||
209 | { | ||
210 | unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555); | ||
211 | res = (res & 0x3333) + ((res >> 2) & 0x3333); | ||
212 | res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); | ||
213 | return (res & 0x00FF) + ((res >> 8) & 0x00FF); | ||
214 | } | ||
215 | |||
216 | static inline unsigned int hweight8(unsigned int w) | ||
217 | { | ||
218 | unsigned short res = (w & 0x55) + ((w >> 1) & 0x55); | ||
219 | res = (res & 0x33) + ((res >> 2) & 0x33); | ||
220 | return (res & 0x0F) + ((res >> 4) & 0x0F); | ||
221 | } | ||
222 | #endif | ||
223 | |||
224 | /* --------------------------------------------------------------------- */ | ||
225 | |||
226 | static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, struct timeval *tv, unsigned char curs) | ||
227 | { | ||
228 | int timediff; | ||
229 | int bdus8 = bc->baud_us >> 3; | ||
230 | int bdus4 = bc->baud_us >> 2; | ||
231 | int bdus2 = bc->baud_us >> 1; | ||
232 | |||
233 | timediff = 1000000 + tv->tv_usec - bc->modem.ser12.pll_time; | ||
234 | while (timediff >= 500000) | ||
235 | timediff -= 1000000; | ||
236 | while (timediff >= bdus2) { | ||
237 | timediff -= bc->baud_us; | ||
238 | bc->modem.ser12.pll_time += bc->baud_us; | ||
239 | bc->modem.ser12.dcd_time--; | ||
240 | /* first check if there is room to add a bit */ | ||
241 | if (bc->modem.shreg & 1) { | ||
242 | hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff); | ||
243 | bc->modem.shreg = 0x10000; | ||
244 | } | ||
245 | /* add a one bit */ | ||
246 | bc->modem.shreg >>= 1; | ||
247 | } | ||
248 | if (bc->modem.ser12.dcd_time <= 0) { | ||
249 | if (!bc->opt_dcd) | ||
250 | hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + | ||
251 | bc->modem.ser12.dcd_sum1 + | ||
252 | bc->modem.ser12.dcd_sum2) < 0); | ||
253 | bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; | ||
254 | bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; | ||
255 | bc->modem.ser12.dcd_sum0 = 2; /* slight bias */ | ||
256 | bc->modem.ser12.dcd_time += 120; | ||
257 | } | ||
258 | if (bc->modem.ser12.last_rxbit != curs) { | ||
259 | bc->modem.ser12.last_rxbit = curs; | ||
260 | bc->modem.shreg |= 0x10000; | ||
261 | /* adjust the PLL */ | ||
262 | if (timediff > 0) | ||
263 | bc->modem.ser12.pll_time += bdus8; | ||
264 | else | ||
265 | bc->modem.ser12.pll_time += 1000000 - bdus8; | ||
266 | /* update DCD */ | ||
267 | if (abs(timediff) > bdus4) | ||
268 | bc->modem.ser12.dcd_sum0 += 4; | ||
269 | else | ||
270 | bc->modem.ser12.dcd_sum0--; | ||
271 | #ifdef BAYCOM_DEBUG | ||
272 | bc->debug_vals.cur_pllcorr = timediff; | ||
273 | #endif /* BAYCOM_DEBUG */ | ||
274 | } | ||
275 | while (bc->modem.ser12.pll_time >= 1000000) | ||
276 | bc->modem.ser12.pll_time -= 1000000; | ||
277 | } | ||
278 | |||
279 | /* --------------------------------------------------------------------- */ | ||
280 | |||
281 | static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
282 | { | ||
283 | struct net_device *dev = (struct net_device *)dev_id; | ||
284 | struct baycom_state *bc = netdev_priv(dev); | ||
285 | struct timeval tv; | ||
286 | unsigned char iir, msr; | ||
287 | unsigned int txcount = 0; | ||
288 | |||
289 | if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC) | ||
290 | return IRQ_NONE; | ||
291 | /* fast way out for shared irq */ | ||
292 | if ((iir = inb(IIR(dev->base_addr))) & 1) | ||
293 | return IRQ_NONE; | ||
294 | /* get current time */ | ||
295 | do_gettimeofday(&tv); | ||
296 | msr = inb(MSR(dev->base_addr)); | ||
297 | /* delta DCD */ | ||
298 | if ((msr & 8) && bc->opt_dcd) | ||
299 | hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); | ||
300 | do { | ||
301 | switch (iir & 6) { | ||
302 | case 6: | ||
303 | inb(LSR(dev->base_addr)); | ||
304 | break; | ||
305 | |||
306 | case 4: | ||
307 | inb(RBR(dev->base_addr)); | ||
308 | break; | ||
309 | |||
310 | case 2: | ||
311 | /* | ||
312 | * make sure the next interrupt is generated; | ||
313 | * 0 must be used to power the modem; the modem draws its | ||
314 | * power from the TxD line | ||
315 | */ | ||
316 | outb(0x00, THR(dev->base_addr)); | ||
317 | baycom_int_freq(bc); | ||
318 | txcount++; | ||
319 | /* | ||
320 | * first output the last bit (!) then call HDLC transmitter, | ||
321 | * since this may take quite long | ||
322 | */ | ||
323 | if (bc->modem.ptt) | ||
324 | outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); | ||
325 | else | ||
326 | outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ | ||
327 | break; | ||
328 | |||
329 | default: | ||
330 | msr = inb(MSR(dev->base_addr)); | ||
331 | /* delta DCD */ | ||
332 | if ((msr & 8) && bc->opt_dcd) | ||
333 | hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); | ||
334 | break; | ||
335 | } | ||
336 | iir = inb(IIR(dev->base_addr)); | ||
337 | } while (!(iir & 1)); | ||
338 | ser12_rx(dev, bc, &tv, msr & 0x10); /* CTS */ | ||
339 | if (bc->modem.ptt && txcount) { | ||
340 | if (bc->modem.ser12.txshreg <= 1) { | ||
341 | bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); | ||
342 | if (!hdlcdrv_ptt(&bc->hdrv)) { | ||
343 | ser12_set_divisor(dev, 115200/100/8); | ||
344 | bc->modem.ptt = 0; | ||
345 | goto end_transmit; | ||
346 | } | ||
347 | } | ||
348 | bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1)); | ||
349 | bc->modem.ser12.txshreg >>= 1; | ||
350 | } | ||
351 | end_transmit: | ||
352 | local_irq_enable(); | ||
353 | if (!bc->modem.ptt && txcount) { | ||
354 | hdlcdrv_arbitrate(dev, &bc->hdrv); | ||
355 | if (hdlcdrv_ptt(&bc->hdrv)) { | ||
356 | ser12_set_divisor(dev, bc->baud_uartdiv); | ||
357 | bc->modem.ser12.txshreg = 1; | ||
358 | bc->modem.ptt = 1; | ||
359 | } | ||
360 | } | ||
361 | hdlcdrv_transmitter(dev, &bc->hdrv); | ||
362 | hdlcdrv_receiver(dev, &bc->hdrv); | ||
363 | local_irq_disable(); | ||
364 | return IRQ_HANDLED; | ||
365 | } | ||
366 | |||
367 | /* --------------------------------------------------------------------- */ | ||
368 | |||
369 | enum uart { c_uart_unknown, c_uart_8250, | ||
370 | c_uart_16450, c_uart_16550, c_uart_16550A}; | ||
371 | static const char *uart_str[] = { | ||
372 | "unknown", "8250", "16450", "16550", "16550A" | ||
373 | }; | ||
374 | |||
375 | static enum uart ser12_check_uart(unsigned int iobase) | ||
376 | { | ||
377 | unsigned char b1,b2,b3; | ||
378 | enum uart u; | ||
379 | enum uart uart_tab[] = | ||
380 | { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; | ||
381 | |||
382 | b1 = inb(MCR(iobase)); | ||
383 | outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ | ||
384 | b2 = inb(MSR(iobase)); | ||
385 | outb(0x1a, MCR(iobase)); | ||
386 | b3 = inb(MSR(iobase)) & 0xf0; | ||
387 | outb(b1, MCR(iobase)); /* restore old values */ | ||
388 | outb(b2, MSR(iobase)); | ||
389 | if (b3 != 0x90) | ||
390 | return c_uart_unknown; | ||
391 | inb(RBR(iobase)); | ||
392 | inb(RBR(iobase)); | ||
393 | outb(0x01, FCR(iobase)); /* enable FIFOs */ | ||
394 | u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; | ||
395 | if (u == c_uart_16450) { | ||
396 | outb(0x5a, SCR(iobase)); | ||
397 | b1 = inb(SCR(iobase)); | ||
398 | outb(0xa5, SCR(iobase)); | ||
399 | b2 = inb(SCR(iobase)); | ||
400 | if ((b1 != 0x5a) || (b2 != 0xa5)) | ||
401 | u = c_uart_8250; | ||
402 | } | ||
403 | return u; | ||
404 | } | ||
405 | |||
406 | /* --------------------------------------------------------------------- */ | ||
407 | |||
408 | static int ser12_open(struct net_device *dev) | ||
409 | { | ||
410 | struct baycom_state *bc = netdev_priv(dev); | ||
411 | enum uart u; | ||
412 | |||
413 | if (!dev || !bc) | ||
414 | return -ENXIO; | ||
415 | if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || | ||
416 | dev->irq < 2 || dev->irq > 15) | ||
417 | return -ENXIO; | ||
418 | if (bc->baud < 300 || bc->baud > 4800) | ||
419 | return -EINVAL; | ||
420 | if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) { | ||
421 | printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", | ||
422 | dev->base_addr); | ||
423 | return -EACCES; | ||
424 | } | ||
425 | memset(&bc->modem, 0, sizeof(bc->modem)); | ||
426 | bc->hdrv.par.bitrate = bc->baud; | ||
427 | bc->baud_us = 1000000/bc->baud; | ||
428 | bc->baud_uartdiv = (115200/8)/bc->baud; | ||
429 | if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){ | ||
430 | release_region(dev->base_addr, SER12_EXTENT); | ||
431 | return -EIO; | ||
432 | } | ||
433 | outb(0, FCR(dev->base_addr)); /* disable FIFOs */ | ||
434 | outb(0x0d, MCR(dev->base_addr)); | ||
435 | outb(0, IER(dev->base_addr)); | ||
436 | if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ, | ||
437 | "baycom_ser_fdx", dev)) { | ||
438 | release_region(dev->base_addr, SER12_EXTENT); | ||
439 | return -EBUSY; | ||
440 | } | ||
441 | /* | ||
442 | * set the SIO to 6 Bits/character; during receive, | ||
443 | * the baud rate is set to produce 100 ints/sec | ||
444 | * to feed the channel arbitration process, | ||
445 | * during transmit to baud ints/sec to run | ||
446 | * the transmitter | ||
447 | */ | ||
448 | ser12_set_divisor(dev, 115200/100/8); | ||
449 | /* | ||
450 | * enable transmitter empty interrupt and modem status interrupt | ||
451 | */ | ||
452 | outb(0x0a, IER(dev->base_addr)); | ||
453 | /* | ||
454 | * make sure the next interrupt is generated; | ||
455 | * 0 must be used to power the modem; the modem draws its | ||
456 | * power from the TxD line | ||
457 | */ | ||
458 | outb(0x00, THR(dev->base_addr)); | ||
459 | hdlcdrv_setdcd(&bc->hdrv, 0); | ||
460 | printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u baud %u uart %s\n", | ||
461 | bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | /* --------------------------------------------------------------------- */ | ||
466 | |||
467 | static int ser12_close(struct net_device *dev) | ||
468 | { | ||
469 | struct baycom_state *bc = netdev_priv(dev); | ||
470 | |||
471 | if (!dev || !bc) | ||
472 | return -EINVAL; | ||
473 | /* | ||
474 | * disable interrupts | ||
475 | */ | ||
476 | outb(0, IER(dev->base_addr)); | ||
477 | outb(1, MCR(dev->base_addr)); | ||
478 | free_irq(dev->irq, dev); | ||
479 | release_region(dev->base_addr, SER12_EXTENT); | ||
480 | printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n", | ||
481 | bc_drvname, dev->base_addr, dev->irq); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | /* --------------------------------------------------------------------- */ | ||
486 | /* | ||
487 | * ===================== hdlcdrv driver interface ========================= | ||
488 | */ | ||
489 | |||
490 | /* --------------------------------------------------------------------- */ | ||
491 | |||
492 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, | ||
493 | struct hdlcdrv_ioctl *hi, int cmd); | ||
494 | |||
495 | /* --------------------------------------------------------------------- */ | ||
496 | |||
497 | static struct hdlcdrv_ops ser12_ops = { | ||
498 | .drvname = bc_drvname, | ||
499 | .drvinfo = bc_drvinfo, | ||
500 | .open = ser12_open, | ||
501 | .close = ser12_close, | ||
502 | .ioctl = baycom_ioctl, | ||
503 | }; | ||
504 | |||
505 | /* --------------------------------------------------------------------- */ | ||
506 | |||
507 | static int baycom_setmode(struct baycom_state *bc, const char *modestr) | ||
508 | { | ||
509 | unsigned int baud; | ||
510 | |||
511 | if (!strncmp(modestr, "ser", 3)) { | ||
512 | baud = simple_strtoul(modestr+3, NULL, 10); | ||
513 | if (baud >= 3 && baud <= 48) | ||
514 | bc->baud = baud*100; | ||
515 | } | ||
516 | if (strchr(modestr, '*')) | ||
517 | bc->opt_dcd = 0; | ||
518 | else if (strchr(modestr, '+')) | ||
519 | bc->opt_dcd = -1; | ||
520 | else | ||
521 | bc->opt_dcd = 1; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /* --------------------------------------------------------------------- */ | ||
526 | |||
527 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, | ||
528 | struct hdlcdrv_ioctl *hi, int cmd) | ||
529 | { | ||
530 | struct baycom_state *bc; | ||
531 | struct baycom_ioctl bi; | ||
532 | |||
533 | if (!dev) | ||
534 | return -EINVAL; | ||
535 | |||
536 | bc = netdev_priv(dev); | ||
537 | BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); | ||
538 | |||
539 | if (cmd != SIOCDEVPRIVATE) | ||
540 | return -ENOIOCTLCMD; | ||
541 | switch (hi->cmd) { | ||
542 | default: | ||
543 | break; | ||
544 | |||
545 | case HDLCDRVCTL_GETMODE: | ||
546 | sprintf(hi->data.modename, "ser%u", bc->baud / 100); | ||
547 | if (bc->opt_dcd <= 0) | ||
548 | strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+"); | ||
549 | if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) | ||
550 | return -EFAULT; | ||
551 | return 0; | ||
552 | |||
553 | case HDLCDRVCTL_SETMODE: | ||
554 | if (netif_running(dev) || !capable(CAP_NET_ADMIN)) | ||
555 | return -EACCES; | ||
556 | hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; | ||
557 | return baycom_setmode(bc, hi->data.modename); | ||
558 | |||
559 | case HDLCDRVCTL_MODELIST: | ||
560 | strcpy(hi->data.modename, "ser12,ser3,ser24"); | ||
561 | if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) | ||
562 | return -EFAULT; | ||
563 | return 0; | ||
564 | |||
565 | case HDLCDRVCTL_MODEMPARMASK: | ||
566 | return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; | ||
567 | |||
568 | } | ||
569 | |||
570 | if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) | ||
571 | return -EFAULT; | ||
572 | switch (bi.cmd) { | ||
573 | default: | ||
574 | return -ENOIOCTLCMD; | ||
575 | |||
576 | #ifdef BAYCOM_DEBUG | ||
577 | case BAYCOMCTL_GETDEBUG: | ||
578 | bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; | ||
579 | bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; | ||
580 | bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; | ||
581 | break; | ||
582 | #endif /* BAYCOM_DEBUG */ | ||
583 | |||
584 | } | ||
585 | if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) | ||
586 | return -EFAULT; | ||
587 | return 0; | ||
588 | |||
589 | } | ||
590 | |||
591 | /* --------------------------------------------------------------------- */ | ||
592 | |||
593 | /* | ||
594 | * command line settable parameters | ||
595 | */ | ||
596 | static char *mode[NR_PORTS] = { "ser12*", }; | ||
597 | static int iobase[NR_PORTS] = { 0x3f8, }; | ||
598 | static int irq[NR_PORTS] = { 4, }; | ||
599 | static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 }; | ||
600 | |||
601 | module_param_array(mode, charp, NULL, 0); | ||
602 | MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); | ||
603 | module_param_array(iobase, int, NULL, 0); | ||
604 | MODULE_PARM_DESC(iobase, "baycom io base address"); | ||
605 | module_param_array(irq, int, NULL, 0); | ||
606 | MODULE_PARM_DESC(irq, "baycom irq number"); | ||
607 | module_param_array(baud, int, NULL, 0); | ||
608 | MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)"); | ||
609 | |||
610 | MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); | ||
611 | MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver"); | ||
612 | MODULE_LICENSE("GPL"); | ||
613 | |||
614 | /* --------------------------------------------------------------------- */ | ||
615 | |||
616 | static int __init init_baycomserfdx(void) | ||
617 | { | ||
618 | int i, found = 0; | ||
619 | char set_hw = 1; | ||
620 | |||
621 | printk(bc_drvinfo); | ||
622 | /* | ||
623 | * register net devices | ||
624 | */ | ||
625 | for (i = 0; i < NR_PORTS; i++) { | ||
626 | struct net_device *dev; | ||
627 | struct baycom_state *bc; | ||
628 | char ifname[IFNAMSIZ]; | ||
629 | |||
630 | sprintf(ifname, "bcsf%d", i); | ||
631 | |||
632 | if (!mode[i]) | ||
633 | set_hw = 0; | ||
634 | if (!set_hw) | ||
635 | iobase[i] = irq[i] = 0; | ||
636 | |||
637 | dev = hdlcdrv_register(&ser12_ops, | ||
638 | sizeof(struct baycom_state), | ||
639 | ifname, iobase[i], irq[i], 0); | ||
640 | if (IS_ERR(dev)) | ||
641 | break; | ||
642 | |||
643 | bc = netdev_priv(dev); | ||
644 | if (set_hw && baycom_setmode(bc, mode[i])) | ||
645 | set_hw = 0; | ||
646 | bc->baud = baud[i]; | ||
647 | found++; | ||
648 | baycom_device[i] = dev; | ||
649 | } | ||
650 | |||
651 | if (!found) | ||
652 | return -ENXIO; | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static void __exit cleanup_baycomserfdx(void) | ||
657 | { | ||
658 | int i; | ||
659 | |||
660 | for(i = 0; i < NR_PORTS; i++) { | ||
661 | struct net_device *dev = baycom_device[i]; | ||
662 | if (dev) | ||
663 | hdlcdrv_unregister(dev); | ||
664 | } | ||
665 | } | ||
666 | |||
667 | module_init(init_baycomserfdx); | ||
668 | module_exit(cleanup_baycomserfdx); | ||
669 | |||
670 | /* --------------------------------------------------------------------- */ | ||
671 | |||
672 | #ifndef MODULE | ||
673 | |||
674 | /* | ||
675 | * format: baycom_ser_fdx=io,irq,mode | ||
676 | * mode: ser# hardware DCD | ||
677 | * ser#* software DCD | ||
678 | * ser#+ hardware DCD, inverted signal at DCD pin | ||
679 | * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' | ||
680 | */ | ||
681 | |||
682 | static int __init baycom_ser_fdx_setup(char *str) | ||
683 | { | ||
684 | static unsigned nr_dev; | ||
685 | int ints[4]; | ||
686 | |||
687 | if (nr_dev >= NR_PORTS) | ||
688 | return 0; | ||
689 | str = get_options(str, 4, ints); | ||
690 | if (ints[0] < 2) | ||
691 | return 0; | ||
692 | mode[nr_dev] = str; | ||
693 | iobase[nr_dev] = ints[1]; | ||
694 | irq[nr_dev] = ints[2]; | ||
695 | if (ints[0] >= 3) | ||
696 | baud[nr_dev] = ints[3]; | ||
697 | nr_dev++; | ||
698 | return 1; | ||
699 | } | ||
700 | |||
701 | __setup("baycom_ser_fdx=", baycom_ser_fdx_setup); | ||
702 | |||
703 | #endif /* MODULE */ | ||
704 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c new file mode 100644 index 000000000000..eead85d00962 --- /dev/null +++ b/drivers/net/hamradio/baycom_ser_hdx.c | |||
@@ -0,0 +1,740 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem 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 | * | ||
27 | * Supported modems | ||
28 | * | ||
29 | * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only | ||
30 | * of a modulator/demodulator chip, usually a TI TCM3105. The computer | ||
31 | * is responsible for regenerating the receiver bit clock, as well as | ||
32 | * for handling the HDLC protocol. The modem connects to a serial port, | ||
33 | * hence the name. Since the serial port is not used as an async serial | ||
34 | * port, the kernel driver for serial ports cannot be used, and this | ||
35 | * driver only supports standard serial hardware (8250, 16450, 16550A) | ||
36 | * | ||
37 | * | ||
38 | * Command line options (insmod command line) | ||
39 | * | ||
40 | * mode ser12 hardware DCD | ||
41 | * ser12* software DCD | ||
42 | * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware | ||
43 | * mutes audio input to the modem | ||
44 | * ser12+ hardware DCD, inverted signal at DCD pin | ||
45 | * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 | ||
46 | * irq interrupt line of the port; common values are 4,3 | ||
47 | * | ||
48 | * | ||
49 | * History: | ||
50 | * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface | ||
51 | * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) | ||
52 | * 0.3 26.04.1997 init code/data tagged | ||
53 | * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) | ||
54 | * 0.5 11.11.1997 ser12/par96 split into separate files | ||
55 | * 0.6 14.04.1998 cleanups | ||
56 | * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall | ||
57 | * 0.8 10.08.1999 use module_init/module_exit | ||
58 | * 0.9 12.02.2000 adapted to softnet driver interface | ||
59 | * 0.10 03.07.2000 fix interface name handling | ||
60 | */ | ||
61 | |||
62 | /*****************************************************************************/ | ||
63 | |||
64 | #include <linux/module.h> | ||
65 | #include <linux/ioport.h> | ||
66 | #include <linux/string.h> | ||
67 | #include <linux/init.h> | ||
68 | #include <asm/uaccess.h> | ||
69 | #include <asm/io.h> | ||
70 | #include <linux/hdlcdrv.h> | ||
71 | #include <linux/baycom.h> | ||
72 | |||
73 | /* --------------------------------------------------------------------- */ | ||
74 | |||
75 | #define BAYCOM_DEBUG | ||
76 | |||
77 | /* --------------------------------------------------------------------- */ | ||
78 | |||
79 | static const char bc_drvname[] = "baycom_ser_hdx"; | ||
80 | static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" | ||
81 | KERN_INFO "baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n"; | ||
82 | |||
83 | /* --------------------------------------------------------------------- */ | ||
84 | |||
85 | #define NR_PORTS 4 | ||
86 | |||
87 | static struct net_device *baycom_device[NR_PORTS]; | ||
88 | |||
89 | /* --------------------------------------------------------------------- */ | ||
90 | |||
91 | #define RBR(iobase) (iobase+0) | ||
92 | #define THR(iobase) (iobase+0) | ||
93 | #define IER(iobase) (iobase+1) | ||
94 | #define IIR(iobase) (iobase+2) | ||
95 | #define FCR(iobase) (iobase+2) | ||
96 | #define LCR(iobase) (iobase+3) | ||
97 | #define MCR(iobase) (iobase+4) | ||
98 | #define LSR(iobase) (iobase+5) | ||
99 | #define MSR(iobase) (iobase+6) | ||
100 | #define SCR(iobase) (iobase+7) | ||
101 | #define DLL(iobase) (iobase+0) | ||
102 | #define DLM(iobase) (iobase+1) | ||
103 | |||
104 | #define SER12_EXTENT 8 | ||
105 | |||
106 | /* ---------------------------------------------------------------------- */ | ||
107 | /* | ||
108 | * Information that need to be kept for each board. | ||
109 | */ | ||
110 | |||
111 | struct baycom_state { | ||
112 | struct hdlcdrv_state hdrv; | ||
113 | |||
114 | int opt_dcd; | ||
115 | |||
116 | struct modem_state { | ||
117 | short arb_divider; | ||
118 | unsigned char flags; | ||
119 | unsigned int shreg; | ||
120 | struct modem_state_ser12 { | ||
121 | unsigned char tx_bit; | ||
122 | int dcd_sum0, dcd_sum1, dcd_sum2; | ||
123 | unsigned char last_sample; | ||
124 | unsigned char last_rxbit; | ||
125 | unsigned int dcd_shreg; | ||
126 | unsigned int dcd_time; | ||
127 | unsigned int bit_pll; | ||
128 | unsigned char interm_sample; | ||
129 | } ser12; | ||
130 | } modem; | ||
131 | |||
132 | #ifdef BAYCOM_DEBUG | ||
133 | struct debug_vals { | ||
134 | unsigned long last_jiffies; | ||
135 | unsigned cur_intcnt; | ||
136 | unsigned last_intcnt; | ||
137 | int cur_pllcorr; | ||
138 | int last_pllcorr; | ||
139 | } debug_vals; | ||
140 | #endif /* BAYCOM_DEBUG */ | ||
141 | }; | ||
142 | |||
143 | /* --------------------------------------------------------------------- */ | ||
144 | |||
145 | static inline void baycom_int_freq(struct baycom_state *bc) | ||
146 | { | ||
147 | #ifdef BAYCOM_DEBUG | ||
148 | unsigned long cur_jiffies = jiffies; | ||
149 | /* | ||
150 | * measure the interrupt frequency | ||
151 | */ | ||
152 | bc->debug_vals.cur_intcnt++; | ||
153 | if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { | ||
154 | bc->debug_vals.last_jiffies = cur_jiffies; | ||
155 | bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; | ||
156 | bc->debug_vals.cur_intcnt = 0; | ||
157 | bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; | ||
158 | bc->debug_vals.cur_pllcorr = 0; | ||
159 | } | ||
160 | #endif /* BAYCOM_DEBUG */ | ||
161 | } | ||
162 | |||
163 | /* --------------------------------------------------------------------- */ | ||
164 | /* | ||
165 | * ===================== SER12 specific routines ========================= | ||
166 | */ | ||
167 | |||
168 | static inline void ser12_set_divisor(struct net_device *dev, | ||
169 | unsigned char divisor) | ||
170 | { | ||
171 | outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ | ||
172 | outb(divisor, DLL(dev->base_addr)); | ||
173 | outb(0, DLM(dev->base_addr)); | ||
174 | outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ | ||
175 | /* | ||
176 | * make sure the next interrupt is generated; | ||
177 | * 0 must be used to power the modem; the modem draws its | ||
178 | * power from the TxD line | ||
179 | */ | ||
180 | outb(0x00, THR(dev->base_addr)); | ||
181 | /* | ||
182 | * it is important not to set the divider while transmitting; | ||
183 | * this reportedly makes some UARTs generating interrupts | ||
184 | * in the hundredthousands per second region | ||
185 | * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno) | ||
186 | */ | ||
187 | } | ||
188 | |||
189 | /* --------------------------------------------------------------------- */ | ||
190 | |||
191 | /* | ||
192 | * must call the TX arbitrator every 10ms | ||
193 | */ | ||
194 | #define SER12_ARB_DIVIDER(bc) (bc->opt_dcd ? 24 : 36) | ||
195 | |||
196 | #define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240) | ||
197 | |||
198 | static inline void ser12_tx(struct net_device *dev, struct baycom_state *bc) | ||
199 | { | ||
200 | /* one interrupt per channel bit */ | ||
201 | ser12_set_divisor(dev, 12); | ||
202 | /* | ||
203 | * first output the last bit (!) then call HDLC transmitter, | ||
204 | * since this may take quite long | ||
205 | */ | ||
206 | outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); | ||
207 | if (bc->modem.shreg <= 1) | ||
208 | bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); | ||
209 | bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ | ||
210 | (bc->modem.shreg & 1)); | ||
211 | bc->modem.shreg >>= 1; | ||
212 | } | ||
213 | |||
214 | /* --------------------------------------------------------------------- */ | ||
215 | |||
216 | static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc) | ||
217 | { | ||
218 | unsigned char cur_s; | ||
219 | /* | ||
220 | * do demodulator | ||
221 | */ | ||
222 | cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */ | ||
223 | hdlcdrv_channelbit(&bc->hdrv, cur_s); | ||
224 | bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) | | ||
225 | (cur_s != bc->modem.ser12.last_sample); | ||
226 | bc->modem.ser12.last_sample = cur_s; | ||
227 | if(bc->modem.ser12.dcd_shreg & 1) { | ||
228 | if (!bc->opt_dcd) { | ||
229 | unsigned int dcdspos, dcdsneg; | ||
230 | |||
231 | dcdspos = dcdsneg = 0; | ||
232 | dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); | ||
233 | if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) | ||
234 | dcdspos += 2; | ||
235 | dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); | ||
236 | dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); | ||
237 | dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); | ||
238 | |||
239 | bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; | ||
240 | } else | ||
241 | bc->modem.ser12.dcd_sum0--; | ||
242 | } | ||
243 | if(!bc->modem.ser12.dcd_time) { | ||
244 | hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + | ||
245 | bc->modem.ser12.dcd_sum1 + | ||
246 | bc->modem.ser12.dcd_sum2) < 0); | ||
247 | bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; | ||
248 | bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; | ||
249 | /* offset to ensure DCD off on silent input */ | ||
250 | bc->modem.ser12.dcd_sum0 = 2; | ||
251 | bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); | ||
252 | } | ||
253 | bc->modem.ser12.dcd_time--; | ||
254 | if (!bc->opt_dcd) { | ||
255 | /* | ||
256 | * PLL code for the improved software DCD algorithm | ||
257 | */ | ||
258 | if (bc->modem.ser12.interm_sample) { | ||
259 | /* | ||
260 | * intermediate sample; set timing correction to normal | ||
261 | */ | ||
262 | ser12_set_divisor(dev, 4); | ||
263 | } else { | ||
264 | /* | ||
265 | * do PLL correction and call HDLC receiver | ||
266 | */ | ||
267 | switch (bc->modem.ser12.dcd_shreg & 7) { | ||
268 | case 1: /* transition too late */ | ||
269 | ser12_set_divisor(dev, 5); | ||
270 | #ifdef BAYCOM_DEBUG | ||
271 | bc->debug_vals.cur_pllcorr++; | ||
272 | #endif /* BAYCOM_DEBUG */ | ||
273 | break; | ||
274 | case 4: /* transition too early */ | ||
275 | ser12_set_divisor(dev, 3); | ||
276 | #ifdef BAYCOM_DEBUG | ||
277 | bc->debug_vals.cur_pllcorr--; | ||
278 | #endif /* BAYCOM_DEBUG */ | ||
279 | break; | ||
280 | default: | ||
281 | ser12_set_divisor(dev, 4); | ||
282 | break; | ||
283 | } | ||
284 | bc->modem.shreg >>= 1; | ||
285 | if (bc->modem.ser12.last_sample == | ||
286 | bc->modem.ser12.last_rxbit) | ||
287 | bc->modem.shreg |= 0x10000; | ||
288 | bc->modem.ser12.last_rxbit = | ||
289 | bc->modem.ser12.last_sample; | ||
290 | } | ||
291 | if (++bc->modem.ser12.interm_sample >= 3) | ||
292 | bc->modem.ser12.interm_sample = 0; | ||
293 | /* | ||
294 | * DCD stuff | ||
295 | */ | ||
296 | if (bc->modem.ser12.dcd_shreg & 1) { | ||
297 | unsigned int dcdspos, dcdsneg; | ||
298 | |||
299 | dcdspos = dcdsneg = 0; | ||
300 | dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); | ||
301 | dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) | ||
302 | << 1; | ||
303 | dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); | ||
304 | dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); | ||
305 | dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); | ||
306 | |||
307 | bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; | ||
308 | } | ||
309 | } else { | ||
310 | /* | ||
311 | * PLL algorithm for the hardware squelch DCD algorithm | ||
312 | */ | ||
313 | if (bc->modem.ser12.interm_sample) { | ||
314 | /* | ||
315 | * intermediate sample; set timing correction to normal | ||
316 | */ | ||
317 | ser12_set_divisor(dev, 6); | ||
318 | } else { | ||
319 | /* | ||
320 | * do PLL correction and call HDLC receiver | ||
321 | */ | ||
322 | switch (bc->modem.ser12.dcd_shreg & 3) { | ||
323 | case 1: /* transition too late */ | ||
324 | ser12_set_divisor(dev, 7); | ||
325 | #ifdef BAYCOM_DEBUG | ||
326 | bc->debug_vals.cur_pllcorr++; | ||
327 | #endif /* BAYCOM_DEBUG */ | ||
328 | break; | ||
329 | case 2: /* transition too early */ | ||
330 | ser12_set_divisor(dev, 5); | ||
331 | #ifdef BAYCOM_DEBUG | ||
332 | bc->debug_vals.cur_pllcorr--; | ||
333 | #endif /* BAYCOM_DEBUG */ | ||
334 | break; | ||
335 | default: | ||
336 | ser12_set_divisor(dev, 6); | ||
337 | break; | ||
338 | } | ||
339 | bc->modem.shreg >>= 1; | ||
340 | if (bc->modem.ser12.last_sample == | ||
341 | bc->modem.ser12.last_rxbit) | ||
342 | bc->modem.shreg |= 0x10000; | ||
343 | bc->modem.ser12.last_rxbit = | ||
344 | bc->modem.ser12.last_sample; | ||
345 | } | ||
346 | bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample; | ||
347 | /* | ||
348 | * DCD stuff | ||
349 | */ | ||
350 | bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1); | ||
351 | } | ||
352 | outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ | ||
353 | if (bc->modem.shreg & 1) { | ||
354 | hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); | ||
355 | bc->modem.shreg = 0x10000; | ||
356 | } | ||
357 | if(!bc->modem.ser12.dcd_time) { | ||
358 | if (bc->opt_dcd & 1) | ||
359 | hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80)); | ||
360 | else | ||
361 | hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + | ||
362 | bc->modem.ser12.dcd_sum1 + | ||
363 | bc->modem.ser12.dcd_sum2) < 0); | ||
364 | bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; | ||
365 | bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; | ||
366 | /* offset to ensure DCD off on silent input */ | ||
367 | bc->modem.ser12.dcd_sum0 = 2; | ||
368 | bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); | ||
369 | } | ||
370 | bc->modem.ser12.dcd_time--; | ||
371 | } | ||
372 | |||
373 | /* --------------------------------------------------------------------- */ | ||
374 | |||
375 | static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
376 | { | ||
377 | struct net_device *dev = (struct net_device *)dev_id; | ||
378 | struct baycom_state *bc = netdev_priv(dev); | ||
379 | unsigned char iir; | ||
380 | |||
381 | if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) | ||
382 | return IRQ_NONE; | ||
383 | /* fast way out */ | ||
384 | if ((iir = inb(IIR(dev->base_addr))) & 1) | ||
385 | return IRQ_NONE; | ||
386 | baycom_int_freq(bc); | ||
387 | do { | ||
388 | switch (iir & 6) { | ||
389 | case 6: | ||
390 | inb(LSR(dev->base_addr)); | ||
391 | break; | ||
392 | |||
393 | case 4: | ||
394 | inb(RBR(dev->base_addr)); | ||
395 | break; | ||
396 | |||
397 | case 2: | ||
398 | /* | ||
399 | * check if transmitter active | ||
400 | */ | ||
401 | if (hdlcdrv_ptt(&bc->hdrv)) | ||
402 | ser12_tx(dev, bc); | ||
403 | else { | ||
404 | ser12_rx(dev, bc); | ||
405 | bc->modem.arb_divider--; | ||
406 | } | ||
407 | outb(0x00, THR(dev->base_addr)); | ||
408 | break; | ||
409 | |||
410 | default: | ||
411 | inb(MSR(dev->base_addr)); | ||
412 | break; | ||
413 | } | ||
414 | iir = inb(IIR(dev->base_addr)); | ||
415 | } while (!(iir & 1)); | ||
416 | if (bc->modem.arb_divider <= 0) { | ||
417 | bc->modem.arb_divider = SER12_ARB_DIVIDER(bc); | ||
418 | local_irq_enable(); | ||
419 | hdlcdrv_arbitrate(dev, &bc->hdrv); | ||
420 | } | ||
421 | local_irq_enable(); | ||
422 | hdlcdrv_transmitter(dev, &bc->hdrv); | ||
423 | hdlcdrv_receiver(dev, &bc->hdrv); | ||
424 | local_irq_disable(); | ||
425 | return IRQ_HANDLED; | ||
426 | } | ||
427 | |||
428 | /* --------------------------------------------------------------------- */ | ||
429 | |||
430 | enum uart { c_uart_unknown, c_uart_8250, | ||
431 | c_uart_16450, c_uart_16550, c_uart_16550A}; | ||
432 | static const char *uart_str[] = { | ||
433 | "unknown", "8250", "16450", "16550", "16550A" | ||
434 | }; | ||
435 | |||
436 | static enum uart ser12_check_uart(unsigned int iobase) | ||
437 | { | ||
438 | unsigned char b1,b2,b3; | ||
439 | enum uart u; | ||
440 | enum uart uart_tab[] = | ||
441 | { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; | ||
442 | |||
443 | b1 = inb(MCR(iobase)); | ||
444 | outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ | ||
445 | b2 = inb(MSR(iobase)); | ||
446 | outb(0x1a, MCR(iobase)); | ||
447 | b3 = inb(MSR(iobase)) & 0xf0; | ||
448 | outb(b1, MCR(iobase)); /* restore old values */ | ||
449 | outb(b2, MSR(iobase)); | ||
450 | if (b3 != 0x90) | ||
451 | return c_uart_unknown; | ||
452 | inb(RBR(iobase)); | ||
453 | inb(RBR(iobase)); | ||
454 | outb(0x01, FCR(iobase)); /* enable FIFOs */ | ||
455 | u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; | ||
456 | if (u == c_uart_16450) { | ||
457 | outb(0x5a, SCR(iobase)); | ||
458 | b1 = inb(SCR(iobase)); | ||
459 | outb(0xa5, SCR(iobase)); | ||
460 | b2 = inb(SCR(iobase)); | ||
461 | if ((b1 != 0x5a) || (b2 != 0xa5)) | ||
462 | u = c_uart_8250; | ||
463 | } | ||
464 | return u; | ||
465 | } | ||
466 | |||
467 | /* --------------------------------------------------------------------- */ | ||
468 | |||
469 | static int ser12_open(struct net_device *dev) | ||
470 | { | ||
471 | struct baycom_state *bc = netdev_priv(dev); | ||
472 | enum uart u; | ||
473 | |||
474 | if (!dev || !bc) | ||
475 | return -ENXIO; | ||
476 | if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || | ||
477 | dev->irq < 2 || dev->irq > 15) | ||
478 | return -ENXIO; | ||
479 | if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12")) | ||
480 | return -EACCES; | ||
481 | memset(&bc->modem, 0, sizeof(bc->modem)); | ||
482 | bc->hdrv.par.bitrate = 1200; | ||
483 | if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) { | ||
484 | release_region(dev->base_addr, SER12_EXTENT); | ||
485 | return -EIO; | ||
486 | } | ||
487 | outb(0, FCR(dev->base_addr)); /* disable FIFOs */ | ||
488 | outb(0x0d, MCR(dev->base_addr)); | ||
489 | outb(0, IER(dev->base_addr)); | ||
490 | if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ, | ||
491 | "baycom_ser12", dev)) { | ||
492 | release_region(dev->base_addr, SER12_EXTENT); | ||
493 | return -EBUSY; | ||
494 | } | ||
495 | /* | ||
496 | * enable transmitter empty interrupt | ||
497 | */ | ||
498 | outb(2, IER(dev->base_addr)); | ||
499 | /* | ||
500 | * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that | ||
501 | * we get exactly (hopefully) 2 or 3 interrupts per radio symbol, | ||
502 | * depending on the usage of the software DCD routine | ||
503 | */ | ||
504 | ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4); | ||
505 | printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u uart %s\n", | ||
506 | bc_drvname, dev->base_addr, dev->irq, uart_str[u]); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | /* --------------------------------------------------------------------- */ | ||
511 | |||
512 | static int ser12_close(struct net_device *dev) | ||
513 | { | ||
514 | struct baycom_state *bc = netdev_priv(dev); | ||
515 | |||
516 | if (!dev || !bc) | ||
517 | return -EINVAL; | ||
518 | /* | ||
519 | * disable interrupts | ||
520 | */ | ||
521 | outb(0, IER(dev->base_addr)); | ||
522 | outb(1, MCR(dev->base_addr)); | ||
523 | free_irq(dev->irq, dev); | ||
524 | release_region(dev->base_addr, SER12_EXTENT); | ||
525 | printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n", | ||
526 | bc_drvname, dev->base_addr, dev->irq); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /* --------------------------------------------------------------------- */ | ||
531 | /* | ||
532 | * ===================== hdlcdrv driver interface ========================= | ||
533 | */ | ||
534 | |||
535 | /* --------------------------------------------------------------------- */ | ||
536 | |||
537 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, | ||
538 | struct hdlcdrv_ioctl *hi, int cmd); | ||
539 | |||
540 | /* --------------------------------------------------------------------- */ | ||
541 | |||
542 | static struct hdlcdrv_ops ser12_ops = { | ||
543 | .drvname = bc_drvname, | ||
544 | .drvinfo = bc_drvinfo, | ||
545 | .open = ser12_open, | ||
546 | .close = ser12_close, | ||
547 | .ioctl = baycom_ioctl, | ||
548 | }; | ||
549 | |||
550 | /* --------------------------------------------------------------------- */ | ||
551 | |||
552 | static int baycom_setmode(struct baycom_state *bc, const char *modestr) | ||
553 | { | ||
554 | if (strchr(modestr, '*')) | ||
555 | bc->opt_dcd = 0; | ||
556 | else if (strchr(modestr, '+')) | ||
557 | bc->opt_dcd = -1; | ||
558 | else if (strchr(modestr, '@')) | ||
559 | bc->opt_dcd = -2; | ||
560 | else | ||
561 | bc->opt_dcd = 1; | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | /* --------------------------------------------------------------------- */ | ||
566 | |||
567 | static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, | ||
568 | struct hdlcdrv_ioctl *hi, int cmd) | ||
569 | { | ||
570 | struct baycom_state *bc; | ||
571 | struct baycom_ioctl bi; | ||
572 | |||
573 | if (!dev) | ||
574 | return -EINVAL; | ||
575 | |||
576 | bc = netdev_priv(dev); | ||
577 | BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); | ||
578 | |||
579 | if (cmd != SIOCDEVPRIVATE) | ||
580 | return -ENOIOCTLCMD; | ||
581 | switch (hi->cmd) { | ||
582 | default: | ||
583 | break; | ||
584 | |||
585 | case HDLCDRVCTL_GETMODE: | ||
586 | strcpy(hi->data.modename, "ser12"); | ||
587 | if (bc->opt_dcd <= 0) | ||
588 | strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+"); | ||
589 | if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) | ||
590 | return -EFAULT; | ||
591 | return 0; | ||
592 | |||
593 | case HDLCDRVCTL_SETMODE: | ||
594 | if (netif_running(dev) || !capable(CAP_NET_ADMIN)) | ||
595 | return -EACCES; | ||
596 | hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; | ||
597 | return baycom_setmode(bc, hi->data.modename); | ||
598 | |||
599 | case HDLCDRVCTL_MODELIST: | ||
600 | strcpy(hi->data.modename, "ser12"); | ||
601 | if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) | ||
602 | return -EFAULT; | ||
603 | return 0; | ||
604 | |||
605 | case HDLCDRVCTL_MODEMPARMASK: | ||
606 | return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ; | ||
607 | |||
608 | } | ||
609 | |||
610 | if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) | ||
611 | return -EFAULT; | ||
612 | switch (bi.cmd) { | ||
613 | default: | ||
614 | return -ENOIOCTLCMD; | ||
615 | |||
616 | #ifdef BAYCOM_DEBUG | ||
617 | case BAYCOMCTL_GETDEBUG: | ||
618 | bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; | ||
619 | bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; | ||
620 | bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; | ||
621 | break; | ||
622 | #endif /* BAYCOM_DEBUG */ | ||
623 | |||
624 | } | ||
625 | if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) | ||
626 | return -EFAULT; | ||
627 | return 0; | ||
628 | |||
629 | } | ||
630 | |||
631 | /* --------------------------------------------------------------------- */ | ||
632 | |||
633 | /* | ||
634 | * command line settable parameters | ||
635 | */ | ||
636 | static char *mode[NR_PORTS] = { "ser12*", }; | ||
637 | static int iobase[NR_PORTS] = { 0x3f8, }; | ||
638 | static int irq[NR_PORTS] = { 4, }; | ||
639 | |||
640 | module_param_array(mode, charp, NULL, 0); | ||
641 | MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD"); | ||
642 | module_param_array(iobase, int, NULL, 0); | ||
643 | MODULE_PARM_DESC(iobase, "baycom io base address"); | ||
644 | module_param_array(irq, int, NULL, 0); | ||
645 | MODULE_PARM_DESC(irq, "baycom irq number"); | ||
646 | |||
647 | MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); | ||
648 | MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver"); | ||
649 | MODULE_LICENSE("GPL"); | ||
650 | |||
651 | /* --------------------------------------------------------------------- */ | ||
652 | |||
653 | static int __init init_baycomserhdx(void) | ||
654 | { | ||
655 | int i, found = 0; | ||
656 | char set_hw = 1; | ||
657 | |||
658 | printk(bc_drvinfo); | ||
659 | /* | ||
660 | * register net devices | ||
661 | */ | ||
662 | for (i = 0; i < NR_PORTS; i++) { | ||
663 | struct net_device *dev; | ||
664 | struct baycom_state *bc; | ||
665 | char ifname[IFNAMSIZ]; | ||
666 | |||
667 | sprintf(ifname, "bcsh%d", i); | ||
668 | |||
669 | if (!mode[i]) | ||
670 | set_hw = 0; | ||
671 | if (!set_hw) | ||
672 | iobase[i] = irq[i] = 0; | ||
673 | |||
674 | dev = hdlcdrv_register(&ser12_ops, | ||
675 | sizeof(struct baycom_state), | ||
676 | ifname, iobase[i], irq[i], 0); | ||
677 | if (IS_ERR(dev)) | ||
678 | break; | ||
679 | |||
680 | bc = netdev_priv(dev); | ||
681 | if (set_hw && baycom_setmode(bc, mode[i])) | ||
682 | set_hw = 0; | ||
683 | found++; | ||
684 | baycom_device[i] = dev; | ||
685 | } | ||
686 | |||
687 | if (!found) | ||
688 | return -ENXIO; | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static void __exit cleanup_baycomserhdx(void) | ||
693 | { | ||
694 | int i; | ||
695 | |||
696 | for(i = 0; i < NR_PORTS; i++) { | ||
697 | struct net_device *dev = baycom_device[i]; | ||
698 | |||
699 | if (dev) | ||
700 | hdlcdrv_unregister(dev); | ||
701 | } | ||
702 | } | ||
703 | |||
704 | module_init(init_baycomserhdx); | ||
705 | module_exit(cleanup_baycomserhdx); | ||
706 | |||
707 | /* --------------------------------------------------------------------- */ | ||
708 | |||
709 | #ifndef MODULE | ||
710 | |||
711 | /* | ||
712 | * format: baycom_ser_hdx=io,irq,mode | ||
713 | * mode: ser12 hardware DCD | ||
714 | * ser12* software DCD | ||
715 | * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware | ||
716 | * mutes audio input to the modem | ||
717 | * ser12+ hardware DCD, inverted signal at DCD pin | ||
718 | */ | ||
719 | |||
720 | static int __init baycom_ser_hdx_setup(char *str) | ||
721 | { | ||
722 | static unsigned nr_dev; | ||
723 | int ints[3]; | ||
724 | |||
725 | if (nr_dev >= NR_PORTS) | ||
726 | return 0; | ||
727 | str = get_options(str, 3, ints); | ||
728 | if (ints[0] < 2) | ||
729 | return 0; | ||
730 | mode[nr_dev] = str; | ||
731 | iobase[nr_dev] = ints[1]; | ||
732 | irq[nr_dev] = ints[2]; | ||
733 | nr_dev++; | ||
734 | return 1; | ||
735 | } | ||
736 | |||
737 | __setup("baycom_ser_hdx=", baycom_ser_hdx_setup); | ||
738 | |||
739 | #endif /* MODULE */ | ||
740 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c new file mode 100644 index 000000000000..ef1a359e2273 --- /dev/null +++ b/drivers/net/hamradio/bpqether.c | |||
@@ -0,0 +1,643 @@ | |||
1 | /* | ||
2 | * G8BPQ compatible "AX.25 via ethernet" driver release 004 | ||
3 | * | ||
4 | * This code REQUIRES 2.0.0 or higher/ NET3.029 | ||
5 | * | ||
6 | * This module: | ||
7 | * This module is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This is a "pseudo" network driver to allow AX.25 over Ethernet | ||
13 | * using G8BPQ encapsulation. It has been extracted from the protocol | ||
14 | * implementation because | ||
15 | * | ||
16 | * - things got unreadable within the protocol stack | ||
17 | * - to cure the protocol stack from "feature-ism" | ||
18 | * - a protocol implementation shouldn't need to know on | ||
19 | * which hardware it is running | ||
20 | * - user-level programs like the AX.25 utilities shouldn't | ||
21 | * need to know about the hardware. | ||
22 | * - IP over ethernet encapsulated AX.25 was impossible | ||
23 | * - rxecho.c did not work | ||
24 | * - to have room for extensions | ||
25 | * - it just deserves to "live" as an own driver | ||
26 | * | ||
27 | * This driver can use any ethernet destination address, and can be | ||
28 | * limited to accept frames from one dedicated ethernet card only. | ||
29 | * | ||
30 | * Note that the driver sets up the BPQ devices automagically on | ||
31 | * startup or (if started before the "insmod" of an ethernet device) | ||
32 | * on "ifconfig up". It hopefully will remove the BPQ on "rmmod"ing | ||
33 | * the ethernet device (in fact: as soon as another ethernet or bpq | ||
34 | * device gets "ifconfig"ured). | ||
35 | * | ||
36 | * I have heard that several people are thinking of experiments | ||
37 | * with highspeed packet radio using existing ethernet cards. | ||
38 | * Well, this driver is prepared for this purpose, just add | ||
39 | * your tx key control and a txdelay / tailtime algorithm, | ||
40 | * probably some buffering, and /voila/... | ||
41 | * | ||
42 | * History | ||
43 | * BPQ 001 Joerg(DL1BKE) Extracted BPQ code from AX.25 | ||
44 | * protocol stack and added my own | ||
45 | * yet existing patches | ||
46 | * BPQ 002 Joerg(DL1BKE) Scan network device list on | ||
47 | * startup. | ||
48 | * BPQ 003 Joerg(DL1BKE) Ethernet destination address | ||
49 | * and accepted source address | ||
50 | * can be configured by an ioctl() | ||
51 | * call. | ||
52 | * Fixed to match Linux networking | ||
53 | * changes - 2.1.15. | ||
54 | * BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig. | ||
55 | */ | ||
56 | |||
57 | #include <linux/config.h> | ||
58 | #include <linux/errno.h> | ||
59 | #include <linux/types.h> | ||
60 | #include <linux/socket.h> | ||
61 | #include <linux/in.h> | ||
62 | #include <linux/kernel.h> | ||
63 | #include <linux/string.h> | ||
64 | #include <linux/net.h> | ||
65 | #include <net/ax25.h> | ||
66 | #include <linux/inet.h> | ||
67 | #include <linux/netdevice.h> | ||
68 | #include <linux/if_ether.h> | ||
69 | #include <linux/if_arp.h> | ||
70 | #include <linux/skbuff.h> | ||
71 | #include <net/sock.h> | ||
72 | #include <asm/system.h> | ||
73 | #include <asm/uaccess.h> | ||
74 | #include <linux/mm.h> | ||
75 | #include <linux/interrupt.h> | ||
76 | #include <linux/notifier.h> | ||
77 | #include <linux/proc_fs.h> | ||
78 | #include <linux/seq_file.h> | ||
79 | #include <linux/stat.h> | ||
80 | #include <linux/netfilter.h> | ||
81 | #include <linux/module.h> | ||
82 | #include <linux/init.h> | ||
83 | #include <linux/rtnetlink.h> | ||
84 | |||
85 | #include <net/ip.h> | ||
86 | #include <net/arp.h> | ||
87 | |||
88 | #include <linux/bpqether.h> | ||
89 | |||
90 | static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n"; | ||
91 | |||
92 | static unsigned char ax25_bcast[AX25_ADDR_LEN] = | ||
93 | {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; | ||
94 | static unsigned char ax25_defaddr[AX25_ADDR_LEN] = | ||
95 | {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; | ||
96 | |||
97 | static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; | ||
98 | |||
99 | static char bpq_eth_addr[6]; | ||
100 | |||
101 | static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *); | ||
102 | static int bpq_device_event(struct notifier_block *, unsigned long, void *); | ||
103 | static const char *bpq_print_ethaddr(const unsigned char *); | ||
104 | |||
105 | static struct packet_type bpq_packet_type = { | ||
106 | .type = __constant_htons(ETH_P_BPQ), | ||
107 | .func = bpq_rcv, | ||
108 | }; | ||
109 | |||
110 | static struct notifier_block bpq_dev_notifier = { | ||
111 | .notifier_call =bpq_device_event, | ||
112 | }; | ||
113 | |||
114 | |||
115 | struct bpqdev { | ||
116 | struct list_head bpq_list; /* list of bpq devices chain */ | ||
117 | struct net_device *ethdev; /* link to ethernet device */ | ||
118 | struct net_device *axdev; /* bpq device (bpq#) */ | ||
119 | struct net_device_stats stats; /* some statistics */ | ||
120 | char dest_addr[6]; /* ether destination address */ | ||
121 | char acpt_addr[6]; /* accept ether frames from this address only */ | ||
122 | }; | ||
123 | |||
124 | static LIST_HEAD(bpq_devices); | ||
125 | |||
126 | |||
127 | /* ------------------------------------------------------------------------ */ | ||
128 | |||
129 | |||
130 | /* | ||
131 | * Get the ethernet device for a BPQ device | ||
132 | */ | ||
133 | static inline struct net_device *bpq_get_ether_dev(struct net_device *dev) | ||
134 | { | ||
135 | struct bpqdev *bpq = netdev_priv(dev); | ||
136 | |||
137 | return bpq ? bpq->ethdev : NULL; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Get the BPQ device for the ethernet device | ||
142 | */ | ||
143 | static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) | ||
144 | { | ||
145 | struct bpqdev *bpq; | ||
146 | |||
147 | list_for_each_entry(bpq, &bpq_devices, bpq_list) { | ||
148 | if (bpq->ethdev == dev) | ||
149 | return bpq->axdev; | ||
150 | } | ||
151 | return NULL; | ||
152 | } | ||
153 | |||
154 | static inline int dev_is_ethdev(struct net_device *dev) | ||
155 | { | ||
156 | return ( | ||
157 | dev->type == ARPHRD_ETHER | ||
158 | && strncmp(dev->name, "dummy", 5) | ||
159 | ); | ||
160 | } | ||
161 | |||
162 | /* ------------------------------------------------------------------------ */ | ||
163 | |||
164 | |||
165 | /* | ||
166 | * Receive an AX.25 frame via an ethernet interface. | ||
167 | */ | ||
168 | static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype) | ||
169 | { | ||
170 | int len; | ||
171 | char * ptr; | ||
172 | struct ethhdr *eth; | ||
173 | struct bpqdev *bpq; | ||
174 | |||
175 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) | ||
176 | return NET_RX_DROP; | ||
177 | |||
178 | if (!pskb_may_pull(skb, sizeof(struct ethhdr))) | ||
179 | goto drop; | ||
180 | |||
181 | rcu_read_lock(); | ||
182 | dev = bpq_get_ax25_dev(dev); | ||
183 | |||
184 | if (dev == NULL || !netif_running(dev)) | ||
185 | goto drop_unlock; | ||
186 | |||
187 | /* | ||
188 | * if we want to accept frames from just one ethernet device | ||
189 | * we check the source address of the sender. | ||
190 | */ | ||
191 | |||
192 | bpq = netdev_priv(dev); | ||
193 | |||
194 | eth = eth_hdr(skb); | ||
195 | |||
196 | if (!(bpq->acpt_addr[0] & 0x01) && | ||
197 | memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) | ||
198 | goto drop_unlock; | ||
199 | |||
200 | if (skb_cow(skb, sizeof(struct ethhdr))) | ||
201 | goto drop_unlock; | ||
202 | |||
203 | len = skb->data[0] + skb->data[1] * 256 - 5; | ||
204 | |||
205 | skb_pull(skb, 2); /* Remove the length bytes */ | ||
206 | skb_trim(skb, len); /* Set the length of the data */ | ||
207 | |||
208 | bpq->stats.rx_packets++; | ||
209 | bpq->stats.rx_bytes += len; | ||
210 | |||
211 | ptr = skb_push(skb, 1); | ||
212 | *ptr = 0; | ||
213 | |||
214 | skb->dev = dev; | ||
215 | skb->protocol = htons(ETH_P_AX25); | ||
216 | skb->mac.raw = skb->data; | ||
217 | skb->pkt_type = PACKET_HOST; | ||
218 | |||
219 | netif_rx(skb); | ||
220 | dev->last_rx = jiffies; | ||
221 | unlock: | ||
222 | |||
223 | rcu_read_unlock(); | ||
224 | |||
225 | return 0; | ||
226 | drop_unlock: | ||
227 | kfree_skb(skb); | ||
228 | goto unlock; | ||
229 | |||
230 | drop: | ||
231 | kfree_skb(skb); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Send an AX.25 frame via an ethernet interface | ||
237 | */ | ||
238 | static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) | ||
239 | { | ||
240 | struct sk_buff *newskb; | ||
241 | unsigned char *ptr; | ||
242 | struct bpqdev *bpq; | ||
243 | int size; | ||
244 | |||
245 | /* | ||
246 | * Just to be *really* sure not to send anything if the interface | ||
247 | * is down, the ethernet device may have gone. | ||
248 | */ | ||
249 | if (!netif_running(dev)) { | ||
250 | kfree_skb(skb); | ||
251 | return -ENODEV; | ||
252 | } | ||
253 | |||
254 | skb_pull(skb, 1); | ||
255 | size = skb->len; | ||
256 | |||
257 | /* | ||
258 | * The AX.25 code leaves enough room for the ethernet header, but | ||
259 | * sendto() does not. | ||
260 | */ | ||
261 | if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ | ||
262 | if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { | ||
263 | printk(KERN_WARNING "bpqether: out of memory\n"); | ||
264 | kfree_skb(skb); | ||
265 | return -ENOMEM; | ||
266 | } | ||
267 | |||
268 | if (skb->sk != NULL) | ||
269 | skb_set_owner_w(newskb, skb->sk); | ||
270 | |||
271 | kfree_skb(skb); | ||
272 | skb = newskb; | ||
273 | } | ||
274 | |||
275 | skb->protocol = htons(ETH_P_AX25); | ||
276 | |||
277 | ptr = skb_push(skb, 2); | ||
278 | |||
279 | *ptr++ = (size + 5) % 256; | ||
280 | *ptr++ = (size + 5) / 256; | ||
281 | |||
282 | bpq = netdev_priv(dev); | ||
283 | |||
284 | if ((dev = bpq_get_ether_dev(dev)) == NULL) { | ||
285 | bpq->stats.tx_dropped++; | ||
286 | kfree_skb(skb); | ||
287 | return -ENODEV; | ||
288 | } | ||
289 | |||
290 | skb->dev = dev; | ||
291 | skb->nh.raw = skb->data; | ||
292 | dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); | ||
293 | bpq->stats.tx_packets++; | ||
294 | bpq->stats.tx_bytes+=skb->len; | ||
295 | |||
296 | dev_queue_xmit(skb); | ||
297 | netif_wake_queue(dev); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Statistics | ||
303 | */ | ||
304 | static struct net_device_stats *bpq_get_stats(struct net_device *dev) | ||
305 | { | ||
306 | struct bpqdev *bpq = netdev_priv(dev); | ||
307 | |||
308 | return &bpq->stats; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Set AX.25 callsign | ||
313 | */ | ||
314 | static int bpq_set_mac_address(struct net_device *dev, void *addr) | ||
315 | { | ||
316 | struct sockaddr *sa = (struct sockaddr *)addr; | ||
317 | |||
318 | memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | /* Ioctl commands | ||
324 | * | ||
325 | * SIOCSBPQETHOPT reserved for enhancements | ||
326 | * SIOCSBPQETHADDR set the destination and accepted | ||
327 | * source ethernet address (broadcast | ||
328 | * or multicast: accept all) | ||
329 | */ | ||
330 | static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
331 | { | ||
332 | struct bpq_ethaddr __user *ethaddr = ifr->ifr_data; | ||
333 | struct bpqdev *bpq = netdev_priv(dev); | ||
334 | struct bpq_req req; | ||
335 | |||
336 | if (!capable(CAP_NET_ADMIN)) | ||
337 | return -EPERM; | ||
338 | |||
339 | switch (cmd) { | ||
340 | case SIOCSBPQETHOPT: | ||
341 | if (copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req))) | ||
342 | return -EFAULT; | ||
343 | switch (req.cmd) { | ||
344 | case SIOCGBPQETHPARAM: | ||
345 | case SIOCSBPQETHPARAM: | ||
346 | default: | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
350 | break; | ||
351 | |||
352 | case SIOCSBPQETHADDR: | ||
353 | if (copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN)) | ||
354 | return -EFAULT; | ||
355 | if (copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN)) | ||
356 | return -EFAULT; | ||
357 | break; | ||
358 | |||
359 | default: | ||
360 | return -EINVAL; | ||
361 | } | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * open/close a device | ||
368 | */ | ||
369 | static int bpq_open(struct net_device *dev) | ||
370 | { | ||
371 | netif_start_queue(dev); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int bpq_close(struct net_device *dev) | ||
376 | { | ||
377 | netif_stop_queue(dev); | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | |||
382 | /* ------------------------------------------------------------------------ */ | ||
383 | |||
384 | |||
385 | /* | ||
386 | * Proc filesystem | ||
387 | */ | ||
388 | static const char * bpq_print_ethaddr(const unsigned char *e) | ||
389 | { | ||
390 | static char buf[18]; | ||
391 | |||
392 | sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", | ||
393 | e[0], e[1], e[2], e[3], e[4], e[5]); | ||
394 | |||
395 | return buf; | ||
396 | } | ||
397 | |||
398 | static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) | ||
399 | { | ||
400 | int i = 1; | ||
401 | struct bpqdev *bpqdev; | ||
402 | |||
403 | rcu_read_lock(); | ||
404 | |||
405 | if (*pos == 0) | ||
406 | return SEQ_START_TOKEN; | ||
407 | |||
408 | list_for_each_entry(bpqdev, &bpq_devices, bpq_list) { | ||
409 | if (i == *pos) | ||
410 | return bpqdev; | ||
411 | } | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
416 | { | ||
417 | struct list_head *p; | ||
418 | |||
419 | ++*pos; | ||
420 | |||
421 | if (v == SEQ_START_TOKEN) | ||
422 | p = bpq_devices.next; | ||
423 | else | ||
424 | p = ((struct bpqdev *)v)->bpq_list.next; | ||
425 | |||
426 | return (p == &bpq_devices) ? NULL | ||
427 | : list_entry(p, struct bpqdev, bpq_list); | ||
428 | } | ||
429 | |||
430 | static void bpq_seq_stop(struct seq_file *seq, void *v) | ||
431 | { | ||
432 | rcu_read_unlock(); | ||
433 | } | ||
434 | |||
435 | |||
436 | static int bpq_seq_show(struct seq_file *seq, void *v) | ||
437 | { | ||
438 | if (v == SEQ_START_TOKEN) | ||
439 | seq_puts(seq, | ||
440 | "dev ether destination accept from\n"); | ||
441 | else { | ||
442 | const struct bpqdev *bpqdev = v; | ||
443 | |||
444 | seq_printf(seq, "%-5s %-10s %s ", | ||
445 | bpqdev->axdev->name, bpqdev->ethdev->name, | ||
446 | bpq_print_ethaddr(bpqdev->dest_addr)); | ||
447 | |||
448 | seq_printf(seq, "%s\n", | ||
449 | (bpqdev->acpt_addr[0] & 0x01) ? "*" | ||
450 | : bpq_print_ethaddr(bpqdev->acpt_addr)); | ||
451 | |||
452 | } | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static struct seq_operations bpq_seqops = { | ||
457 | .start = bpq_seq_start, | ||
458 | .next = bpq_seq_next, | ||
459 | .stop = bpq_seq_stop, | ||
460 | .show = bpq_seq_show, | ||
461 | }; | ||
462 | |||
463 | static int bpq_info_open(struct inode *inode, struct file *file) | ||
464 | { | ||
465 | return seq_open(file, &bpq_seqops); | ||
466 | } | ||
467 | |||
468 | static struct file_operations bpq_info_fops = { | ||
469 | .owner = THIS_MODULE, | ||
470 | .open = bpq_info_open, | ||
471 | .read = seq_read, | ||
472 | .llseek = seq_lseek, | ||
473 | .release = seq_release, | ||
474 | }; | ||
475 | |||
476 | |||
477 | /* ------------------------------------------------------------------------ */ | ||
478 | |||
479 | |||
480 | static void bpq_setup(struct net_device *dev) | ||
481 | { | ||
482 | |||
483 | dev->hard_start_xmit = bpq_xmit; | ||
484 | dev->open = bpq_open; | ||
485 | dev->stop = bpq_close; | ||
486 | dev->set_mac_address = bpq_set_mac_address; | ||
487 | dev->get_stats = bpq_get_stats; | ||
488 | dev->do_ioctl = bpq_ioctl; | ||
489 | dev->destructor = free_netdev; | ||
490 | |||
491 | memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); | ||
492 | memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); | ||
493 | |||
494 | dev->flags = 0; | ||
495 | |||
496 | #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) | ||
497 | dev->hard_header = ax25_encapsulate; | ||
498 | dev->rebuild_header = ax25_rebuild_header; | ||
499 | #endif | ||
500 | |||
501 | dev->type = ARPHRD_AX25; | ||
502 | dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; | ||
503 | dev->mtu = AX25_DEF_PACLEN; | ||
504 | dev->addr_len = AX25_ADDR_LEN; | ||
505 | |||
506 | } | ||
507 | |||
508 | /* | ||
509 | * Setup a new device. | ||
510 | */ | ||
511 | static int bpq_new_device(struct net_device *edev) | ||
512 | { | ||
513 | int err; | ||
514 | struct net_device *ndev; | ||
515 | struct bpqdev *bpq; | ||
516 | |||
517 | ndev = alloc_netdev(sizeof(struct bpqdev), "bpq%d", | ||
518 | bpq_setup); | ||
519 | if (!ndev) | ||
520 | return -ENOMEM; | ||
521 | |||
522 | |||
523 | bpq = netdev_priv(ndev); | ||
524 | dev_hold(edev); | ||
525 | bpq->ethdev = edev; | ||
526 | bpq->axdev = ndev; | ||
527 | |||
528 | memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); | ||
529 | memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); | ||
530 | |||
531 | err = dev_alloc_name(ndev, ndev->name); | ||
532 | if (err < 0) | ||
533 | goto error; | ||
534 | |||
535 | err = register_netdevice(ndev); | ||
536 | if (err) | ||
537 | goto error; | ||
538 | |||
539 | /* List protected by RTNL */ | ||
540 | list_add_rcu(&bpq->bpq_list, &bpq_devices); | ||
541 | return 0; | ||
542 | |||
543 | error: | ||
544 | dev_put(edev); | ||
545 | free_netdev(ndev); | ||
546 | return err; | ||
547 | |||
548 | } | ||
549 | |||
550 | static void bpq_free_device(struct net_device *ndev) | ||
551 | { | ||
552 | struct bpqdev *bpq = netdev_priv(ndev); | ||
553 | |||
554 | dev_put(bpq->ethdev); | ||
555 | list_del_rcu(&bpq->bpq_list); | ||
556 | |||
557 | unregister_netdevice(ndev); | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * Handle device status changes. | ||
562 | */ | ||
563 | static int bpq_device_event(struct notifier_block *this,unsigned long event, void *ptr) | ||
564 | { | ||
565 | struct net_device *dev = (struct net_device *)ptr; | ||
566 | |||
567 | if (!dev_is_ethdev(dev)) | ||
568 | return NOTIFY_DONE; | ||
569 | |||
570 | rcu_read_lock(); | ||
571 | |||
572 | switch (event) { | ||
573 | case NETDEV_UP: /* new ethernet device -> new BPQ interface */ | ||
574 | if (bpq_get_ax25_dev(dev) == NULL) | ||
575 | bpq_new_device(dev); | ||
576 | break; | ||
577 | |||
578 | case NETDEV_DOWN: /* ethernet device closed -> close BPQ interface */ | ||
579 | if ((dev = bpq_get_ax25_dev(dev)) != NULL) | ||
580 | dev_close(dev); | ||
581 | break; | ||
582 | |||
583 | case NETDEV_UNREGISTER: /* ethernet device removed -> free BPQ interface */ | ||
584 | if ((dev = bpq_get_ax25_dev(dev)) != NULL) | ||
585 | bpq_free_device(dev); | ||
586 | break; | ||
587 | default: | ||
588 | break; | ||
589 | } | ||
590 | rcu_read_unlock(); | ||
591 | |||
592 | return NOTIFY_DONE; | ||
593 | } | ||
594 | |||
595 | |||
596 | /* ------------------------------------------------------------------------ */ | ||
597 | |||
598 | /* | ||
599 | * Initialize driver. To be called from af_ax25 if not compiled as a | ||
600 | * module | ||
601 | */ | ||
602 | static int __init bpq_init_driver(void) | ||
603 | { | ||
604 | #ifdef CONFIG_PROC_FS | ||
605 | if (!proc_net_fops_create("bpqether", S_IRUGO, &bpq_info_fops)) { | ||
606 | printk(KERN_ERR | ||
607 | "bpq: cannot create /proc/net/bpqether entry.\n"); | ||
608 | return -ENOENT; | ||
609 | } | ||
610 | #endif /* CONFIG_PROC_FS */ | ||
611 | |||
612 | dev_add_pack(&bpq_packet_type); | ||
613 | |||
614 | register_netdevice_notifier(&bpq_dev_notifier); | ||
615 | |||
616 | printk(banner); | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static void __exit bpq_cleanup_driver(void) | ||
622 | { | ||
623 | struct bpqdev *bpq; | ||
624 | |||
625 | dev_remove_pack(&bpq_packet_type); | ||
626 | |||
627 | unregister_netdevice_notifier(&bpq_dev_notifier); | ||
628 | |||
629 | proc_net_remove("bpqether"); | ||
630 | |||
631 | rtnl_lock(); | ||
632 | while (!list_empty(&bpq_devices)) { | ||
633 | bpq = list_entry(bpq_devices.next, struct bpqdev, bpq_list); | ||
634 | bpq_free_device(bpq->axdev); | ||
635 | } | ||
636 | rtnl_unlock(); | ||
637 | } | ||
638 | |||
639 | MODULE_AUTHOR("Joerg Reuter DL1BKE <jreuter@yaina.de>"); | ||
640 | MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); | ||
641 | MODULE_LICENSE("GPL"); | ||
642 | module_init(bpq_init_driver); | ||
643 | module_exit(bpq_cleanup_driver); | ||
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c new file mode 100644 index 000000000000..f3269b70a8c5 --- /dev/null +++ b/drivers/net/hamradio/dmascc.c | |||
@@ -0,0 +1,1493 @@ | |||
1 | /* | ||
2 | * Driver for high-speed SCC boards (those with DMA support) | ||
3 | * Copyright (C) 1997-2000 Klaus Kudielka | ||
4 | * | ||
5 | * S5SCC/DMA support by Janko Koleznik S52HI | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/if_arp.h> | ||
27 | #include <linux/in.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/netdevice.h> | ||
34 | #include <linux/rtnetlink.h> | ||
35 | #include <linux/sockios.h> | ||
36 | #include <linux/workqueue.h> | ||
37 | #include <asm/atomic.h> | ||
38 | #include <asm/bitops.h> | ||
39 | #include <asm/dma.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/irq.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <net/ax25.h> | ||
44 | #include "z8530.h" | ||
45 | |||
46 | |||
47 | /* Number of buffers per channel */ | ||
48 | |||
49 | #define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (min. 2 recommended) */ | ||
50 | #define NUM_RX_BUF 6 /* NUM_RX_BUF >= 1 (min. 2 recommended) */ | ||
51 | #define BUF_SIZE 1576 /* BUF_SIZE >= mtu + hard_header_len */ | ||
52 | |||
53 | |||
54 | /* Cards supported */ | ||
55 | |||
56 | #define HW_PI { "Ottawa PI", 0x300, 0x20, 0x10, 8, \ | ||
57 | 0, 8, 1843200, 3686400 } | ||
58 | #define HW_PI2 { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \ | ||
59 | 0, 8, 3686400, 7372800 } | ||
60 | #define HW_TWIN { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \ | ||
61 | 0, 4, 6144000, 6144000 } | ||
62 | #define HW_S5 { "S5SCC/DMA", 0x200, 0x10, 0x10, 32, \ | ||
63 | 0, 8, 4915200, 9830400 } | ||
64 | |||
65 | #define HARDWARE { HW_PI, HW_PI2, HW_TWIN, HW_S5 } | ||
66 | |||
67 | #define TMR_0_HZ 25600 /* Frequency of timer 0 */ | ||
68 | |||
69 | #define TYPE_PI 0 | ||
70 | #define TYPE_PI2 1 | ||
71 | #define TYPE_TWIN 2 | ||
72 | #define TYPE_S5 3 | ||
73 | #define NUM_TYPES 4 | ||
74 | |||
75 | #define MAX_NUM_DEVS 32 | ||
76 | |||
77 | |||
78 | /* SCC chips supported */ | ||
79 | |||
80 | #define Z8530 0 | ||
81 | #define Z85C30 1 | ||
82 | #define Z85230 2 | ||
83 | |||
84 | #define CHIPNAMES { "Z8530", "Z85C30", "Z85230" } | ||
85 | |||
86 | |||
87 | /* I/O registers */ | ||
88 | |||
89 | /* 8530 registers relative to card base */ | ||
90 | #define SCCB_CMD 0x00 | ||
91 | #define SCCB_DATA 0x01 | ||
92 | #define SCCA_CMD 0x02 | ||
93 | #define SCCA_DATA 0x03 | ||
94 | |||
95 | /* 8253/8254 registers relative to card base */ | ||
96 | #define TMR_CNT0 0x00 | ||
97 | #define TMR_CNT1 0x01 | ||
98 | #define TMR_CNT2 0x02 | ||
99 | #define TMR_CTRL 0x03 | ||
100 | |||
101 | /* Additional PI/PI2 registers relative to card base */ | ||
102 | #define PI_DREQ_MASK 0x04 | ||
103 | |||
104 | /* Additional PackeTwin registers relative to card base */ | ||
105 | #define TWIN_INT_REG 0x08 | ||
106 | #define TWIN_CLR_TMR1 0x09 | ||
107 | #define TWIN_CLR_TMR2 0x0a | ||
108 | #define TWIN_SPARE_1 0x0b | ||
109 | #define TWIN_DMA_CFG 0x08 | ||
110 | #define TWIN_SERIAL_CFG 0x09 | ||
111 | #define TWIN_DMA_CLR_FF 0x0a | ||
112 | #define TWIN_SPARE_2 0x0b | ||
113 | |||
114 | |||
115 | /* PackeTwin I/O register values */ | ||
116 | |||
117 | /* INT_REG */ | ||
118 | #define TWIN_SCC_MSK 0x01 | ||
119 | #define TWIN_TMR1_MSK 0x02 | ||
120 | #define TWIN_TMR2_MSK 0x04 | ||
121 | #define TWIN_INT_MSK 0x07 | ||
122 | |||
123 | /* SERIAL_CFG */ | ||
124 | #define TWIN_DTRA_ON 0x01 | ||
125 | #define TWIN_DTRB_ON 0x02 | ||
126 | #define TWIN_EXTCLKA 0x04 | ||
127 | #define TWIN_EXTCLKB 0x08 | ||
128 | #define TWIN_LOOPA_ON 0x10 | ||
129 | #define TWIN_LOOPB_ON 0x20 | ||
130 | #define TWIN_EI 0x80 | ||
131 | |||
132 | /* DMA_CFG */ | ||
133 | #define TWIN_DMA_HDX_T1 0x08 | ||
134 | #define TWIN_DMA_HDX_R1 0x0a | ||
135 | #define TWIN_DMA_HDX_T3 0x14 | ||
136 | #define TWIN_DMA_HDX_R3 0x16 | ||
137 | #define TWIN_DMA_FDX_T3R1 0x1b | ||
138 | #define TWIN_DMA_FDX_T1R3 0x1d | ||
139 | |||
140 | |||
141 | /* Status values */ | ||
142 | |||
143 | #define IDLE 0 | ||
144 | #define TX_HEAD 1 | ||
145 | #define TX_DATA 2 | ||
146 | #define TX_PAUSE 3 | ||
147 | #define TX_TAIL 4 | ||
148 | #define RTS_OFF 5 | ||
149 | #define WAIT 6 | ||
150 | #define DCD_ON 7 | ||
151 | #define RX_ON 8 | ||
152 | #define DCD_OFF 9 | ||
153 | |||
154 | |||
155 | /* Ioctls */ | ||
156 | |||
157 | #define SIOCGSCCPARAM SIOCDEVPRIVATE | ||
158 | #define SIOCSSCCPARAM (SIOCDEVPRIVATE+1) | ||
159 | |||
160 | |||
161 | /* Data types */ | ||
162 | |||
163 | struct scc_param { | ||
164 | int pclk_hz; /* frequency of BRG input (don't change) */ | ||
165 | int brg_tc; /* BRG terminal count; BRG disabled if < 0 */ | ||
166 | int nrzi; /* 0 (nrz), 1 (nrzi) */ | ||
167 | int clocks; /* see dmascc_cfg documentation */ | ||
168 | int txdelay; /* [1/TMR_0_HZ] */ | ||
169 | int txtimeout; /* [1/HZ] */ | ||
170 | int txtail; /* [1/TMR_0_HZ] */ | ||
171 | int waittime; /* [1/TMR_0_HZ] */ | ||
172 | int slottime; /* [1/TMR_0_HZ] */ | ||
173 | int persist; /* 1 ... 256 */ | ||
174 | int dma; /* -1 (disable), 0, 1, 3 */ | ||
175 | int txpause; /* [1/TMR_0_HZ] */ | ||
176 | int rtsoff; /* [1/TMR_0_HZ] */ | ||
177 | int dcdon; /* [1/TMR_0_HZ] */ | ||
178 | int dcdoff; /* [1/TMR_0_HZ] */ | ||
179 | }; | ||
180 | |||
181 | struct scc_hardware { | ||
182 | char *name; | ||
183 | int io_region; | ||
184 | int io_delta; | ||
185 | int io_size; | ||
186 | int num_devs; | ||
187 | int scc_offset; | ||
188 | int tmr_offset; | ||
189 | int tmr_hz; | ||
190 | int pclk_hz; | ||
191 | }; | ||
192 | |||
193 | struct scc_priv { | ||
194 | int type; | ||
195 | int chip; | ||
196 | struct net_device *dev; | ||
197 | struct scc_info *info; | ||
198 | struct net_device_stats stats; | ||
199 | int channel; | ||
200 | int card_base, scc_cmd, scc_data; | ||
201 | int tmr_cnt, tmr_ctrl, tmr_mode; | ||
202 | struct scc_param param; | ||
203 | char rx_buf[NUM_RX_BUF][BUF_SIZE]; | ||
204 | int rx_len[NUM_RX_BUF]; | ||
205 | int rx_ptr; | ||
206 | struct work_struct rx_work; | ||
207 | int rx_head, rx_tail, rx_count; | ||
208 | int rx_over; | ||
209 | char tx_buf[NUM_TX_BUF][BUF_SIZE]; | ||
210 | int tx_len[NUM_TX_BUF]; | ||
211 | int tx_ptr; | ||
212 | int tx_head, tx_tail, tx_count; | ||
213 | int state; | ||
214 | unsigned long tx_start; | ||
215 | int rr0; | ||
216 | spinlock_t *register_lock; /* Per scc_info */ | ||
217 | spinlock_t ring_lock; | ||
218 | }; | ||
219 | |||
220 | struct scc_info { | ||
221 | int irq_used; | ||
222 | int twin_serial_cfg; | ||
223 | struct net_device *dev[2]; | ||
224 | struct scc_priv priv[2]; | ||
225 | struct scc_info *next; | ||
226 | spinlock_t register_lock; /* Per device register lock */ | ||
227 | }; | ||
228 | |||
229 | |||
230 | /* Function declarations */ | ||
231 | static int setup_adapter(int card_base, int type, int n) __init; | ||
232 | |||
233 | static void write_scc(struct scc_priv *priv, int reg, int val); | ||
234 | static void write_scc_data(struct scc_priv *priv, int val, int fast); | ||
235 | static int read_scc(struct scc_priv *priv, int reg); | ||
236 | static int read_scc_data(struct scc_priv *priv); | ||
237 | |||
238 | static int scc_open(struct net_device *dev); | ||
239 | static int scc_close(struct net_device *dev); | ||
240 | static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | ||
241 | static int scc_send_packet(struct sk_buff *skb, struct net_device *dev); | ||
242 | static struct net_device_stats *scc_get_stats(struct net_device *dev); | ||
243 | static int scc_set_mac_address(struct net_device *dev, void *sa); | ||
244 | |||
245 | static inline void tx_on(struct scc_priv *priv); | ||
246 | static inline void rx_on(struct scc_priv *priv); | ||
247 | static inline void rx_off(struct scc_priv *priv); | ||
248 | static void start_timer(struct scc_priv *priv, int t, int r15); | ||
249 | static inline unsigned char random(void); | ||
250 | |||
251 | static inline void z8530_isr(struct scc_info *info); | ||
252 | static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); | ||
253 | static void rx_isr(struct scc_priv *priv); | ||
254 | static void special_condition(struct scc_priv *priv, int rc); | ||
255 | static void rx_bh(void *arg); | ||
256 | static void tx_isr(struct scc_priv *priv); | ||
257 | static void es_isr(struct scc_priv *priv); | ||
258 | static void tm_isr(struct scc_priv *priv); | ||
259 | |||
260 | |||
261 | /* Initialization variables */ | ||
262 | |||
263 | static int io[MAX_NUM_DEVS] __initdata = { 0, }; | ||
264 | |||
265 | /* Beware! hw[] is also used in cleanup_module(). */ | ||
266 | static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE; | ||
267 | static char ax25_broadcast[7] __initdata = | ||
268 | { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, | ||
269 | '0' << 1 }; | ||
270 | static char ax25_test[7] __initdata = | ||
271 | { 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, | ||
272 | '1' << 1 }; | ||
273 | |||
274 | |||
275 | /* Global variables */ | ||
276 | |||
277 | static struct scc_info *first; | ||
278 | static unsigned long rand; | ||
279 | |||
280 | |||
281 | MODULE_AUTHOR("Klaus Kudielka"); | ||
282 | MODULE_DESCRIPTION("Driver for high-speed SCC boards"); | ||
283 | MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); | ||
284 | MODULE_LICENSE("GPL"); | ||
285 | |||
286 | static void __exit dmascc_exit(void) | ||
287 | { | ||
288 | int i; | ||
289 | struct scc_info *info; | ||
290 | |||
291 | while (first) { | ||
292 | info = first; | ||
293 | |||
294 | /* Unregister devices */ | ||
295 | for (i = 0; i < 2; i++) | ||
296 | unregister_netdev(info->dev[i]); | ||
297 | |||
298 | /* Reset board */ | ||
299 | if (info->priv[0].type == TYPE_TWIN) | ||
300 | outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); | ||
301 | write_scc(&info->priv[0], R9, FHWRES); | ||
302 | release_region(info->dev[0]->base_addr, | ||
303 | hw[info->priv[0].type].io_size); | ||
304 | |||
305 | for (i = 0; i < 2; i++) | ||
306 | free_netdev(info->dev[i]); | ||
307 | |||
308 | /* Free memory */ | ||
309 | first = info->next; | ||
310 | kfree(info); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | #ifndef MODULE | ||
315 | void __init dmascc_setup(char *str, int *ints) | ||
316 | { | ||
317 | int i; | ||
318 | |||
319 | for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) | ||
320 | io[i] = ints[i + 1]; | ||
321 | } | ||
322 | #endif | ||
323 | |||
324 | static int __init dmascc_init(void) | ||
325 | { | ||
326 | int h, i, j, n; | ||
327 | int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], | ||
328 | t1[MAX_NUM_DEVS]; | ||
329 | unsigned t_val; | ||
330 | unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS], | ||
331 | counting[MAX_NUM_DEVS]; | ||
332 | |||
333 | /* Initialize random number generator */ | ||
334 | rand = jiffies; | ||
335 | /* Cards found = 0 */ | ||
336 | n = 0; | ||
337 | /* Warning message */ | ||
338 | if (!io[0]) | ||
339 | printk(KERN_INFO "dmascc: autoprobing (dangerous)\n"); | ||
340 | |||
341 | /* Run autodetection for each card type */ | ||
342 | for (h = 0; h < NUM_TYPES; h++) { | ||
343 | |||
344 | if (io[0]) { | ||
345 | /* User-specified I/O address regions */ | ||
346 | for (i = 0; i < hw[h].num_devs; i++) | ||
347 | base[i] = 0; | ||
348 | for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) { | ||
349 | j = (io[i] - | ||
350 | hw[h].io_region) / hw[h].io_delta; | ||
351 | if (j >= 0 && j < hw[h].num_devs | ||
352 | && hw[h].io_region + | ||
353 | j * hw[h].io_delta == io[i]) { | ||
354 | base[j] = io[i]; | ||
355 | } | ||
356 | } | ||
357 | } else { | ||
358 | /* Default I/O address regions */ | ||
359 | for (i = 0; i < hw[h].num_devs; i++) { | ||
360 | base[i] = | ||
361 | hw[h].io_region + i * hw[h].io_delta; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | /* Check valid I/O address regions */ | ||
366 | for (i = 0; i < hw[h].num_devs; i++) | ||
367 | if (base[i]) { | ||
368 | if (!request_region | ||
369 | (base[i], hw[h].io_size, "dmascc")) | ||
370 | base[i] = 0; | ||
371 | else { | ||
372 | tcmd[i] = | ||
373 | base[i] + hw[h].tmr_offset + | ||
374 | TMR_CTRL; | ||
375 | t0[i] = | ||
376 | base[i] + hw[h].tmr_offset + | ||
377 | TMR_CNT0; | ||
378 | t1[i] = | ||
379 | base[i] + hw[h].tmr_offset + | ||
380 | TMR_CNT1; | ||
381 | } | ||
382 | } | ||
383 | |||
384 | /* Start timers */ | ||
385 | for (i = 0; i < hw[h].num_devs; i++) | ||
386 | if (base[i]) { | ||
387 | /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */ | ||
388 | outb(0x36, tcmd[i]); | ||
389 | outb((hw[h].tmr_hz / TMR_0_HZ) & 0xFF, | ||
390 | t0[i]); | ||
391 | outb((hw[h].tmr_hz / TMR_0_HZ) >> 8, | ||
392 | t0[i]); | ||
393 | /* Timer 1: LSB+MSB, Mode 0, HZ/10 */ | ||
394 | outb(0x70, tcmd[i]); | ||
395 | outb((TMR_0_HZ / HZ * 10) & 0xFF, t1[i]); | ||
396 | outb((TMR_0_HZ / HZ * 10) >> 8, t1[i]); | ||
397 | start[i] = jiffies; | ||
398 | delay[i] = 0; | ||
399 | counting[i] = 1; | ||
400 | /* Timer 2: LSB+MSB, Mode 0 */ | ||
401 | outb(0xb0, tcmd[i]); | ||
402 | } | ||
403 | time = jiffies; | ||
404 | /* Wait until counter registers are loaded */ | ||
405 | udelay(2000000 / TMR_0_HZ); | ||
406 | |||
407 | /* Timing loop */ | ||
408 | while (jiffies - time < 13) { | ||
409 | for (i = 0; i < hw[h].num_devs; i++) | ||
410 | if (base[i] && counting[i]) { | ||
411 | /* Read back Timer 1: latch; read LSB; read MSB */ | ||
412 | outb(0x40, tcmd[i]); | ||
413 | t_val = | ||
414 | inb(t1[i]) + (inb(t1[i]) << 8); | ||
415 | /* Also check whether counter did wrap */ | ||
416 | if (t_val == 0 | ||
417 | || t_val > TMR_0_HZ / HZ * 10) | ||
418 | counting[i] = 0; | ||
419 | delay[i] = jiffies - start[i]; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* Evaluate measurements */ | ||
424 | for (i = 0; i < hw[h].num_devs; i++) | ||
425 | if (base[i]) { | ||
426 | if ((delay[i] >= 9 && delay[i] <= 11) && | ||
427 | /* Ok, we have found an adapter */ | ||
428 | (setup_adapter(base[i], h, n) == 0)) | ||
429 | n++; | ||
430 | else | ||
431 | release_region(base[i], | ||
432 | hw[h].io_size); | ||
433 | } | ||
434 | |||
435 | } /* NUM_TYPES */ | ||
436 | |||
437 | /* If any adapter was successfully initialized, return ok */ | ||
438 | if (n) | ||
439 | return 0; | ||
440 | |||
441 | /* If no adapter found, return error */ | ||
442 | printk(KERN_INFO "dmascc: no adapters found\n"); | ||
443 | return -EIO; | ||
444 | } | ||
445 | |||
446 | module_init(dmascc_init); | ||
447 | module_exit(dmascc_exit); | ||
448 | |||
449 | static void dev_setup(struct net_device *dev) | ||
450 | { | ||
451 | dev->type = ARPHRD_AX25; | ||
452 | dev->hard_header_len = 73; | ||
453 | dev->mtu = 1500; | ||
454 | dev->addr_len = 7; | ||
455 | dev->tx_queue_len = 64; | ||
456 | memcpy(dev->broadcast, ax25_broadcast, 7); | ||
457 | memcpy(dev->dev_addr, ax25_test, 7); | ||
458 | } | ||
459 | |||
460 | static int __init setup_adapter(int card_base, int type, int n) | ||
461 | { | ||
462 | int i, irq, chip; | ||
463 | struct scc_info *info; | ||
464 | struct net_device *dev; | ||
465 | struct scc_priv *priv; | ||
466 | unsigned long time; | ||
467 | unsigned int irqs; | ||
468 | int tmr_base = card_base + hw[type].tmr_offset; | ||
469 | int scc_base = card_base + hw[type].scc_offset; | ||
470 | char *chipnames[] = CHIPNAMES; | ||
471 | |||
472 | /* Allocate memory */ | ||
473 | info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); | ||
474 | if (!info) { | ||
475 | printk(KERN_ERR "dmascc: " | ||
476 | "could not allocate memory for %s at %#3x\n", | ||
477 | hw[type].name, card_base); | ||
478 | goto out; | ||
479 | } | ||
480 | |||
481 | /* Initialize what is necessary for write_scc and write_scc_data */ | ||
482 | memset(info, 0, sizeof(struct scc_info)); | ||
483 | |||
484 | info->dev[0] = alloc_netdev(0, "", dev_setup); | ||
485 | if (!info->dev[0]) { | ||
486 | printk(KERN_ERR "dmascc: " | ||
487 | "could not allocate memory for %s at %#3x\n", | ||
488 | hw[type].name, card_base); | ||
489 | goto out1; | ||
490 | } | ||
491 | |||
492 | info->dev[1] = alloc_netdev(0, "", dev_setup); | ||
493 | if (!info->dev[1]) { | ||
494 | printk(KERN_ERR "dmascc: " | ||
495 | "could not allocate memory for %s at %#3x\n", | ||
496 | hw[type].name, card_base); | ||
497 | goto out2; | ||
498 | } | ||
499 | spin_lock_init(&info->register_lock); | ||
500 | |||
501 | priv = &info->priv[0]; | ||
502 | priv->type = type; | ||
503 | priv->card_base = card_base; | ||
504 | priv->scc_cmd = scc_base + SCCA_CMD; | ||
505 | priv->scc_data = scc_base + SCCA_DATA; | ||
506 | priv->register_lock = &info->register_lock; | ||
507 | |||
508 | /* Reset SCC */ | ||
509 | write_scc(priv, R9, FHWRES | MIE | NV); | ||
510 | |||
511 | /* Determine type of chip by enabling SDLC/HDLC enhancements */ | ||
512 | write_scc(priv, R15, SHDLCE); | ||
513 | if (!read_scc(priv, R15)) { | ||
514 | /* WR7' not present. This is an ordinary Z8530 SCC. */ | ||
515 | chip = Z8530; | ||
516 | } else { | ||
517 | /* Put one character in TX FIFO */ | ||
518 | write_scc_data(priv, 0, 0); | ||
519 | if (read_scc(priv, R0) & Tx_BUF_EMP) { | ||
520 | /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ | ||
521 | chip = Z85230; | ||
522 | } else { | ||
523 | /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ | ||
524 | chip = Z85C30; | ||
525 | } | ||
526 | } | ||
527 | write_scc(priv, R15, 0); | ||
528 | |||
529 | /* Start IRQ auto-detection */ | ||
530 | irqs = probe_irq_on(); | ||
531 | |||
532 | /* Enable interrupts */ | ||
533 | if (type == TYPE_TWIN) { | ||
534 | outb(0, card_base + TWIN_DMA_CFG); | ||
535 | inb(card_base + TWIN_CLR_TMR1); | ||
536 | inb(card_base + TWIN_CLR_TMR2); | ||
537 | info->twin_serial_cfg = TWIN_EI; | ||
538 | outb(info->twin_serial_cfg, card_base + TWIN_SERIAL_CFG); | ||
539 | } else { | ||
540 | write_scc(priv, R15, CTSIE); | ||
541 | write_scc(priv, R0, RES_EXT_INT); | ||
542 | write_scc(priv, R1, EXT_INT_ENAB); | ||
543 | } | ||
544 | |||
545 | /* Start timer */ | ||
546 | outb(1, tmr_base + TMR_CNT1); | ||
547 | outb(0, tmr_base + TMR_CNT1); | ||
548 | |||
549 | /* Wait and detect IRQ */ | ||
550 | time = jiffies; | ||
551 | while (jiffies - time < 2 + HZ / TMR_0_HZ); | ||
552 | irq = probe_irq_off(irqs); | ||
553 | |||
554 | /* Clear pending interrupt, disable interrupts */ | ||
555 | if (type == TYPE_TWIN) { | ||
556 | inb(card_base + TWIN_CLR_TMR1); | ||
557 | } else { | ||
558 | write_scc(priv, R1, 0); | ||
559 | write_scc(priv, R15, 0); | ||
560 | write_scc(priv, R0, RES_EXT_INT); | ||
561 | } | ||
562 | |||
563 | if (irq <= 0) { | ||
564 | printk(KERN_ERR | ||
565 | "dmascc: could not find irq of %s at %#3x (irq=%d)\n", | ||
566 | hw[type].name, card_base, irq); | ||
567 | goto out3; | ||
568 | } | ||
569 | |||
570 | /* Set up data structures */ | ||
571 | for (i = 0; i < 2; i++) { | ||
572 | dev = info->dev[i]; | ||
573 | priv = &info->priv[i]; | ||
574 | priv->type = type; | ||
575 | priv->chip = chip; | ||
576 | priv->dev = dev; | ||
577 | priv->info = info; | ||
578 | priv->channel = i; | ||
579 | spin_lock_init(&priv->ring_lock); | ||
580 | priv->register_lock = &info->register_lock; | ||
581 | priv->card_base = card_base; | ||
582 | priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); | ||
583 | priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); | ||
584 | priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); | ||
585 | priv->tmr_ctrl = tmr_base + TMR_CTRL; | ||
586 | priv->tmr_mode = i ? 0xb0 : 0x70; | ||
587 | priv->param.pclk_hz = hw[type].pclk_hz; | ||
588 | priv->param.brg_tc = -1; | ||
589 | priv->param.clocks = TCTRxCP | RCRTxCP; | ||
590 | priv->param.persist = 256; | ||
591 | priv->param.dma = -1; | ||
592 | INIT_WORK(&priv->rx_work, rx_bh, priv); | ||
593 | dev->priv = priv; | ||
594 | sprintf(dev->name, "dmascc%i", 2 * n + i); | ||
595 | SET_MODULE_OWNER(dev); | ||
596 | dev->base_addr = card_base; | ||
597 | dev->irq = irq; | ||
598 | dev->open = scc_open; | ||
599 | dev->stop = scc_close; | ||
600 | dev->do_ioctl = scc_ioctl; | ||
601 | dev->hard_start_xmit = scc_send_packet; | ||
602 | dev->get_stats = scc_get_stats; | ||
603 | dev->hard_header = ax25_encapsulate; | ||
604 | dev->rebuild_header = ax25_rebuild_header; | ||
605 | dev->set_mac_address = scc_set_mac_address; | ||
606 | } | ||
607 | if (register_netdev(info->dev[0])) { | ||
608 | printk(KERN_ERR "dmascc: could not register %s\n", | ||
609 | info->dev[0]->name); | ||
610 | goto out3; | ||
611 | } | ||
612 | if (register_netdev(info->dev[1])) { | ||
613 | printk(KERN_ERR "dmascc: could not register %s\n", | ||
614 | info->dev[1]->name); | ||
615 | goto out4; | ||
616 | } | ||
617 | |||
618 | |||
619 | info->next = first; | ||
620 | first = info; | ||
621 | printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", | ||
622 | hw[type].name, chipnames[chip], card_base, irq); | ||
623 | return 0; | ||
624 | |||
625 | out4: | ||
626 | unregister_netdev(info->dev[0]); | ||
627 | out3: | ||
628 | if (info->priv[0].type == TYPE_TWIN) | ||
629 | outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); | ||
630 | write_scc(&info->priv[0], R9, FHWRES); | ||
631 | free_netdev(info->dev[1]); | ||
632 | out2: | ||
633 | free_netdev(info->dev[0]); | ||
634 | out1: | ||
635 | kfree(info); | ||
636 | out: | ||
637 | return -1; | ||
638 | } | ||
639 | |||
640 | |||
641 | /* Driver functions */ | ||
642 | |||
643 | static void write_scc(struct scc_priv *priv, int reg, int val) | ||
644 | { | ||
645 | unsigned long flags; | ||
646 | switch (priv->type) { | ||
647 | case TYPE_S5: | ||
648 | if (reg) | ||
649 | outb(reg, priv->scc_cmd); | ||
650 | outb(val, priv->scc_cmd); | ||
651 | return; | ||
652 | case TYPE_TWIN: | ||
653 | if (reg) | ||
654 | outb_p(reg, priv->scc_cmd); | ||
655 | outb_p(val, priv->scc_cmd); | ||
656 | return; | ||
657 | default: | ||
658 | spin_lock_irqsave(priv->register_lock, flags); | ||
659 | outb_p(0, priv->card_base + PI_DREQ_MASK); | ||
660 | if (reg) | ||
661 | outb_p(reg, priv->scc_cmd); | ||
662 | outb_p(val, priv->scc_cmd); | ||
663 | outb(1, priv->card_base + PI_DREQ_MASK); | ||
664 | spin_unlock_irqrestore(priv->register_lock, flags); | ||
665 | return; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | |||
670 | static void write_scc_data(struct scc_priv *priv, int val, int fast) | ||
671 | { | ||
672 | unsigned long flags; | ||
673 | switch (priv->type) { | ||
674 | case TYPE_S5: | ||
675 | outb(val, priv->scc_data); | ||
676 | return; | ||
677 | case TYPE_TWIN: | ||
678 | outb_p(val, priv->scc_data); | ||
679 | return; | ||
680 | default: | ||
681 | if (fast) | ||
682 | outb_p(val, priv->scc_data); | ||
683 | else { | ||
684 | spin_lock_irqsave(priv->register_lock, flags); | ||
685 | outb_p(0, priv->card_base + PI_DREQ_MASK); | ||
686 | outb_p(val, priv->scc_data); | ||
687 | outb(1, priv->card_base + PI_DREQ_MASK); | ||
688 | spin_unlock_irqrestore(priv->register_lock, flags); | ||
689 | } | ||
690 | return; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | |||
695 | static int read_scc(struct scc_priv *priv, int reg) | ||
696 | { | ||
697 | int rc; | ||
698 | unsigned long flags; | ||
699 | switch (priv->type) { | ||
700 | case TYPE_S5: | ||
701 | if (reg) | ||
702 | outb(reg, priv->scc_cmd); | ||
703 | return inb(priv->scc_cmd); | ||
704 | case TYPE_TWIN: | ||
705 | if (reg) | ||
706 | outb_p(reg, priv->scc_cmd); | ||
707 | return inb_p(priv->scc_cmd); | ||
708 | default: | ||
709 | spin_lock_irqsave(priv->register_lock, flags); | ||
710 | outb_p(0, priv->card_base + PI_DREQ_MASK); | ||
711 | if (reg) | ||
712 | outb_p(reg, priv->scc_cmd); | ||
713 | rc = inb_p(priv->scc_cmd); | ||
714 | outb(1, priv->card_base + PI_DREQ_MASK); | ||
715 | spin_unlock_irqrestore(priv->register_lock, flags); | ||
716 | return rc; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | |||
721 | static int read_scc_data(struct scc_priv *priv) | ||
722 | { | ||
723 | int rc; | ||
724 | unsigned long flags; | ||
725 | switch (priv->type) { | ||
726 | case TYPE_S5: | ||
727 | return inb(priv->scc_data); | ||
728 | case TYPE_TWIN: | ||
729 | return inb_p(priv->scc_data); | ||
730 | default: | ||
731 | spin_lock_irqsave(priv->register_lock, flags); | ||
732 | outb_p(0, priv->card_base + PI_DREQ_MASK); | ||
733 | rc = inb_p(priv->scc_data); | ||
734 | outb(1, priv->card_base + PI_DREQ_MASK); | ||
735 | spin_unlock_irqrestore(priv->register_lock, flags); | ||
736 | return rc; | ||
737 | } | ||
738 | } | ||
739 | |||
740 | |||
741 | static int scc_open(struct net_device *dev) | ||
742 | { | ||
743 | struct scc_priv *priv = dev->priv; | ||
744 | struct scc_info *info = priv->info; | ||
745 | int card_base = priv->card_base; | ||
746 | |||
747 | /* Request IRQ if not already used by other channel */ | ||
748 | if (!info->irq_used) { | ||
749 | if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) { | ||
750 | return -EAGAIN; | ||
751 | } | ||
752 | } | ||
753 | info->irq_used++; | ||
754 | |||
755 | /* Request DMA if required */ | ||
756 | if (priv->param.dma >= 0) { | ||
757 | if (request_dma(priv->param.dma, "dmascc")) { | ||
758 | if (--info->irq_used == 0) | ||
759 | free_irq(dev->irq, info); | ||
760 | return -EAGAIN; | ||
761 | } else { | ||
762 | unsigned long flags = claim_dma_lock(); | ||
763 | clear_dma_ff(priv->param.dma); | ||
764 | release_dma_lock(flags); | ||
765 | } | ||
766 | } | ||
767 | |||
768 | /* Initialize local variables */ | ||
769 | priv->rx_ptr = 0; | ||
770 | priv->rx_over = 0; | ||
771 | priv->rx_head = priv->rx_tail = priv->rx_count = 0; | ||
772 | priv->state = IDLE; | ||
773 | priv->tx_head = priv->tx_tail = priv->tx_count = 0; | ||
774 | priv->tx_ptr = 0; | ||
775 | |||
776 | /* Reset channel */ | ||
777 | write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); | ||
778 | /* X1 clock, SDLC mode */ | ||
779 | write_scc(priv, R4, SDLC | X1CLK); | ||
780 | /* DMA */ | ||
781 | write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); | ||
782 | /* 8 bit RX char, RX disable */ | ||
783 | write_scc(priv, R3, Rx8); | ||
784 | /* 8 bit TX char, TX disable */ | ||
785 | write_scc(priv, R5, Tx8); | ||
786 | /* SDLC address field */ | ||
787 | write_scc(priv, R6, 0); | ||
788 | /* SDLC flag */ | ||
789 | write_scc(priv, R7, FLAG); | ||
790 | switch (priv->chip) { | ||
791 | case Z85C30: | ||
792 | /* Select WR7' */ | ||
793 | write_scc(priv, R15, SHDLCE); | ||
794 | /* Auto EOM reset */ | ||
795 | write_scc(priv, R7, AUTOEOM); | ||
796 | write_scc(priv, R15, 0); | ||
797 | break; | ||
798 | case Z85230: | ||
799 | /* Select WR7' */ | ||
800 | write_scc(priv, R15, SHDLCE); | ||
801 | /* The following bits are set (see 2.5.2.1): | ||
802 | - Automatic EOM reset | ||
803 | - Interrupt request if RX FIFO is half full | ||
804 | This bit should be ignored in DMA mode (according to the | ||
805 | documentation), but actually isn't. The receiver doesn't work if | ||
806 | it is set. Thus, we have to clear it in DMA mode. | ||
807 | - Interrupt/DMA request if TX FIFO is completely empty | ||
808 | a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30 | ||
809 | compatibility). | ||
810 | b) If cleared, DMA requests may follow each other very quickly, | ||
811 | filling up the TX FIFO. | ||
812 | Advantage: TX works even in case of high bus latency. | ||
813 | Disadvantage: Edge-triggered DMA request circuitry may miss | ||
814 | a request. No more data is delivered, resulting | ||
815 | in a TX FIFO underrun. | ||
816 | Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared. | ||
817 | The PackeTwin doesn't. I don't know about the PI, but let's | ||
818 | assume it behaves like the PI2. | ||
819 | */ | ||
820 | if (priv->param.dma >= 0) { | ||
821 | if (priv->type == TYPE_TWIN) | ||
822 | write_scc(priv, R7, AUTOEOM | TXFIFOE); | ||
823 | else | ||
824 | write_scc(priv, R7, AUTOEOM); | ||
825 | } else { | ||
826 | write_scc(priv, R7, AUTOEOM | RXFIFOH); | ||
827 | } | ||
828 | write_scc(priv, R15, 0); | ||
829 | break; | ||
830 | } | ||
831 | /* Preset CRC, NRZ(I) encoding */ | ||
832 | write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ)); | ||
833 | |||
834 | /* Configure baud rate generator */ | ||
835 | if (priv->param.brg_tc >= 0) { | ||
836 | /* Program BR generator */ | ||
837 | write_scc(priv, R12, priv->param.brg_tc & 0xFF); | ||
838 | write_scc(priv, R13, (priv->param.brg_tc >> 8) & 0xFF); | ||
839 | /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by | ||
840 | PackeTwin, not connected on the PI2); set DPLL source to BRG */ | ||
841 | write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL); | ||
842 | /* Enable DPLL */ | ||
843 | write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL); | ||
844 | } else { | ||
845 | /* Disable BR generator */ | ||
846 | write_scc(priv, R14, DTRREQ | BRSRC); | ||
847 | } | ||
848 | |||
849 | /* Configure clocks */ | ||
850 | if (priv->type == TYPE_TWIN) { | ||
851 | /* Disable external TX clock receiver */ | ||
852 | outb((info->twin_serial_cfg &= | ||
853 | ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), | ||
854 | card_base + TWIN_SERIAL_CFG); | ||
855 | } | ||
856 | write_scc(priv, R11, priv->param.clocks); | ||
857 | if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) { | ||
858 | /* Enable external TX clock receiver */ | ||
859 | outb((info->twin_serial_cfg |= | ||
860 | (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), | ||
861 | card_base + TWIN_SERIAL_CFG); | ||
862 | } | ||
863 | |||
864 | /* Configure PackeTwin */ | ||
865 | if (priv->type == TYPE_TWIN) { | ||
866 | /* Assert DTR, enable interrupts */ | ||
867 | outb((info->twin_serial_cfg |= TWIN_EI | | ||
868 | (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)), | ||
869 | card_base + TWIN_SERIAL_CFG); | ||
870 | } | ||
871 | |||
872 | /* Read current status */ | ||
873 | priv->rr0 = read_scc(priv, R0); | ||
874 | /* Enable DCD interrupt */ | ||
875 | write_scc(priv, R15, DCDIE); | ||
876 | |||
877 | netif_start_queue(dev); | ||
878 | |||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | |||
883 | static int scc_close(struct net_device *dev) | ||
884 | { | ||
885 | struct scc_priv *priv = dev->priv; | ||
886 | struct scc_info *info = priv->info; | ||
887 | int card_base = priv->card_base; | ||
888 | |||
889 | netif_stop_queue(dev); | ||
890 | |||
891 | if (priv->type == TYPE_TWIN) { | ||
892 | /* Drop DTR */ | ||
893 | outb((info->twin_serial_cfg &= | ||
894 | (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)), | ||
895 | card_base + TWIN_SERIAL_CFG); | ||
896 | } | ||
897 | |||
898 | /* Reset channel, free DMA and IRQ */ | ||
899 | write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV); | ||
900 | if (priv->param.dma >= 0) { | ||
901 | if (priv->type == TYPE_TWIN) | ||
902 | outb(0, card_base + TWIN_DMA_CFG); | ||
903 | free_dma(priv->param.dma); | ||
904 | } | ||
905 | if (--info->irq_used == 0) | ||
906 | free_irq(dev->irq, info); | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | |||
912 | static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
913 | { | ||
914 | struct scc_priv *priv = dev->priv; | ||
915 | |||
916 | switch (cmd) { | ||
917 | case SIOCGSCCPARAM: | ||
918 | if (copy_to_user | ||
919 | (ifr->ifr_data, &priv->param, | ||
920 | sizeof(struct scc_param))) | ||
921 | return -EFAULT; | ||
922 | return 0; | ||
923 | case SIOCSSCCPARAM: | ||
924 | if (!capable(CAP_NET_ADMIN)) | ||
925 | return -EPERM; | ||
926 | if (netif_running(dev)) | ||
927 | return -EAGAIN; | ||
928 | if (copy_from_user | ||
929 | (&priv->param, ifr->ifr_data, | ||
930 | sizeof(struct scc_param))) | ||
931 | return -EFAULT; | ||
932 | return 0; | ||
933 | default: | ||
934 | return -EINVAL; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | |||
939 | static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
940 | { | ||
941 | struct scc_priv *priv = dev->priv; | ||
942 | unsigned long flags; | ||
943 | int i; | ||
944 | |||
945 | /* Temporarily stop the scheduler feeding us packets */ | ||
946 | netif_stop_queue(dev); | ||
947 | |||
948 | /* Transfer data to DMA buffer */ | ||
949 | i = priv->tx_head; | ||
950 | memcpy(priv->tx_buf[i], skb->data + 1, skb->len - 1); | ||
951 | priv->tx_len[i] = skb->len - 1; | ||
952 | |||
953 | /* Clear interrupts while we touch our circular buffers */ | ||
954 | |||
955 | spin_lock_irqsave(&priv->ring_lock, flags); | ||
956 | /* Move the ring buffer's head */ | ||
957 | priv->tx_head = (i + 1) % NUM_TX_BUF; | ||
958 | priv->tx_count++; | ||
959 | |||
960 | /* If we just filled up the last buffer, leave queue stopped. | ||
961 | The higher layers must wait until we have a DMA buffer | ||
962 | to accept the data. */ | ||
963 | if (priv->tx_count < NUM_TX_BUF) | ||
964 | netif_wake_queue(dev); | ||
965 | |||
966 | /* Set new TX state */ | ||
967 | if (priv->state == IDLE) { | ||
968 | /* Assert RTS, start timer */ | ||
969 | priv->state = TX_HEAD; | ||
970 | priv->tx_start = jiffies; | ||
971 | write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); | ||
972 | write_scc(priv, R15, 0); | ||
973 | start_timer(priv, priv->param.txdelay, 0); | ||
974 | } | ||
975 | |||
976 | /* Turn interrupts back on and free buffer */ | ||
977 | spin_unlock_irqrestore(&priv->ring_lock, flags); | ||
978 | dev_kfree_skb(skb); | ||
979 | |||
980 | return 0; | ||
981 | } | ||
982 | |||
983 | |||
984 | static struct net_device_stats *scc_get_stats(struct net_device *dev) | ||
985 | { | ||
986 | struct scc_priv *priv = dev->priv; | ||
987 | |||
988 | return &priv->stats; | ||
989 | } | ||
990 | |||
991 | |||
992 | static int scc_set_mac_address(struct net_device *dev, void *sa) | ||
993 | { | ||
994 | memcpy(dev->dev_addr, ((struct sockaddr *) sa)->sa_data, | ||
995 | dev->addr_len); | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | |||
1000 | static inline void tx_on(struct scc_priv *priv) | ||
1001 | { | ||
1002 | int i, n; | ||
1003 | unsigned long flags; | ||
1004 | |||
1005 | if (priv->param.dma >= 0) { | ||
1006 | n = (priv->chip == Z85230) ? 3 : 1; | ||
1007 | /* Program DMA controller */ | ||
1008 | flags = claim_dma_lock(); | ||
1009 | set_dma_mode(priv->param.dma, DMA_MODE_WRITE); | ||
1010 | set_dma_addr(priv->param.dma, | ||
1011 | (int) priv->tx_buf[priv->tx_tail] + n); | ||
1012 | set_dma_count(priv->param.dma, | ||
1013 | priv->tx_len[priv->tx_tail] - n); | ||
1014 | release_dma_lock(flags); | ||
1015 | /* Enable TX underrun interrupt */ | ||
1016 | write_scc(priv, R15, TxUIE); | ||
1017 | /* Configure DREQ */ | ||
1018 | if (priv->type == TYPE_TWIN) | ||
1019 | outb((priv->param.dma == | ||
1020 | 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, | ||
1021 | priv->card_base + TWIN_DMA_CFG); | ||
1022 | else | ||
1023 | write_scc(priv, R1, | ||
1024 | EXT_INT_ENAB | WT_FN_RDYFN | | ||
1025 | WT_RDY_ENAB); | ||
1026 | /* Write first byte(s) */ | ||
1027 | spin_lock_irqsave(priv->register_lock, flags); | ||
1028 | for (i = 0; i < n; i++) | ||
1029 | write_scc_data(priv, | ||
1030 | priv->tx_buf[priv->tx_tail][i], 1); | ||
1031 | enable_dma(priv->param.dma); | ||
1032 | spin_unlock_irqrestore(priv->register_lock, flags); | ||
1033 | } else { | ||
1034 | write_scc(priv, R15, TxUIE); | ||
1035 | write_scc(priv, R1, | ||
1036 | EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); | ||
1037 | tx_isr(priv); | ||
1038 | } | ||
1039 | /* Reset EOM latch if we do not have the AUTOEOM feature */ | ||
1040 | if (priv->chip == Z8530) | ||
1041 | write_scc(priv, R0, RES_EOM_L); | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | static inline void rx_on(struct scc_priv *priv) | ||
1046 | { | ||
1047 | unsigned long flags; | ||
1048 | |||
1049 | /* Clear RX FIFO */ | ||
1050 | while (read_scc(priv, R0) & Rx_CH_AV) | ||
1051 | read_scc_data(priv); | ||
1052 | priv->rx_over = 0; | ||
1053 | if (priv->param.dma >= 0) { | ||
1054 | /* Program DMA controller */ | ||
1055 | flags = claim_dma_lock(); | ||
1056 | set_dma_mode(priv->param.dma, DMA_MODE_READ); | ||
1057 | set_dma_addr(priv->param.dma, | ||
1058 | (int) priv->rx_buf[priv->rx_head]); | ||
1059 | set_dma_count(priv->param.dma, BUF_SIZE); | ||
1060 | release_dma_lock(flags); | ||
1061 | enable_dma(priv->param.dma); | ||
1062 | /* Configure PackeTwin DMA */ | ||
1063 | if (priv->type == TYPE_TWIN) { | ||
1064 | outb((priv->param.dma == | ||
1065 | 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, | ||
1066 | priv->card_base + TWIN_DMA_CFG); | ||
1067 | } | ||
1068 | /* Sp. cond. intr. only, ext int enable, RX DMA enable */ | ||
1069 | write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | | ||
1070 | WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); | ||
1071 | } else { | ||
1072 | /* Reset current frame */ | ||
1073 | priv->rx_ptr = 0; | ||
1074 | /* Intr. on all Rx characters and Sp. cond., ext int enable */ | ||
1075 | write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | | ||
1076 | WT_FN_RDYFN); | ||
1077 | } | ||
1078 | write_scc(priv, R0, ERR_RES); | ||
1079 | write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB); | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | static inline void rx_off(struct scc_priv *priv) | ||
1084 | { | ||
1085 | /* Disable receiver */ | ||
1086 | write_scc(priv, R3, Rx8); | ||
1087 | /* Disable DREQ / RX interrupt */ | ||
1088 | if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) | ||
1089 | outb(0, priv->card_base + TWIN_DMA_CFG); | ||
1090 | else | ||
1091 | write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); | ||
1092 | /* Disable DMA */ | ||
1093 | if (priv->param.dma >= 0) | ||
1094 | disable_dma(priv->param.dma); | ||
1095 | } | ||
1096 | |||
1097 | |||
1098 | static void start_timer(struct scc_priv *priv, int t, int r15) | ||
1099 | { | ||
1100 | unsigned long flags; | ||
1101 | |||
1102 | outb(priv->tmr_mode, priv->tmr_ctrl); | ||
1103 | if (t == 0) { | ||
1104 | tm_isr(priv); | ||
1105 | } else if (t > 0) { | ||
1106 | save_flags(flags); | ||
1107 | cli(); | ||
1108 | outb(t & 0xFF, priv->tmr_cnt); | ||
1109 | outb((t >> 8) & 0xFF, priv->tmr_cnt); | ||
1110 | if (priv->type != TYPE_TWIN) { | ||
1111 | write_scc(priv, R15, r15 | CTSIE); | ||
1112 | priv->rr0 |= CTS; | ||
1113 | } | ||
1114 | restore_flags(flags); | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | |||
1119 | static inline unsigned char random(void) | ||
1120 | { | ||
1121 | /* See "Numerical Recipes in C", second edition, p. 284 */ | ||
1122 | rand = rand * 1664525L + 1013904223L; | ||
1123 | return (unsigned char) (rand >> 24); | ||
1124 | } | ||
1125 | |||
1126 | static inline void z8530_isr(struct scc_info *info) | ||
1127 | { | ||
1128 | int is, i = 100; | ||
1129 | |||
1130 | while ((is = read_scc(&info->priv[0], R3)) && i--) { | ||
1131 | if (is & CHARxIP) { | ||
1132 | rx_isr(&info->priv[0]); | ||
1133 | } else if (is & CHATxIP) { | ||
1134 | tx_isr(&info->priv[0]); | ||
1135 | } else if (is & CHAEXT) { | ||
1136 | es_isr(&info->priv[0]); | ||
1137 | } else if (is & CHBRxIP) { | ||
1138 | rx_isr(&info->priv[1]); | ||
1139 | } else if (is & CHBTxIP) { | ||
1140 | tx_isr(&info->priv[1]); | ||
1141 | } else { | ||
1142 | es_isr(&info->priv[1]); | ||
1143 | } | ||
1144 | write_scc(&info->priv[0], R0, RES_H_IUS); | ||
1145 | i++; | ||
1146 | } | ||
1147 | if (i < 0) { | ||
1148 | printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", | ||
1149 | is); | ||
1150 | } | ||
1151 | /* Ok, no interrupts pending from this 8530. The INT line should | ||
1152 | be inactive now. */ | ||
1153 | } | ||
1154 | |||
1155 | |||
1156 | static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
1157 | { | ||
1158 | struct scc_info *info = dev_id; | ||
1159 | |||
1160 | spin_lock(info->priv[0].register_lock); | ||
1161 | /* At this point interrupts are enabled, and the interrupt under service | ||
1162 | is already acknowledged, but masked off. | ||
1163 | |||
1164 | Interrupt processing: We loop until we know that the IRQ line is | ||
1165 | low. If another positive edge occurs afterwards during the ISR, | ||
1166 | another interrupt will be triggered by the interrupt controller | ||
1167 | as soon as the IRQ level is enabled again (see asm/irq.h). | ||
1168 | |||
1169 | Bottom-half handlers will be processed after scc_isr(). This is | ||
1170 | important, since we only have small ringbuffers and want new data | ||
1171 | to be fetched/delivered immediately. */ | ||
1172 | |||
1173 | if (info->priv[0].type == TYPE_TWIN) { | ||
1174 | int is, card_base = info->priv[0].card_base; | ||
1175 | while ((is = ~inb(card_base + TWIN_INT_REG)) & | ||
1176 | TWIN_INT_MSK) { | ||
1177 | if (is & TWIN_SCC_MSK) { | ||
1178 | z8530_isr(info); | ||
1179 | } else if (is & TWIN_TMR1_MSK) { | ||
1180 | inb(card_base + TWIN_CLR_TMR1); | ||
1181 | tm_isr(&info->priv[0]); | ||
1182 | } else { | ||
1183 | inb(card_base + TWIN_CLR_TMR2); | ||
1184 | tm_isr(&info->priv[1]); | ||
1185 | } | ||
1186 | } | ||
1187 | } else | ||
1188 | z8530_isr(info); | ||
1189 | spin_unlock(info->priv[0].register_lock); | ||
1190 | return IRQ_HANDLED; | ||
1191 | } | ||
1192 | |||
1193 | |||
1194 | static void rx_isr(struct scc_priv *priv) | ||
1195 | { | ||
1196 | if (priv->param.dma >= 0) { | ||
1197 | /* Check special condition and perform error reset. See 2.4.7.5. */ | ||
1198 | special_condition(priv, read_scc(priv, R1)); | ||
1199 | write_scc(priv, R0, ERR_RES); | ||
1200 | } else { | ||
1201 | /* Check special condition for each character. Error reset not necessary. | ||
1202 | Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */ | ||
1203 | int rc; | ||
1204 | while (read_scc(priv, R0) & Rx_CH_AV) { | ||
1205 | rc = read_scc(priv, R1); | ||
1206 | if (priv->rx_ptr < BUF_SIZE) | ||
1207 | priv->rx_buf[priv->rx_head][priv-> | ||
1208 | rx_ptr++] = | ||
1209 | read_scc_data(priv); | ||
1210 | else { | ||
1211 | priv->rx_over = 2; | ||
1212 | read_scc_data(priv); | ||
1213 | } | ||
1214 | special_condition(priv, rc); | ||
1215 | } | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | |||
1220 | static void special_condition(struct scc_priv *priv, int rc) | ||
1221 | { | ||
1222 | int cb; | ||
1223 | unsigned long flags; | ||
1224 | |||
1225 | /* See Figure 2-15. Only overrun and EOF need to be checked. */ | ||
1226 | |||
1227 | if (rc & Rx_OVR) { | ||
1228 | /* Receiver overrun */ | ||
1229 | priv->rx_over = 1; | ||
1230 | if (priv->param.dma < 0) | ||
1231 | write_scc(priv, R0, ERR_RES); | ||
1232 | } else if (rc & END_FR) { | ||
1233 | /* End of frame. Get byte count */ | ||
1234 | if (priv->param.dma >= 0) { | ||
1235 | flags = claim_dma_lock(); | ||
1236 | cb = BUF_SIZE - get_dma_residue(priv->param.dma) - | ||
1237 | 2; | ||
1238 | release_dma_lock(flags); | ||
1239 | } else { | ||
1240 | cb = priv->rx_ptr - 2; | ||
1241 | } | ||
1242 | if (priv->rx_over) { | ||
1243 | /* We had an overrun */ | ||
1244 | priv->stats.rx_errors++; | ||
1245 | if (priv->rx_over == 2) | ||
1246 | priv->stats.rx_length_errors++; | ||
1247 | else | ||
1248 | priv->stats.rx_fifo_errors++; | ||
1249 | priv->rx_over = 0; | ||
1250 | } else if (rc & CRC_ERR) { | ||
1251 | /* Count invalid CRC only if packet length >= minimum */ | ||
1252 | if (cb >= 15) { | ||
1253 | priv->stats.rx_errors++; | ||
1254 | priv->stats.rx_crc_errors++; | ||
1255 | } | ||
1256 | } else { | ||
1257 | if (cb >= 15) { | ||
1258 | if (priv->rx_count < NUM_RX_BUF - 1) { | ||
1259 | /* Put good frame in FIFO */ | ||
1260 | priv->rx_len[priv->rx_head] = cb; | ||
1261 | priv->rx_head = | ||
1262 | (priv->rx_head + | ||
1263 | 1) % NUM_RX_BUF; | ||
1264 | priv->rx_count++; | ||
1265 | schedule_work(&priv->rx_work); | ||
1266 | } else { | ||
1267 | priv->stats.rx_errors++; | ||
1268 | priv->stats.rx_over_errors++; | ||
1269 | } | ||
1270 | } | ||
1271 | } | ||
1272 | /* Get ready for new frame */ | ||
1273 | if (priv->param.dma >= 0) { | ||
1274 | flags = claim_dma_lock(); | ||
1275 | set_dma_addr(priv->param.dma, | ||
1276 | (int) priv->rx_buf[priv->rx_head]); | ||
1277 | set_dma_count(priv->param.dma, BUF_SIZE); | ||
1278 | release_dma_lock(flags); | ||
1279 | } else { | ||
1280 | priv->rx_ptr = 0; | ||
1281 | } | ||
1282 | } | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | static void rx_bh(void *arg) | ||
1287 | { | ||
1288 | struct scc_priv *priv = arg; | ||
1289 | int i = priv->rx_tail; | ||
1290 | int cb; | ||
1291 | unsigned long flags; | ||
1292 | struct sk_buff *skb; | ||
1293 | unsigned char *data; | ||
1294 | |||
1295 | spin_lock_irqsave(&priv->ring_lock, flags); | ||
1296 | while (priv->rx_count) { | ||
1297 | spin_unlock_irqrestore(&priv->ring_lock, flags); | ||
1298 | cb = priv->rx_len[i]; | ||
1299 | /* Allocate buffer */ | ||
1300 | skb = dev_alloc_skb(cb + 1); | ||
1301 | if (skb == NULL) { | ||
1302 | /* Drop packet */ | ||
1303 | priv->stats.rx_dropped++; | ||
1304 | } else { | ||
1305 | /* Fill buffer */ | ||
1306 | data = skb_put(skb, cb + 1); | ||
1307 | data[0] = 0; | ||
1308 | memcpy(&data[1], priv->rx_buf[i], cb); | ||
1309 | skb->dev = priv->dev; | ||
1310 | skb->protocol = ntohs(ETH_P_AX25); | ||
1311 | skb->mac.raw = skb->data; | ||
1312 | netif_rx(skb); | ||
1313 | priv->dev->last_rx = jiffies; | ||
1314 | priv->stats.rx_packets++; | ||
1315 | priv->stats.rx_bytes += cb; | ||
1316 | } | ||
1317 | spin_lock_irqsave(&priv->ring_lock, flags); | ||
1318 | /* Move tail */ | ||
1319 | priv->rx_tail = i = (i + 1) % NUM_RX_BUF; | ||
1320 | priv->rx_count--; | ||
1321 | } | ||
1322 | spin_unlock_irqrestore(&priv->ring_lock, flags); | ||
1323 | } | ||
1324 | |||
1325 | |||
1326 | static void tx_isr(struct scc_priv *priv) | ||
1327 | { | ||
1328 | int i = priv->tx_tail, p = priv->tx_ptr; | ||
1329 | |||
1330 | /* Suspend TX interrupts if we don't want to send anything. | ||
1331 | See Figure 2-22. */ | ||
1332 | if (p == priv->tx_len[i]) { | ||
1333 | write_scc(priv, R0, RES_Tx_P); | ||
1334 | return; | ||
1335 | } | ||
1336 | |||
1337 | /* Write characters */ | ||
1338 | while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) { | ||
1339 | write_scc_data(priv, priv->tx_buf[i][p++], 0); | ||
1340 | } | ||
1341 | |||
1342 | /* Reset EOM latch of Z8530 */ | ||
1343 | if (!priv->tx_ptr && p && priv->chip == Z8530) | ||
1344 | write_scc(priv, R0, RES_EOM_L); | ||
1345 | |||
1346 | priv->tx_ptr = p; | ||
1347 | } | ||
1348 | |||
1349 | |||
1350 | static void es_isr(struct scc_priv *priv) | ||
1351 | { | ||
1352 | int i, rr0, drr0, res; | ||
1353 | unsigned long flags; | ||
1354 | |||
1355 | /* Read status, reset interrupt bit (open latches) */ | ||
1356 | rr0 = read_scc(priv, R0); | ||
1357 | write_scc(priv, R0, RES_EXT_INT); | ||
1358 | drr0 = priv->rr0 ^ rr0; | ||
1359 | priv->rr0 = rr0; | ||
1360 | |||
1361 | /* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since | ||
1362 | it might have already been cleared again by AUTOEOM. */ | ||
1363 | if (priv->state == TX_DATA) { | ||
1364 | /* Get remaining bytes */ | ||
1365 | i = priv->tx_tail; | ||
1366 | if (priv->param.dma >= 0) { | ||
1367 | disable_dma(priv->param.dma); | ||
1368 | flags = claim_dma_lock(); | ||
1369 | res = get_dma_residue(priv->param.dma); | ||
1370 | release_dma_lock(flags); | ||
1371 | } else { | ||
1372 | res = priv->tx_len[i] - priv->tx_ptr; | ||
1373 | priv->tx_ptr = 0; | ||
1374 | } | ||
1375 | /* Disable DREQ / TX interrupt */ | ||
1376 | if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) | ||
1377 | outb(0, priv->card_base + TWIN_DMA_CFG); | ||
1378 | else | ||
1379 | write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); | ||
1380 | if (res) { | ||
1381 | /* Update packet statistics */ | ||
1382 | priv->stats.tx_errors++; | ||
1383 | priv->stats.tx_fifo_errors++; | ||
1384 | /* Other underrun interrupts may already be waiting */ | ||
1385 | write_scc(priv, R0, RES_EXT_INT); | ||
1386 | write_scc(priv, R0, RES_EXT_INT); | ||
1387 | } else { | ||
1388 | /* Update packet statistics */ | ||
1389 | priv->stats.tx_packets++; | ||
1390 | priv->stats.tx_bytes += priv->tx_len[i]; | ||
1391 | /* Remove frame from FIFO */ | ||
1392 | priv->tx_tail = (i + 1) % NUM_TX_BUF; | ||
1393 | priv->tx_count--; | ||
1394 | /* Inform upper layers */ | ||
1395 | netif_wake_queue(priv->dev); | ||
1396 | } | ||
1397 | /* Switch state */ | ||
1398 | write_scc(priv, R15, 0); | ||
1399 | if (priv->tx_count && | ||
1400 | (jiffies - priv->tx_start) < priv->param.txtimeout) { | ||
1401 | priv->state = TX_PAUSE; | ||
1402 | start_timer(priv, priv->param.txpause, 0); | ||
1403 | } else { | ||
1404 | priv->state = TX_TAIL; | ||
1405 | start_timer(priv, priv->param.txtail, 0); | ||
1406 | } | ||
1407 | } | ||
1408 | |||
1409 | /* DCD transition */ | ||
1410 | if (drr0 & DCD) { | ||
1411 | if (rr0 & DCD) { | ||
1412 | switch (priv->state) { | ||
1413 | case IDLE: | ||
1414 | case WAIT: | ||
1415 | priv->state = DCD_ON; | ||
1416 | write_scc(priv, R15, 0); | ||
1417 | start_timer(priv, priv->param.dcdon, 0); | ||
1418 | } | ||
1419 | } else { | ||
1420 | switch (priv->state) { | ||
1421 | case RX_ON: | ||
1422 | rx_off(priv); | ||
1423 | priv->state = DCD_OFF; | ||
1424 | write_scc(priv, R15, 0); | ||
1425 | start_timer(priv, priv->param.dcdoff, 0); | ||
1426 | } | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | /* CTS transition */ | ||
1431 | if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN) | ||
1432 | tm_isr(priv); | ||
1433 | |||
1434 | } | ||
1435 | |||
1436 | |||
1437 | static void tm_isr(struct scc_priv *priv) | ||
1438 | { | ||
1439 | switch (priv->state) { | ||
1440 | case TX_HEAD: | ||
1441 | case TX_PAUSE: | ||
1442 | tx_on(priv); | ||
1443 | priv->state = TX_DATA; | ||
1444 | break; | ||
1445 | case TX_TAIL: | ||
1446 | write_scc(priv, R5, TxCRC_ENAB | Tx8); | ||
1447 | priv->state = RTS_OFF; | ||
1448 | if (priv->type != TYPE_TWIN) | ||
1449 | write_scc(priv, R15, 0); | ||
1450 | start_timer(priv, priv->param.rtsoff, 0); | ||
1451 | break; | ||
1452 | case RTS_OFF: | ||
1453 | write_scc(priv, R15, DCDIE); | ||
1454 | priv->rr0 = read_scc(priv, R0); | ||
1455 | if (priv->rr0 & DCD) { | ||
1456 | priv->stats.collisions++; | ||
1457 | rx_on(priv); | ||
1458 | priv->state = RX_ON; | ||
1459 | } else { | ||
1460 | priv->state = WAIT; | ||
1461 | start_timer(priv, priv->param.waittime, DCDIE); | ||
1462 | } | ||
1463 | break; | ||
1464 | case WAIT: | ||
1465 | if (priv->tx_count) { | ||
1466 | priv->state = TX_HEAD; | ||
1467 | priv->tx_start = jiffies; | ||
1468 | write_scc(priv, R5, | ||
1469 | TxCRC_ENAB | RTS | TxENAB | Tx8); | ||
1470 | write_scc(priv, R15, 0); | ||
1471 | start_timer(priv, priv->param.txdelay, 0); | ||
1472 | } else { | ||
1473 | priv->state = IDLE; | ||
1474 | if (priv->type != TYPE_TWIN) | ||
1475 | write_scc(priv, R15, DCDIE); | ||
1476 | } | ||
1477 | break; | ||
1478 | case DCD_ON: | ||
1479 | case DCD_OFF: | ||
1480 | write_scc(priv, R15, DCDIE); | ||
1481 | priv->rr0 = read_scc(priv, R0); | ||
1482 | if (priv->rr0 & DCD) { | ||
1483 | rx_on(priv); | ||
1484 | priv->state = RX_ON; | ||
1485 | } else { | ||
1486 | priv->state = WAIT; | ||
1487 | start_timer(priv, | ||
1488 | random() / priv->param.persist * | ||
1489 | priv->param.slottime, DCDIE); | ||
1490 | } | ||
1491 | break; | ||
1492 | } | ||
1493 | } | ||
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 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c new file mode 100644 index 000000000000..d9ea080aea0f --- /dev/null +++ b/drivers/net/hamradio/mkiss.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /* | ||
2 | * MKISS Driver | ||
3 | * | ||
4 | * This module: | ||
5 | * This module is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This module implements the AX.25 protocol for kernel-based | ||
11 | * devices like TTYs. It interfaces between a raw TTY, and the | ||
12 | * kernel's AX.25 protocol layers, just like slip.c. | ||
13 | * AX.25 needs to be separated from slip.c while slip.c is no | ||
14 | * longer a static kernel device since it is a module. | ||
15 | * This method clears the way to implement other kiss protocols | ||
16 | * like mkiss smack g8bpq ..... so far only mkiss is implemented. | ||
17 | * | ||
18 | * Hans Alblas <hans@esrac.ele.tue.nl> | ||
19 | * | ||
20 | * History | ||
21 | * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. | ||
22 | * Matthias (DG2FEF) Added support for FlexNet CRC (on special request) | ||
23 | * Fixed bug in ax25_close(): dev_lock_wait() was | ||
24 | * called twice, causing a deadlock. | ||
25 | * Jeroen (PE1RXQ) Removed old MKISS_MAGIC stuff and calls to | ||
26 | * MOD_*_USE_COUNT | ||
27 | * Remove cli() and fix rtnl lock usage. | ||
28 | */ | ||
29 | |||
30 | #include <linux/config.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <linux/bitops.h> | ||
34 | #include <asm/uaccess.h> | ||
35 | #include <linux/string.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/in.h> | ||
39 | #include <linux/inet.h> | ||
40 | #include <linux/tty.h> | ||
41 | #include <linux/errno.h> | ||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/major.h> | ||
44 | #include <linux/init.h> | ||
45 | #include <linux/rtnetlink.h> | ||
46 | #include <linux/etherdevice.h> | ||
47 | #include <linux/skbuff.h> | ||
48 | #include <linux/if_arp.h> | ||
49 | |||
50 | #include <net/ax25.h> | ||
51 | |||
52 | #include "mkiss.h" | ||
53 | |||
54 | #ifdef CONFIG_INET | ||
55 | #include <linux/ip.h> | ||
56 | #include <linux/tcp.h> | ||
57 | #endif | ||
58 | |||
59 | static char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; | ||
60 | |||
61 | typedef struct ax25_ctrl { | ||
62 | struct ax_disp ctrl; /* */ | ||
63 | struct net_device dev; /* the device */ | ||
64 | } ax25_ctrl_t; | ||
65 | |||
66 | static ax25_ctrl_t **ax25_ctrls; | ||
67 | |||
68 | int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */ | ||
69 | |||
70 | static struct tty_ldisc ax_ldisc; | ||
71 | |||
72 | static int ax25_init(struct net_device *); | ||
73 | static int kiss_esc(unsigned char *, unsigned char *, int); | ||
74 | static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int); | ||
75 | static void kiss_unesc(struct ax_disp *, unsigned char); | ||
76 | |||
77 | /*---------------------------------------------------------------------------*/ | ||
78 | |||
79 | static const unsigned short Crc_flex_table[] = { | ||
80 | 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, | ||
81 | 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, | ||
82 | 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, | ||
83 | 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, | ||
84 | 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, | ||
85 | 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, | ||
86 | 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, | ||
87 | 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, | ||
88 | 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, | ||
89 | 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, | ||
90 | 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, | ||
91 | 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, | ||
92 | 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, | ||
93 | 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, | ||
94 | 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, | ||
95 | 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, | ||
96 | 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, | ||
97 | 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, | ||
98 | 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, | ||
99 | 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, | ||
100 | 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, | ||
101 | 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, | ||
102 | 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, | ||
103 | 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, | ||
104 | 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, | ||
105 | 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, | ||
106 | 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, | ||
107 | 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, | ||
108 | 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, | ||
109 | 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, | ||
110 | 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, | ||
111 | 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff | ||
112 | }; | ||
113 | |||
114 | /*---------------------------------------------------------------------------*/ | ||
115 | |||
116 | static unsigned short calc_crc_flex(unsigned char *cp, int size) | ||
117 | { | ||
118 | unsigned short crc = 0xffff; | ||
119 | |||
120 | while (size--) | ||
121 | crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; | ||
122 | |||
123 | return crc; | ||
124 | } | ||
125 | |||
126 | /*---------------------------------------------------------------------------*/ | ||
127 | |||
128 | static int check_crc_flex(unsigned char *cp, int size) | ||
129 | { | ||
130 | unsigned short crc = 0xffff; | ||
131 | |||
132 | if (size < 3) | ||
133 | return -1; | ||
134 | |||
135 | while (size--) | ||
136 | crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; | ||
137 | |||
138 | if ((crc & 0xffff) != 0x7070) | ||
139 | return -1; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /*---------------------------------------------------------------------------*/ | ||
145 | |||
146 | /* Find a free channel, and link in this `tty' line. */ | ||
147 | static inline struct ax_disp *ax_alloc(void) | ||
148 | { | ||
149 | ax25_ctrl_t *axp=NULL; | ||
150 | int i; | ||
151 | |||
152 | for (i = 0; i < ax25_maxdev; i++) { | ||
153 | axp = ax25_ctrls[i]; | ||
154 | |||
155 | /* Not allocated ? */ | ||
156 | if (axp == NULL) | ||
157 | break; | ||
158 | |||
159 | /* Not in use ? */ | ||
160 | if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | /* Sorry, too many, all slots in use */ | ||
165 | if (i >= ax25_maxdev) | ||
166 | return NULL; | ||
167 | |||
168 | /* If no channels are available, allocate one */ | ||
169 | if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { | ||
170 | axp = ax25_ctrls[i]; | ||
171 | } | ||
172 | memset(axp, 0, sizeof(ax25_ctrl_t)); | ||
173 | |||
174 | /* Initialize channel control data */ | ||
175 | set_bit(AXF_INUSE, &axp->ctrl.flags); | ||
176 | sprintf(axp->dev.name, "ax%d", i++); | ||
177 | axp->ctrl.tty = NULL; | ||
178 | axp->dev.base_addr = i; | ||
179 | axp->dev.priv = (void *)&axp->ctrl; | ||
180 | axp->dev.next = NULL; | ||
181 | axp->dev.init = ax25_init; | ||
182 | |||
183 | if (axp != NULL) { | ||
184 | /* | ||
185 | * register device so that it can be ifconfig'ed | ||
186 | * ax25_init() will be called as a side-effect | ||
187 | * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl ! | ||
188 | */ | ||
189 | if (register_netdev(&axp->dev) == 0) { | ||
190 | /* (Re-)Set the INUSE bit. Very Important! */ | ||
191 | set_bit(AXF_INUSE, &axp->ctrl.flags); | ||
192 | axp->ctrl.dev = &axp->dev; | ||
193 | axp->dev.priv = (void *) &axp->ctrl; | ||
194 | |||
195 | return &axp->ctrl; | ||
196 | } else { | ||
197 | clear_bit(AXF_INUSE,&axp->ctrl.flags); | ||
198 | printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n"); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | return NULL; | ||
203 | } | ||
204 | |||
205 | /* Free an AX25 channel. */ | ||
206 | static inline void ax_free(struct ax_disp *ax) | ||
207 | { | ||
208 | /* Free all AX25 frame buffers. */ | ||
209 | if (ax->rbuff) | ||
210 | kfree(ax->rbuff); | ||
211 | ax->rbuff = NULL; | ||
212 | if (ax->xbuff) | ||
213 | kfree(ax->xbuff); | ||
214 | ax->xbuff = NULL; | ||
215 | if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) | ||
216 | printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name); | ||
217 | } | ||
218 | |||
219 | static void ax_changedmtu(struct ax_disp *ax) | ||
220 | { | ||
221 | struct net_device *dev = ax->dev; | ||
222 | unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; | ||
223 | int len; | ||
224 | |||
225 | len = dev->mtu * 2; | ||
226 | |||
227 | /* | ||
228 | * allow for arrival of larger UDP packets, even if we say not to | ||
229 | * also fixes a bug in which SunOS sends 512-byte packets even with | ||
230 | * an MSS of 128 | ||
231 | */ | ||
232 | if (len < 576 * 2) | ||
233 | len = 576 * 2; | ||
234 | |||
235 | xbuff = kmalloc(len + 4, GFP_ATOMIC); | ||
236 | rbuff = kmalloc(len + 4, GFP_ATOMIC); | ||
237 | |||
238 | if (xbuff == NULL || rbuff == NULL) { | ||
239 | printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n", | ||
240 | ax->dev->name); | ||
241 | dev->mtu = ax->mtu; | ||
242 | if (xbuff != NULL) | ||
243 | kfree(xbuff); | ||
244 | if (rbuff != NULL) | ||
245 | kfree(rbuff); | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | spin_lock_bh(&ax->buflock); | ||
250 | |||
251 | oxbuff = ax->xbuff; | ||
252 | ax->xbuff = xbuff; | ||
253 | orbuff = ax->rbuff; | ||
254 | ax->rbuff = rbuff; | ||
255 | |||
256 | if (ax->xleft) { | ||
257 | if (ax->xleft <= len) { | ||
258 | memcpy(ax->xbuff, ax->xhead, ax->xleft); | ||
259 | } else { | ||
260 | ax->xleft = 0; | ||
261 | ax->tx_dropped++; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | ax->xhead = ax->xbuff; | ||
266 | |||
267 | if (ax->rcount) { | ||
268 | if (ax->rcount <= len) { | ||
269 | memcpy(ax->rbuff, orbuff, ax->rcount); | ||
270 | } else { | ||
271 | ax->rcount = 0; | ||
272 | ax->rx_over_errors++; | ||
273 | set_bit(AXF_ERROR, &ax->flags); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | ax->mtu = dev->mtu + 73; | ||
278 | ax->buffsize = len; | ||
279 | |||
280 | spin_unlock_bh(&ax->buflock); | ||
281 | |||
282 | if (oxbuff != NULL) | ||
283 | kfree(oxbuff); | ||
284 | if (orbuff != NULL) | ||
285 | kfree(orbuff); | ||
286 | } | ||
287 | |||
288 | |||
289 | /* Set the "sending" flag. This must be atomic. */ | ||
290 | static inline void ax_lock(struct ax_disp *ax) | ||
291 | { | ||
292 | netif_stop_queue(ax->dev); | ||
293 | } | ||
294 | |||
295 | |||
296 | /* Clear the "sending" flag. This must be atomic. */ | ||
297 | static inline void ax_unlock(struct ax_disp *ax) | ||
298 | { | ||
299 | netif_start_queue(ax->dev); | ||
300 | } | ||
301 | |||
302 | /* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ | ||
303 | static void ax_bump(struct ax_disp *ax) | ||
304 | { | ||
305 | struct sk_buff *skb; | ||
306 | int count; | ||
307 | |||
308 | spin_lock_bh(&ax->buflock); | ||
309 | if (ax->rbuff[0] > 0x0f) { | ||
310 | if (ax->rbuff[0] & 0x20) { | ||
311 | ax->crcmode = CRC_MODE_FLEX; | ||
312 | if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { | ||
313 | ax->rx_errors++; | ||
314 | return; | ||
315 | } | ||
316 | ax->rcount -= 2; | ||
317 | /* dl9sau bugfix: the trailling two bytes flexnet crc | ||
318 | * will not be passed to the kernel. thus we have | ||
319 | * to correct the kissparm signature, because it | ||
320 | * indicates a crc but there's none | ||
321 | */ | ||
322 | *ax->rbuff &= ~0x20; | ||
323 | } | ||
324 | } | ||
325 | spin_unlock_bh(&ax->buflock); | ||
326 | |||
327 | count = ax->rcount; | ||
328 | |||
329 | if ((skb = dev_alloc_skb(count)) == NULL) { | ||
330 | printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); | ||
331 | ax->rx_dropped++; | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | skb->dev = ax->dev; | ||
336 | spin_lock_bh(&ax->buflock); | ||
337 | memcpy(skb_put(skb,count), ax->rbuff, count); | ||
338 | spin_unlock_bh(&ax->buflock); | ||
339 | skb->mac.raw = skb->data; | ||
340 | skb->protocol = htons(ETH_P_AX25); | ||
341 | netif_rx(skb); | ||
342 | ax->dev->last_rx = jiffies; | ||
343 | ax->rx_packets++; | ||
344 | ax->rx_bytes+=count; | ||
345 | } | ||
346 | |||
347 | /* Encapsulate one AX.25 packet and stuff into a TTY queue. */ | ||
348 | static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) | ||
349 | { | ||
350 | unsigned char *p; | ||
351 | int actual, count; | ||
352 | |||
353 | if (ax->mtu != ax->dev->mtu + 73) /* Someone has been ifconfigging */ | ||
354 | ax_changedmtu(ax); | ||
355 | |||
356 | if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ | ||
357 | len = ax->mtu; | ||
358 | printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); | ||
359 | ax->tx_dropped++; | ||
360 | ax_unlock(ax); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | p = icp; | ||
365 | |||
366 | spin_lock_bh(&ax->buflock); | ||
367 | switch (ax->crcmode) { | ||
368 | unsigned short crc; | ||
369 | |||
370 | case CRC_MODE_FLEX: | ||
371 | *p |= 0x20; | ||
372 | crc = calc_crc_flex(p, len); | ||
373 | count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); | ||
374 | break; | ||
375 | |||
376 | default: | ||
377 | count = kiss_esc(p, (unsigned char *)ax->xbuff, len); | ||
378 | break; | ||
379 | } | ||
380 | |||
381 | ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); | ||
382 | actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); | ||
383 | ax->tx_packets++; | ||
384 | ax->tx_bytes+=actual; | ||
385 | ax->dev->trans_start = jiffies; | ||
386 | ax->xleft = count - actual; | ||
387 | ax->xhead = ax->xbuff + actual; | ||
388 | |||
389 | spin_unlock_bh(&ax->buflock); | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Called by the driver when there's room for more data. If we have | ||
394 | * more packets to send, we send them here. | ||
395 | */ | ||
396 | static void ax25_write_wakeup(struct tty_struct *tty) | ||
397 | { | ||
398 | int actual; | ||
399 | struct ax_disp *ax = (struct ax_disp *) tty->disc_data; | ||
400 | |||
401 | /* First make sure we're connected. */ | ||
402 | if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev)) | ||
403 | return; | ||
404 | if (ax->xleft <= 0) { | ||
405 | /* Now serial buffer is almost free & we can start | ||
406 | * transmission of another packet | ||
407 | */ | ||
408 | tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); | ||
409 | |||
410 | netif_wake_queue(ax->dev); | ||
411 | return; | ||
412 | } | ||
413 | |||
414 | actual = tty->driver->write(tty, ax->xhead, ax->xleft); | ||
415 | ax->xleft -= actual; | ||
416 | ax->xhead += actual; | ||
417 | } | ||
418 | |||
419 | /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ | ||
420 | static int ax_xmit(struct sk_buff *skb, struct net_device *dev) | ||
421 | { | ||
422 | struct ax_disp *ax = netdev_priv(dev); | ||
423 | |||
424 | if (!netif_running(dev)) { | ||
425 | printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); | ||
426 | return 1; | ||
427 | } | ||
428 | |||
429 | if (netif_queue_stopped(dev)) { | ||
430 | /* | ||
431 | * May be we must check transmitter timeout here ? | ||
432 | * 14 Oct 1994 Dmitry Gorodchanin. | ||
433 | */ | ||
434 | if (jiffies - dev->trans_start < 20 * HZ) { | ||
435 | /* 20 sec timeout not reached */ | ||
436 | return 1; | ||
437 | } | ||
438 | |||
439 | printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, | ||
440 | (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ? | ||
441 | "bad line quality" : "driver error"); | ||
442 | |||
443 | ax->xleft = 0; | ||
444 | ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); | ||
445 | ax_unlock(ax); | ||
446 | } | ||
447 | |||
448 | /* We were not busy, so we are now... :-) */ | ||
449 | if (skb != NULL) { | ||
450 | ax_lock(ax); | ||
451 | ax_encaps(ax, skb->data, skb->len); | ||
452 | kfree_skb(skb); | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) | ||
459 | |||
460 | /* Return the frame type ID */ | ||
461 | static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, | ||
462 | void *daddr, void *saddr, unsigned len) | ||
463 | { | ||
464 | #ifdef CONFIG_INET | ||
465 | if (type != htons(ETH_P_AX25)) | ||
466 | return ax25_encapsulate(skb, dev, type, daddr, saddr, len); | ||
467 | #endif | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | |||
472 | static int ax_rebuild_header(struct sk_buff *skb) | ||
473 | { | ||
474 | #ifdef CONFIG_INET | ||
475 | return ax25_rebuild_header(skb); | ||
476 | #else | ||
477 | return 0; | ||
478 | #endif | ||
479 | } | ||
480 | |||
481 | #endif /* CONFIG_{AX25,AX25_MODULE} */ | ||
482 | |||
483 | /* Open the low-level part of the AX25 channel. Easy! */ | ||
484 | static int ax_open(struct net_device *dev) | ||
485 | { | ||
486 | struct ax_disp *ax = netdev_priv(dev); | ||
487 | unsigned long len; | ||
488 | |||
489 | if (ax->tty == NULL) | ||
490 | return -ENODEV; | ||
491 | |||
492 | /* | ||
493 | * Allocate the frame buffers: | ||
494 | * | ||
495 | * rbuff Receive buffer. | ||
496 | * xbuff Transmit buffer. | ||
497 | */ | ||
498 | len = dev->mtu * 2; | ||
499 | |||
500 | /* | ||
501 | * allow for arrival of larger UDP packets, even if we say not to | ||
502 | * also fixes a bug in which SunOS sends 512-byte packets even with | ||
503 | * an MSS of 128 | ||
504 | */ | ||
505 | if (len < 576 * 2) | ||
506 | len = 576 * 2; | ||
507 | |||
508 | if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) | ||
509 | goto norbuff; | ||
510 | |||
511 | if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) | ||
512 | goto noxbuff; | ||
513 | |||
514 | ax->mtu = dev->mtu + 73; | ||
515 | ax->buffsize = len; | ||
516 | ax->rcount = 0; | ||
517 | ax->xleft = 0; | ||
518 | |||
519 | ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */ | ||
520 | |||
521 | spin_lock_init(&ax->buflock); | ||
522 | |||
523 | netif_start_queue(dev); | ||
524 | return 0; | ||
525 | |||
526 | noxbuff: | ||
527 | kfree(ax->rbuff); | ||
528 | |||
529 | norbuff: | ||
530 | return -ENOMEM; | ||
531 | } | ||
532 | |||
533 | |||
534 | /* Close the low-level part of the AX25 channel. Easy! */ | ||
535 | static int ax_close(struct net_device *dev) | ||
536 | { | ||
537 | struct ax_disp *ax = netdev_priv(dev); | ||
538 | |||
539 | if (ax->tty == NULL) | ||
540 | return -EBUSY; | ||
541 | |||
542 | ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); | ||
543 | |||
544 | netif_stop_queue(dev); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int ax25_receive_room(struct tty_struct *tty) | ||
550 | { | ||
551 | return 65536; /* We can handle an infinite amount of data. :-) */ | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * Handle the 'receiver data ready' interrupt. | ||
556 | * This function is called by the 'tty_io' module in the kernel when | ||
557 | * a block of data has been received, which can now be decapsulated | ||
558 | * and sent on to the AX.25 layer for further processing. | ||
559 | */ | ||
560 | static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) | ||
561 | { | ||
562 | struct ax_disp *ax = (struct ax_disp *) tty->disc_data; | ||
563 | |||
564 | if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev)) | ||
565 | return; | ||
566 | |||
567 | /* | ||
568 | * Argh! mtu change time! - costs us the packet part received | ||
569 | * at the change | ||
570 | */ | ||
571 | if (ax->mtu != ax->dev->mtu + 73) | ||
572 | ax_changedmtu(ax); | ||
573 | |||
574 | /* Read the characters out of the buffer */ | ||
575 | while (count--) { | ||
576 | if (fp != NULL && *fp++) { | ||
577 | if (!test_and_set_bit(AXF_ERROR, &ax->flags)) | ||
578 | ax->rx_errors++; | ||
579 | cp++; | ||
580 | continue; | ||
581 | } | ||
582 | |||
583 | kiss_unesc(ax, *cp++); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | static int ax25_open(struct tty_struct *tty) | ||
588 | { | ||
589 | struct ax_disp *ax = (struct ax_disp *) tty->disc_data; | ||
590 | int err; | ||
591 | |||
592 | /* First make sure we're not already connected. */ | ||
593 | if (ax && ax->magic == AX25_MAGIC) | ||
594 | return -EEXIST; | ||
595 | |||
596 | /* OK. Find a free AX25 channel to use. */ | ||
597 | if ((ax = ax_alloc()) == NULL) | ||
598 | return -ENFILE; | ||
599 | |||
600 | ax->tty = tty; | ||
601 | tty->disc_data = ax; | ||
602 | |||
603 | if (tty->driver->flush_buffer) | ||
604 | tty->driver->flush_buffer(tty); | ||
605 | |||
606 | /* Restore default settings */ | ||
607 | ax->dev->type = ARPHRD_AX25; | ||
608 | |||
609 | /* Perform the low-level AX25 initialization. */ | ||
610 | if ((err = ax_open(ax->dev))) | ||
611 | return err; | ||
612 | |||
613 | /* Done. We have linked the TTY line to a channel. */ | ||
614 | return ax->dev->base_addr; | ||
615 | } | ||
616 | |||
617 | static void ax25_close(struct tty_struct *tty) | ||
618 | { | ||
619 | struct ax_disp *ax = (struct ax_disp *) tty->disc_data; | ||
620 | |||
621 | /* First make sure we're connected. */ | ||
622 | if (ax == NULL || ax->magic != AX25_MAGIC) | ||
623 | return; | ||
624 | |||
625 | unregister_netdev(ax->dev); | ||
626 | |||
627 | tty->disc_data = NULL; | ||
628 | ax->tty = NULL; | ||
629 | |||
630 | ax_free(ax); | ||
631 | } | ||
632 | |||
633 | |||
634 | static struct net_device_stats *ax_get_stats(struct net_device *dev) | ||
635 | { | ||
636 | static struct net_device_stats stats; | ||
637 | struct ax_disp *ax = netdev_priv(dev); | ||
638 | |||
639 | memset(&stats, 0, sizeof(struct net_device_stats)); | ||
640 | |||
641 | stats.rx_packets = ax->rx_packets; | ||
642 | stats.tx_packets = ax->tx_packets; | ||
643 | stats.rx_bytes = ax->rx_bytes; | ||
644 | stats.tx_bytes = ax->tx_bytes; | ||
645 | stats.rx_dropped = ax->rx_dropped; | ||
646 | stats.tx_dropped = ax->tx_dropped; | ||
647 | stats.tx_errors = ax->tx_errors; | ||
648 | stats.rx_errors = ax->rx_errors; | ||
649 | stats.rx_over_errors = ax->rx_over_errors; | ||
650 | |||
651 | return &stats; | ||
652 | } | ||
653 | |||
654 | |||
655 | /************************************************************************ | ||
656 | * STANDARD ENCAPSULATION * | ||
657 | ************************************************************************/ | ||
658 | |||
659 | static int kiss_esc(unsigned char *s, unsigned char *d, int len) | ||
660 | { | ||
661 | unsigned char *ptr = d; | ||
662 | unsigned char c; | ||
663 | |||
664 | /* | ||
665 | * Send an initial END character to flush out any | ||
666 | * data that may have accumulated in the receiver | ||
667 | * due to line noise. | ||
668 | */ | ||
669 | |||
670 | *ptr++ = END; | ||
671 | |||
672 | while (len-- > 0) { | ||
673 | switch (c = *s++) { | ||
674 | case END: | ||
675 | *ptr++ = ESC; | ||
676 | *ptr++ = ESC_END; | ||
677 | break; | ||
678 | case ESC: | ||
679 | *ptr++ = ESC; | ||
680 | *ptr++ = ESC_ESC; | ||
681 | break; | ||
682 | default: | ||
683 | *ptr++ = c; | ||
684 | break; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | *ptr++ = END; | ||
689 | |||
690 | return ptr - d; | ||
691 | } | ||
692 | |||
693 | /* | ||
694 | * MW: | ||
695 | * OK its ugly, but tell me a better solution without copying the | ||
696 | * packet to a temporary buffer :-) | ||
697 | */ | ||
698 | static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len) | ||
699 | { | ||
700 | unsigned char *ptr = d; | ||
701 | unsigned char c=0; | ||
702 | |||
703 | *ptr++ = END; | ||
704 | while (len > 0) { | ||
705 | if (len > 2) | ||
706 | c = *s++; | ||
707 | else if (len > 1) | ||
708 | c = crc >> 8; | ||
709 | else if (len > 0) | ||
710 | c = crc & 0xff; | ||
711 | |||
712 | len--; | ||
713 | |||
714 | switch (c) { | ||
715 | case END: | ||
716 | *ptr++ = ESC; | ||
717 | *ptr++ = ESC_END; | ||
718 | break; | ||
719 | case ESC: | ||
720 | *ptr++ = ESC; | ||
721 | *ptr++ = ESC_ESC; | ||
722 | break; | ||
723 | default: | ||
724 | *ptr++ = c; | ||
725 | break; | ||
726 | } | ||
727 | } | ||
728 | *ptr++ = END; | ||
729 | return ptr - d; | ||
730 | } | ||
731 | |||
732 | static void kiss_unesc(struct ax_disp *ax, unsigned char s) | ||
733 | { | ||
734 | switch (s) { | ||
735 | case END: | ||
736 | /* drop keeptest bit = VSV */ | ||
737 | if (test_bit(AXF_KEEPTEST, &ax->flags)) | ||
738 | clear_bit(AXF_KEEPTEST, &ax->flags); | ||
739 | |||
740 | if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) | ||
741 | ax_bump(ax); | ||
742 | |||
743 | clear_bit(AXF_ESCAPE, &ax->flags); | ||
744 | ax->rcount = 0; | ||
745 | return; | ||
746 | |||
747 | case ESC: | ||
748 | set_bit(AXF_ESCAPE, &ax->flags); | ||
749 | return; | ||
750 | case ESC_ESC: | ||
751 | if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) | ||
752 | s = ESC; | ||
753 | break; | ||
754 | case ESC_END: | ||
755 | if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) | ||
756 | s = END; | ||
757 | break; | ||
758 | } | ||
759 | |||
760 | spin_lock_bh(&ax->buflock); | ||
761 | if (!test_bit(AXF_ERROR, &ax->flags)) { | ||
762 | if (ax->rcount < ax->buffsize) { | ||
763 | ax->rbuff[ax->rcount++] = s; | ||
764 | spin_unlock_bh(&ax->buflock); | ||
765 | return; | ||
766 | } | ||
767 | |||
768 | ax->rx_over_errors++; | ||
769 | set_bit(AXF_ERROR, &ax->flags); | ||
770 | } | ||
771 | spin_unlock_bh(&ax->buflock); | ||
772 | } | ||
773 | |||
774 | |||
775 | static int ax_set_mac_address(struct net_device *dev, void __user *addr) | ||
776 | { | ||
777 | if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN)) | ||
778 | return -EFAULT; | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int ax_set_dev_mac_address(struct net_device *dev, void *addr) | ||
783 | { | ||
784 | struct sockaddr *sa = addr; | ||
785 | |||
786 | memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | |||
792 | /* Perform I/O control on an active ax25 channel. */ | ||
793 | static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void __user *arg) | ||
794 | { | ||
795 | struct ax_disp *ax = (struct ax_disp *) tty->disc_data; | ||
796 | unsigned int tmp; | ||
797 | |||
798 | /* First make sure we're connected. */ | ||
799 | if (ax == NULL || ax->magic != AX25_MAGIC) | ||
800 | return -EINVAL; | ||
801 | |||
802 | switch (cmd) { | ||
803 | case SIOCGIFNAME: | ||
804 | if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1)) | ||
805 | return -EFAULT; | ||
806 | return 0; | ||
807 | |||
808 | case SIOCGIFENCAP: | ||
809 | return put_user(4, (int __user *)arg); | ||
810 | |||
811 | case SIOCSIFENCAP: | ||
812 | if (get_user(tmp, (int __user *)arg)) | ||
813 | return -EFAULT; | ||
814 | ax->mode = tmp; | ||
815 | ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ | ||
816 | ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; | ||
817 | ax->dev->type = ARPHRD_AX25; | ||
818 | return 0; | ||
819 | |||
820 | case SIOCSIFHWADDR: | ||
821 | return ax_set_mac_address(ax->dev, arg); | ||
822 | |||
823 | default: | ||
824 | return -ENOIOCTLCMD; | ||
825 | } | ||
826 | } | ||
827 | |||
828 | static int ax_open_dev(struct net_device *dev) | ||
829 | { | ||
830 | struct ax_disp *ax = netdev_priv(dev); | ||
831 | |||
832 | if (ax->tty == NULL) | ||
833 | return -ENODEV; | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | |||
839 | /* Initialize the driver. Called by network startup. */ | ||
840 | static int ax25_init(struct net_device *dev) | ||
841 | { | ||
842 | struct ax_disp *ax = netdev_priv(dev); | ||
843 | |||
844 | static char ax25_bcast[AX25_ADDR_LEN] = | ||
845 | {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; | ||
846 | static char ax25_test[AX25_ADDR_LEN] = | ||
847 | {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; | ||
848 | |||
849 | if (ax == NULL) /* Allocation failed ?? */ | ||
850 | return -ENODEV; | ||
851 | |||
852 | /* Set up the "AX25 Control Block". (And clear statistics) */ | ||
853 | memset(ax, 0, sizeof (struct ax_disp)); | ||
854 | ax->magic = AX25_MAGIC; | ||
855 | ax->dev = dev; | ||
856 | |||
857 | /* Finish setting up the DEVICE info. */ | ||
858 | dev->mtu = AX_MTU; | ||
859 | dev->hard_start_xmit = ax_xmit; | ||
860 | dev->open = ax_open_dev; | ||
861 | dev->stop = ax_close; | ||
862 | dev->get_stats = ax_get_stats; | ||
863 | dev->set_mac_address = ax_set_dev_mac_address; | ||
864 | dev->hard_header_len = 0; | ||
865 | dev->addr_len = 0; | ||
866 | dev->type = ARPHRD_AX25; | ||
867 | dev->tx_queue_len = 10; | ||
868 | dev->hard_header = ax_header; | ||
869 | dev->rebuild_header = ax_rebuild_header; | ||
870 | |||
871 | memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); | ||
872 | memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); | ||
873 | |||
874 | /* New-style flags. */ | ||
875 | dev->flags = IFF_BROADCAST | IFF_MULTICAST; | ||
876 | |||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | |||
881 | /* ******************************************************************** */ | ||
882 | /* * Init MKISS driver * */ | ||
883 | /* ******************************************************************** */ | ||
884 | |||
885 | static int __init mkiss_init_driver(void) | ||
886 | { | ||
887 | int status; | ||
888 | |||
889 | printk(banner); | ||
890 | |||
891 | if (ax25_maxdev < 4) | ||
892 | ax25_maxdev = 4; /* Sanity */ | ||
893 | |||
894 | if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) { | ||
895 | printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n"); | ||
896 | return -ENOMEM; | ||
897 | } | ||
898 | |||
899 | /* Clear the pointer array, we allocate devices when we need them */ | ||
900 | memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */ | ||
901 | |||
902 | /* Fill in our line protocol discipline, and register it */ | ||
903 | ax_ldisc.magic = TTY_LDISC_MAGIC; | ||
904 | ax_ldisc.name = "mkiss"; | ||
905 | ax_ldisc.open = ax25_open; | ||
906 | ax_ldisc.close = ax25_close; | ||
907 | ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, | ||
908 | unsigned int, unsigned long))ax25_disp_ioctl; | ||
909 | ax_ldisc.receive_buf = ax25_receive_buf; | ||
910 | ax_ldisc.receive_room = ax25_receive_room; | ||
911 | ax_ldisc.write_wakeup = ax25_write_wakeup; | ||
912 | |||
913 | if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) { | ||
914 | printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status); | ||
915 | kfree(ax25_ctrls); | ||
916 | } | ||
917 | return status; | ||
918 | } | ||
919 | |||
920 | static void __exit mkiss_exit_driver(void) | ||
921 | { | ||
922 | int i; | ||
923 | |||
924 | for (i = 0; i < ax25_maxdev; i++) { | ||
925 | if (ax25_ctrls[i]) { | ||
926 | /* | ||
927 | * VSV = if dev->start==0, then device | ||
928 | * unregistered while close proc. | ||
929 | */ | ||
930 | if (netif_running(&ax25_ctrls[i]->dev)) | ||
931 | unregister_netdev(&ax25_ctrls[i]->dev); | ||
932 | kfree(ax25_ctrls[i]); | ||
933 | } | ||
934 | } | ||
935 | |||
936 | kfree(ax25_ctrls); | ||
937 | ax25_ctrls = NULL; | ||
938 | |||
939 | if ((i = tty_register_ldisc(N_AX25, NULL))) | ||
940 | printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i); | ||
941 | } | ||
942 | |||
943 | MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>"); | ||
944 | MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); | ||
945 | MODULE_PARM(ax25_maxdev, "i"); | ||
946 | MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); | ||
947 | MODULE_LICENSE("GPL"); | ||
948 | MODULE_ALIAS_LDISC(N_AX25); | ||
949 | module_init(mkiss_init_driver); | ||
950 | module_exit(mkiss_exit_driver); | ||
951 | |||
diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h new file mode 100644 index 000000000000..4ab700478598 --- /dev/null +++ b/drivers/net/hamradio/mkiss.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /**************************************************************************** | ||
2 | * Defines for the Multi-KISS driver. | ||
3 | ****************************************************************************/ | ||
4 | |||
5 | #define AX25_MAXDEV 16 /* MAX number of AX25 channels; | ||
6 | This can be overridden with | ||
7 | insmod -oax25_maxdev=nnn */ | ||
8 | #define AX_MTU 236 | ||
9 | |||
10 | /* SLIP/KISS protocol characters. */ | ||
11 | #define END 0300 /* indicates end of frame */ | ||
12 | #define ESC 0333 /* indicates byte stuffing */ | ||
13 | #define ESC_END 0334 /* ESC ESC_END means END 'data' */ | ||
14 | #define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ | ||
15 | |||
16 | struct ax_disp { | ||
17 | int magic; | ||
18 | |||
19 | /* Various fields. */ | ||
20 | struct tty_struct *tty; /* ptr to TTY structure */ | ||
21 | struct net_device *dev; /* easy for intr handling */ | ||
22 | |||
23 | /* These are pointers to the malloc()ed frame buffers. */ | ||
24 | unsigned char *rbuff; /* receiver buffer */ | ||
25 | int rcount; /* received chars counter */ | ||
26 | unsigned char *xbuff; /* transmitter buffer */ | ||
27 | unsigned char *xhead; /* pointer to next byte to XMIT */ | ||
28 | int xleft; /* bytes left in XMIT queue */ | ||
29 | |||
30 | /* SLIP interface statistics. */ | ||
31 | unsigned long rx_packets; /* inbound frames counter */ | ||
32 | unsigned long tx_packets; /* outbound frames counter */ | ||
33 | unsigned long rx_bytes; /* inbound bytes counter */ | ||
34 | unsigned long tx_bytes; /* outbound bytes counter */ | ||
35 | unsigned long rx_errors; /* Parity, etc. errors */ | ||
36 | unsigned long tx_errors; /* Planned stuff */ | ||
37 | unsigned long rx_dropped; /* No memory for skb */ | ||
38 | unsigned long tx_dropped; /* When MTU change */ | ||
39 | unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ | ||
40 | |||
41 | /* Detailed SLIP statistics. */ | ||
42 | int mtu; /* Our mtu (to spot changes!) */ | ||
43 | int buffsize; /* Max buffers sizes */ | ||
44 | |||
45 | |||
46 | unsigned long flags; /* Flag values/ mode etc */ | ||
47 | /* long req'd: used by set_bit --RR */ | ||
48 | #define AXF_INUSE 0 /* Channel in use */ | ||
49 | #define AXF_ESCAPE 1 /* ESC received */ | ||
50 | #define AXF_ERROR 2 /* Parity, etc. error */ | ||
51 | #define AXF_KEEPTEST 3 /* Keepalive test flag */ | ||
52 | #define AXF_OUTWAIT 4 /* is outpacket was flag */ | ||
53 | |||
54 | int mode; | ||
55 | int crcmode; /* MW: for FlexNet, SMACK etc. */ | ||
56 | #define CRC_MODE_NONE 0 | ||
57 | #define CRC_MODE_FLEX 1 | ||
58 | #define CRC_MODE_SMACK 2 | ||
59 | spinlock_t buflock; /* lock for rbuf and xbuf */ | ||
60 | }; | ||
61 | |||
62 | #define AX25_MAGIC 0x5316 | ||
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c new file mode 100644 index 000000000000..ce9e7af020da --- /dev/null +++ b/drivers/net/hamradio/scc.c | |||
@@ -0,0 +1,2191 @@ | |||
1 | #define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $" | ||
2 | |||
3 | #define VERSION "3.0" | ||
4 | |||
5 | /* | ||
6 | * Please use z8530drv-utils-3.0 with this version. | ||
7 | * ------------------ | ||
8 | * | ||
9 | * You can find a subset of the documentation in | ||
10 | * Documentation/networking/z8530drv.txt. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | ******************************************************************** | ||
15 | * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 * | ||
16 | ******************************************************************** | ||
17 | |||
18 | |||
19 | ******************************************************************** | ||
20 | |||
21 | Copyright (c) 1993, 2000 Joerg Reuter DL1BKE | ||
22 | |||
23 | portions (c) 1993 Guido ten Dolle PE1NNZ | ||
24 | |||
25 | ******************************************************************** | ||
26 | |||
27 | The driver and the programs in the archive are UNDER CONSTRUCTION. | ||
28 | The code is likely to fail, and so your kernel could --- even | ||
29 | a whole network. | ||
30 | |||
31 | This driver is intended for Amateur Radio use. If you are running it | ||
32 | for commercial purposes, please drop me a note. I am nosy... | ||
33 | |||
34 | ...BUT: | ||
35 | |||
36 | ! You m u s t recognize the appropriate legislations of your country ! | ||
37 | ! before you connect a radio to the SCC board and start to transmit or ! | ||
38 | ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! ! | ||
39 | |||
40 | For non-Amateur-Radio use please note that you might need a special | ||
41 | allowance/licence from the designer of the SCC Board and/or the | ||
42 | MODEM. | ||
43 | |||
44 | This program is free software; you can redistribute it and/or modify | ||
45 | it under the terms of the (modified) GNU General Public License | ||
46 | delivered with the Linux kernel source. | ||
47 | |||
48 | This program is distributed in the hope that it will be useful, | ||
49 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
50 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
51 | GNU General Public License for more details. | ||
52 | |||
53 | You should find a copy of the GNU General Public License in | ||
54 | /usr/src/linux/COPYING; | ||
55 | |||
56 | ******************************************************************** | ||
57 | |||
58 | |||
59 | Incomplete history of z8530drv: | ||
60 | ------------------------------- | ||
61 | |||
62 | 1994-09-13 started to write the driver, rescued most of my own | ||
63 | code (and Hans Alblas' memory buffer pool concept) from | ||
64 | an earlier project "sccdrv" which was initiated by | ||
65 | Guido ten Dolle. Not much of the old driver survived, | ||
66 | though. The first version I put my hands on was sccdrv1.3 | ||
67 | from August 1993. The memory buffer pool concept | ||
68 | appeared in an unauthorized sccdrv version (1.5) from | ||
69 | August 1994. | ||
70 | |||
71 | 1995-01-31 changed copyright notice to GPL without limitations. | ||
72 | |||
73 | . | ||
74 | . <SNIP> | ||
75 | . | ||
76 | |||
77 | 1996-10-05 New semester, new driver... | ||
78 | |||
79 | * KISS TNC emulator removed (TTY driver) | ||
80 | * Source moved to drivers/net/ | ||
81 | * Includes Z8530 defines from drivers/net/z8530.h | ||
82 | * Uses sk_buffer memory management | ||
83 | * Reduced overhead of /proc/net/z8530drv output | ||
84 | * Streamlined quite a lot things | ||
85 | * Invents brand new bugs... ;-) | ||
86 | |||
87 | The move to version number 3.0 reflects theses changes. | ||
88 | You can use 'kissbridge' if you need a KISS TNC emulator. | ||
89 | |||
90 | 1996-12-13 Fixed for Linux networking changes. (G4KLX) | ||
91 | 1997-01-08 Fixed the remaining problems. | ||
92 | 1997-04-02 Hopefully fixed the problems with the new *_timer() | ||
93 | routines, added calibration code. | ||
94 | 1997-10-12 Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO | ||
95 | 1998-01-29 Small fix to avoid lock-up on initialization | ||
96 | 1998-09-29 Fixed the "grouping" bugs, tx_inhibit works again, | ||
97 | using dev->tx_queue_len now instead of MAXQUEUE now. | ||
98 | 1998-10-21 Postponed the spinlock changes, would need a lot of | ||
99 | testing I currently don't have the time to. Softdcd doesn't | ||
100 | work. | ||
101 | 1998-11-04 Softdcd does not work correctly in DPLL mode, in fact it | ||
102 | never did. The DPLL locks on noise, the SYNC unit sees | ||
103 | flags that aren't... Restarting the DPLL does not help | ||
104 | either, it resynchronizes too slow and the first received | ||
105 | frame gets lost. | ||
106 | 2000-02-13 Fixed for new network driver interface changes, still | ||
107 | does TX timeouts itself since it uses its own queue | ||
108 | scheme. | ||
109 | |||
110 | Thanks to all who contributed to this driver with ideas and bug | ||
111 | reports! | ||
112 | |||
113 | NB -- if you find errors, change something, please let me know | ||
114 | first before you distribute it... And please don't touch | ||
115 | the version number. Just replace my callsign in | ||
116 | "v3.0.dl1bke" with your own. Just to avoid confusion... | ||
117 | |||
118 | If you want to add your modification to the linux distribution | ||
119 | please (!) contact me first. | ||
120 | |||
121 | New versions of the driver will be announced on the linux-hams | ||
122 | mailing list on vger.kernel.org. To subscribe send an e-mail | ||
123 | to majordomo@vger.kernel.org with the following line in | ||
124 | the body of the mail: | ||
125 | |||
126 | subscribe linux-hams | ||
127 | |||
128 | The content of the "Subject" field will be ignored. | ||
129 | |||
130 | vy 73, | ||
131 | Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org | ||
132 | AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU | ||
133 | Internet: jreuter@yaina.de | ||
134 | www : http://yaina.de/jreuter | ||
135 | */ | ||
136 | |||
137 | /* ----------------------------------------------------------------------- */ | ||
138 | |||
139 | #undef SCC_LDELAY /* slow it even a bit more down */ | ||
140 | #undef SCC_DONT_CHECK /* don't look if the SCCs you specified are available */ | ||
141 | |||
142 | #define SCC_MAXCHIPS 4 /* number of max. supported chips */ | ||
143 | #define SCC_BUFSIZE 384 /* must not exceed 4096 */ | ||
144 | #undef SCC_DEBUG | ||
145 | |||
146 | #define SCC_DEFAULT_CLOCK 4915200 | ||
147 | /* default pclock if nothing is specified */ | ||
148 | |||
149 | /* ----------------------------------------------------------------------- */ | ||
150 | |||
151 | #include <linux/config.h> | ||
152 | #include <linux/module.h> | ||
153 | #include <linux/errno.h> | ||
154 | #include <linux/signal.h> | ||
155 | #include <linux/timer.h> | ||
156 | #include <linux/interrupt.h> | ||
157 | #include <linux/ioport.h> | ||
158 | #include <linux/string.h> | ||
159 | #include <linux/in.h> | ||
160 | #include <linux/fcntl.h> | ||
161 | #include <linux/ptrace.h> | ||
162 | #include <linux/slab.h> | ||
163 | #include <linux/delay.h> | ||
164 | #include <linux/skbuff.h> | ||
165 | #include <linux/netdevice.h> | ||
166 | #include <linux/rtnetlink.h> | ||
167 | #include <linux/if_ether.h> | ||
168 | #include <linux/if_arp.h> | ||
169 | #include <linux/socket.h> | ||
170 | #include <linux/init.h> | ||
171 | #include <linux/scc.h> | ||
172 | #include <linux/ctype.h> | ||
173 | #include <linux/kernel.h> | ||
174 | #include <linux/proc_fs.h> | ||
175 | #include <linux/seq_file.h> | ||
176 | #include <linux/bitops.h> | ||
177 | |||
178 | #include <net/ax25.h> | ||
179 | |||
180 | #include <asm/irq.h> | ||
181 | #include <asm/system.h> | ||
182 | #include <asm/io.h> | ||
183 | #include <asm/uaccess.h> | ||
184 | |||
185 | #include "z8530.h" | ||
186 | |||
187 | static char banner[] __initdata = KERN_INFO "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n"; | ||
188 | |||
189 | static void t_dwait(unsigned long); | ||
190 | static void t_txdelay(unsigned long); | ||
191 | static void t_tail(unsigned long); | ||
192 | static void t_busy(unsigned long); | ||
193 | static void t_maxkeyup(unsigned long); | ||
194 | static void t_idle(unsigned long); | ||
195 | static void scc_tx_done(struct scc_channel *); | ||
196 | static void scc_start_tx_timer(struct scc_channel *, void (*)(unsigned long), unsigned long); | ||
197 | static void scc_start_maxkeyup(struct scc_channel *); | ||
198 | static void scc_start_defer(struct scc_channel *); | ||
199 | |||
200 | static void z8530_init(void); | ||
201 | |||
202 | static void init_channel(struct scc_channel *scc); | ||
203 | static void scc_key_trx (struct scc_channel *scc, char tx); | ||
204 | static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); | ||
205 | static void scc_init_timer(struct scc_channel *scc); | ||
206 | |||
207 | static int scc_net_alloc(const char *name, struct scc_channel *scc); | ||
208 | static void scc_net_setup(struct net_device *dev); | ||
209 | static int scc_net_open(struct net_device *dev); | ||
210 | static int scc_net_close(struct net_device *dev); | ||
211 | static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb); | ||
212 | static int scc_net_tx(struct sk_buff *skb, struct net_device *dev); | ||
213 | static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | ||
214 | static int scc_net_set_mac_address(struct net_device *dev, void *addr); | ||
215 | static struct net_device_stats * scc_net_get_stats(struct net_device *dev); | ||
216 | |||
217 | static unsigned char SCC_DriverName[] = "scc"; | ||
218 | |||
219 | static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS]; | ||
220 | |||
221 | static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS]; /* information per channel */ | ||
222 | |||
223 | static struct scc_ctrl { | ||
224 | io_port chan_A; | ||
225 | io_port chan_B; | ||
226 | int irq; | ||
227 | } SCC_ctrl[SCC_MAXCHIPS+1]; | ||
228 | |||
229 | static unsigned char Driver_Initialized; | ||
230 | static int Nchips; | ||
231 | static io_port Vector_Latch; | ||
232 | |||
233 | |||
234 | /* ******************************************************************** */ | ||
235 | /* * Port Access Functions * */ | ||
236 | /* ******************************************************************** */ | ||
237 | |||
238 | /* These provide interrupt save 2-step access to the Z8530 registers */ | ||
239 | |||
240 | static DEFINE_SPINLOCK(iolock); /* Guards paired accesses */ | ||
241 | |||
242 | static inline unsigned char InReg(io_port port, unsigned char reg) | ||
243 | { | ||
244 | unsigned long flags; | ||
245 | unsigned char r; | ||
246 | |||
247 | spin_lock_irqsave(&iolock, flags); | ||
248 | #ifdef SCC_LDELAY | ||
249 | Outb(port, reg); | ||
250 | udelay(SCC_LDELAY); | ||
251 | r=Inb(port); | ||
252 | udelay(SCC_LDELAY); | ||
253 | #else | ||
254 | Outb(port, reg); | ||
255 | r=Inb(port); | ||
256 | #endif | ||
257 | spin_unlock_irqrestore(&iolock, flags); | ||
258 | return r; | ||
259 | } | ||
260 | |||
261 | static inline void OutReg(io_port port, unsigned char reg, unsigned char val) | ||
262 | { | ||
263 | unsigned long flags; | ||
264 | |||
265 | spin_lock_irqsave(&iolock, flags); | ||
266 | #ifdef SCC_LDELAY | ||
267 | Outb(port, reg); udelay(SCC_LDELAY); | ||
268 | Outb(port, val); udelay(SCC_LDELAY); | ||
269 | #else | ||
270 | Outb(port, reg); | ||
271 | Outb(port, val); | ||
272 | #endif | ||
273 | spin_unlock_irqrestore(&iolock, flags); | ||
274 | } | ||
275 | |||
276 | static inline void wr(struct scc_channel *scc, unsigned char reg, | ||
277 | unsigned char val) | ||
278 | { | ||
279 | OutReg(scc->ctrl, reg, (scc->wreg[reg] = val)); | ||
280 | } | ||
281 | |||
282 | static inline void or(struct scc_channel *scc, unsigned char reg, unsigned char val) | ||
283 | { | ||
284 | OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val)); | ||
285 | } | ||
286 | |||
287 | static inline void cl(struct scc_channel *scc, unsigned char reg, unsigned char val) | ||
288 | { | ||
289 | OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val)); | ||
290 | } | ||
291 | |||
292 | /* ******************************************************************** */ | ||
293 | /* * Some useful macros * */ | ||
294 | /* ******************************************************************** */ | ||
295 | |||
296 | static inline void scc_discard_buffers(struct scc_channel *scc) | ||
297 | { | ||
298 | unsigned long flags; | ||
299 | |||
300 | spin_lock_irqsave(&scc->lock, flags); | ||
301 | if (scc->tx_buff != NULL) | ||
302 | { | ||
303 | dev_kfree_skb(scc->tx_buff); | ||
304 | scc->tx_buff = NULL; | ||
305 | } | ||
306 | |||
307 | while (skb_queue_len(&scc->tx_queue)) | ||
308 | dev_kfree_skb(skb_dequeue(&scc->tx_queue)); | ||
309 | |||
310 | spin_unlock_irqrestore(&scc->lock, flags); | ||
311 | } | ||
312 | |||
313 | |||
314 | |||
315 | /* ******************************************************************** */ | ||
316 | /* * Interrupt Service Routines * */ | ||
317 | /* ******************************************************************** */ | ||
318 | |||
319 | |||
320 | /* ----> subroutines for the interrupt handlers <---- */ | ||
321 | |||
322 | static inline void scc_notify(struct scc_channel *scc, int event) | ||
323 | { | ||
324 | struct sk_buff *skb; | ||
325 | char *bp; | ||
326 | |||
327 | if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA) | ||
328 | return; | ||
329 | |||
330 | skb = dev_alloc_skb(2); | ||
331 | if (skb != NULL) | ||
332 | { | ||
333 | bp = skb_put(skb, 2); | ||
334 | *bp++ = PARAM_HWEVENT; | ||
335 | *bp++ = event; | ||
336 | scc_net_rx(scc, skb); | ||
337 | } else | ||
338 | scc->stat.nospace++; | ||
339 | } | ||
340 | |||
341 | static inline void flush_rx_FIFO(struct scc_channel *scc) | ||
342 | { | ||
343 | int k; | ||
344 | |||
345 | for (k=0; k<3; k++) | ||
346 | Inb(scc->data); | ||
347 | |||
348 | if(scc->rx_buff != NULL) /* did we receive something? */ | ||
349 | { | ||
350 | scc->stat.rxerrs++; /* then count it as an error */ | ||
351 | dev_kfree_skb_irq(scc->rx_buff); | ||
352 | scc->rx_buff = NULL; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | static void start_hunt(struct scc_channel *scc) | ||
357 | { | ||
358 | if ((scc->modem.clocksrc != CLK_EXTERNAL)) | ||
359 | OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */ | ||
360 | or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */ | ||
361 | } | ||
362 | |||
363 | /* ----> four different interrupt handlers for Tx, Rx, changing of */ | ||
364 | /* DCD/CTS and Rx/Tx errors */ | ||
365 | |||
366 | /* Transmitter interrupt handler */ | ||
367 | static inline void scc_txint(struct scc_channel *scc) | ||
368 | { | ||
369 | struct sk_buff *skb; | ||
370 | |||
371 | scc->stat.txints++; | ||
372 | skb = scc->tx_buff; | ||
373 | |||
374 | /* send first octet */ | ||
375 | |||
376 | if (skb == NULL) | ||
377 | { | ||
378 | skb = skb_dequeue(&scc->tx_queue); | ||
379 | scc->tx_buff = skb; | ||
380 | netif_wake_queue(scc->dev); | ||
381 | |||
382 | if (skb == NULL) | ||
383 | { | ||
384 | scc_tx_done(scc); | ||
385 | Outb(scc->ctrl, RES_Tx_P); | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | if (skb->len == 0) /* Paranoia... */ | ||
390 | { | ||
391 | dev_kfree_skb_irq(skb); | ||
392 | scc->tx_buff = NULL; | ||
393 | scc_tx_done(scc); | ||
394 | Outb(scc->ctrl, RES_Tx_P); | ||
395 | return; | ||
396 | } | ||
397 | |||
398 | scc->stat.tx_state = TXS_ACTIVE; | ||
399 | |||
400 | OutReg(scc->ctrl, R0, RES_Tx_CRC); | ||
401 | /* reset CRC generator */ | ||
402 | or(scc,R10,ABUNDER); /* re-install underrun protection */ | ||
403 | Outb(scc->data,*skb->data); /* send byte */ | ||
404 | skb_pull(skb, 1); | ||
405 | |||
406 | if (!scc->enhanced) /* reset EOM latch */ | ||
407 | Outb(scc->ctrl,RES_EOM_L); | ||
408 | return; | ||
409 | } | ||
410 | |||
411 | /* End Of Frame... */ | ||
412 | |||
413 | if (skb->len == 0) | ||
414 | { | ||
415 | Outb(scc->ctrl, RES_Tx_P); /* reset pending int */ | ||
416 | cl(scc, R10, ABUNDER); /* send CRC */ | ||
417 | dev_kfree_skb_irq(skb); | ||
418 | scc->tx_buff = NULL; | ||
419 | scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */ | ||
420 | return; | ||
421 | } | ||
422 | |||
423 | /* send octet */ | ||
424 | |||
425 | Outb(scc->data,*skb->data); | ||
426 | skb_pull(skb, 1); | ||
427 | } | ||
428 | |||
429 | |||
430 | /* External/Status interrupt handler */ | ||
431 | static inline void scc_exint(struct scc_channel *scc) | ||
432 | { | ||
433 | unsigned char status,changes,chg_and_stat; | ||
434 | |||
435 | scc->stat.exints++; | ||
436 | |||
437 | status = InReg(scc->ctrl,R0); | ||
438 | changes = status ^ scc->status; | ||
439 | chg_and_stat = changes & status; | ||
440 | |||
441 | /* ABORT: generated whenever DCD drops while receiving */ | ||
442 | |||
443 | if (chg_and_stat & BRK_ABRT) /* Received an ABORT */ | ||
444 | flush_rx_FIFO(scc); | ||
445 | |||
446 | /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */ | ||
447 | |||
448 | if ((changes & SYNC_HUNT) && scc->kiss.softdcd) | ||
449 | { | ||
450 | if (status & SYNC_HUNT) | ||
451 | { | ||
452 | scc->dcd = 0; | ||
453 | flush_rx_FIFO(scc); | ||
454 | if ((scc->modem.clocksrc != CLK_EXTERNAL)) | ||
455 | OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */ | ||
456 | } else { | ||
457 | scc->dcd = 1; | ||
458 | } | ||
459 | |||
460 | scc_notify(scc, scc->dcd? HWEV_DCD_OFF:HWEV_DCD_ON); | ||
461 | } | ||
462 | |||
463 | /* DCD: on = start to receive packet, off = ABORT condition */ | ||
464 | /* (a successfully received packet generates a special condition int) */ | ||
465 | |||
466 | if((changes & DCD) && !scc->kiss.softdcd) /* DCD input changed state */ | ||
467 | { | ||
468 | if(status & DCD) /* DCD is now ON */ | ||
469 | { | ||
470 | start_hunt(scc); | ||
471 | scc->dcd = 1; | ||
472 | } else { /* DCD is now OFF */ | ||
473 | cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */ | ||
474 | flush_rx_FIFO(scc); | ||
475 | scc->dcd = 0; | ||
476 | } | ||
477 | |||
478 | scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF); | ||
479 | } | ||
480 | |||
481 | #ifdef notdef | ||
482 | /* CTS: use external TxDelay (what's that good for?!) | ||
483 | * Anyway: If we _could_ use it (BayCom USCC uses CTS for | ||
484 | * own purposes) we _should_ use the "autoenable" feature | ||
485 | * of the Z8530 and not this interrupt... | ||
486 | */ | ||
487 | |||
488 | if (chg_and_stat & CTS) /* CTS is now ON */ | ||
489 | { | ||
490 | if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */ | ||
491 | scc_start_tx_timer(scc, t_txdelay, 0); | ||
492 | } | ||
493 | #endif | ||
494 | |||
495 | if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM)) | ||
496 | { | ||
497 | scc->stat.tx_under++; /* oops, an underrun! count 'em */ | ||
498 | Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */ | ||
499 | |||
500 | if (scc->tx_buff != NULL) | ||
501 | { | ||
502 | dev_kfree_skb_irq(scc->tx_buff); | ||
503 | scc->tx_buff = NULL; | ||
504 | } | ||
505 | |||
506 | or(scc,R10,ABUNDER); | ||
507 | scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */ | ||
508 | } | ||
509 | |||
510 | scc->status = status; | ||
511 | Outb(scc->ctrl,RES_EXT_INT); | ||
512 | } | ||
513 | |||
514 | |||
515 | /* Receiver interrupt handler */ | ||
516 | static inline void scc_rxint(struct scc_channel *scc) | ||
517 | { | ||
518 | struct sk_buff *skb; | ||
519 | |||
520 | scc->stat.rxints++; | ||
521 | |||
522 | if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF) | ||
523 | { | ||
524 | Inb(scc->data); /* discard char */ | ||
525 | or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ | ||
526 | return; | ||
527 | } | ||
528 | |||
529 | skb = scc->rx_buff; | ||
530 | |||
531 | if (skb == NULL) | ||
532 | { | ||
533 | skb = dev_alloc_skb(scc->stat.bufsize); | ||
534 | if (skb == NULL) | ||
535 | { | ||
536 | scc->dev_stat.rx_dropped++; | ||
537 | scc->stat.nospace++; | ||
538 | Inb(scc->data); | ||
539 | or(scc, R3, ENT_HM); | ||
540 | return; | ||
541 | } | ||
542 | |||
543 | scc->rx_buff = skb; | ||
544 | *(skb_put(skb, 1)) = 0; /* KISS data */ | ||
545 | } | ||
546 | |||
547 | if (skb->len >= scc->stat.bufsize) | ||
548 | { | ||
549 | #ifdef notdef | ||
550 | printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n"); | ||
551 | #endif | ||
552 | dev_kfree_skb_irq(skb); | ||
553 | scc->rx_buff = NULL; | ||
554 | Inb(scc->data); | ||
555 | or(scc, R3, ENT_HM); | ||
556 | return; | ||
557 | } | ||
558 | |||
559 | *(skb_put(skb, 1)) = Inb(scc->data); | ||
560 | } | ||
561 | |||
562 | |||
563 | /* Receive Special Condition interrupt handler */ | ||
564 | static inline void scc_spint(struct scc_channel *scc) | ||
565 | { | ||
566 | unsigned char status; | ||
567 | struct sk_buff *skb; | ||
568 | |||
569 | scc->stat.spints++; | ||
570 | |||
571 | status = InReg(scc->ctrl,R1); /* read receiver status */ | ||
572 | |||
573 | Inb(scc->data); /* throw away Rx byte */ | ||
574 | skb = scc->rx_buff; | ||
575 | |||
576 | if(status & Rx_OVR) /* receiver overrun */ | ||
577 | { | ||
578 | scc->stat.rx_over++; /* count them */ | ||
579 | or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ | ||
580 | |||
581 | if (skb != NULL) | ||
582 | dev_kfree_skb_irq(skb); | ||
583 | scc->rx_buff = skb = NULL; | ||
584 | } | ||
585 | |||
586 | if(status & END_FR && skb != NULL) /* end of frame */ | ||
587 | { | ||
588 | /* CRC okay, frame ends on 8 bit boundary and received something ? */ | ||
589 | |||
590 | if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0) | ||
591 | { | ||
592 | /* ignore last received byte (first of the CRC bytes) */ | ||
593 | skb_trim(skb, skb->len-1); | ||
594 | scc_net_rx(scc, skb); | ||
595 | scc->rx_buff = NULL; | ||
596 | scc->stat.rxframes++; | ||
597 | } else { /* a bad frame */ | ||
598 | dev_kfree_skb_irq(skb); | ||
599 | scc->rx_buff = NULL; | ||
600 | scc->stat.rxerrs++; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | Outb(scc->ctrl,ERR_RES); | ||
605 | } | ||
606 | |||
607 | |||
608 | /* ----> interrupt service routine for the Z8530 <---- */ | ||
609 | |||
610 | static void scc_isr_dispatch(struct scc_channel *scc, int vector) | ||
611 | { | ||
612 | spin_lock(&scc->lock); | ||
613 | switch (vector & VECTOR_MASK) | ||
614 | { | ||
615 | case TXINT: scc_txint(scc); break; | ||
616 | case EXINT: scc_exint(scc); break; | ||
617 | case RXINT: scc_rxint(scc); break; | ||
618 | case SPINT: scc_spint(scc); break; | ||
619 | } | ||
620 | spin_unlock(&scc->lock); | ||
621 | } | ||
622 | |||
623 | /* If the card has a latch for the interrupt vector (like the PA0HZP card) | ||
624 | use it to get the number of the chip that generated the int. | ||
625 | If not: poll all defined chips. | ||
626 | */ | ||
627 | |||
628 | #define SCC_IRQTIMEOUT 30000 | ||
629 | |||
630 | static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
631 | { | ||
632 | unsigned char vector; | ||
633 | struct scc_channel *scc; | ||
634 | struct scc_ctrl *ctrl; | ||
635 | int k; | ||
636 | |||
637 | if (Vector_Latch) | ||
638 | { | ||
639 | for(k=0; k < SCC_IRQTIMEOUT; k++) | ||
640 | { | ||
641 | Outb(Vector_Latch, 0); /* Generate INTACK */ | ||
642 | |||
643 | /* Read the vector */ | ||
644 | if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break; | ||
645 | if (vector & 0x01) break; | ||
646 | |||
647 | scc=&SCC_Info[vector >> 3 ^ 0x01]; | ||
648 | if (!scc->dev) break; | ||
649 | |||
650 | scc_isr_dispatch(scc, vector); | ||
651 | |||
652 | OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */ | ||
653 | } | ||
654 | |||
655 | if (k == SCC_IRQTIMEOUT) | ||
656 | printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n"); | ||
657 | |||
658 | return IRQ_HANDLED; | ||
659 | } | ||
660 | |||
661 | /* Find the SCC generating the interrupt by polling all attached SCCs | ||
662 | * reading RR3A (the interrupt pending register) | ||
663 | */ | ||
664 | |||
665 | ctrl = SCC_ctrl; | ||
666 | while (ctrl->chan_A) | ||
667 | { | ||
668 | if (ctrl->irq != irq) | ||
669 | { | ||
670 | ctrl++; | ||
671 | continue; | ||
672 | } | ||
673 | |||
674 | scc = NULL; | ||
675 | for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++) | ||
676 | { | ||
677 | vector=InReg(ctrl->chan_B,R2); /* Read the vector */ | ||
678 | if (vector & 0x01) break; | ||
679 | |||
680 | scc = &SCC_Info[vector >> 3 ^ 0x01]; | ||
681 | if (!scc->dev) break; | ||
682 | |||
683 | scc_isr_dispatch(scc, vector); | ||
684 | } | ||
685 | |||
686 | if (k == SCC_IRQTIMEOUT) | ||
687 | { | ||
688 | printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n"); | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | /* This looks weird and it is. At least the BayCom USCC doesn't | ||
693 | * use the Interrupt Daisy Chain, thus we'll have to start | ||
694 | * all over again to be sure not to miss an interrupt from | ||
695 | * (any of) the other chip(s)... | ||
696 | * Honestly, the situation *is* braindamaged... | ||
697 | */ | ||
698 | |||
699 | if (scc != NULL) | ||
700 | { | ||
701 | OutReg(scc->ctrl,R0,RES_H_IUS); | ||
702 | ctrl = SCC_ctrl; | ||
703 | } else | ||
704 | ctrl++; | ||
705 | } | ||
706 | return IRQ_HANDLED; | ||
707 | } | ||
708 | |||
709 | |||
710 | |||
711 | /* ******************************************************************** */ | ||
712 | /* * Init Channel */ | ||
713 | /* ******************************************************************** */ | ||
714 | |||
715 | |||
716 | /* ----> set SCC channel speed <---- */ | ||
717 | |||
718 | static inline void set_brg(struct scc_channel *scc, unsigned int tc) | ||
719 | { | ||
720 | cl(scc,R14,BRENABL); /* disable baudrate generator */ | ||
721 | wr(scc,R12,tc & 255); /* brg rate LOW */ | ||
722 | wr(scc,R13,tc >> 8); /* brg rate HIGH */ | ||
723 | or(scc,R14,BRENABL); /* enable baudrate generator */ | ||
724 | } | ||
725 | |||
726 | static inline void set_speed(struct scc_channel *scc) | ||
727 | { | ||
728 | unsigned long flags; | ||
729 | spin_lock_irqsave(&scc->lock, flags); | ||
730 | |||
731 | if (scc->modem.speed > 0) /* paranoia... */ | ||
732 | set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2); | ||
733 | |||
734 | spin_unlock_irqrestore(&scc->lock, flags); | ||
735 | } | ||
736 | |||
737 | |||
738 | /* ----> initialize a SCC channel <---- */ | ||
739 | |||
740 | static inline void init_brg(struct scc_channel *scc) | ||
741 | { | ||
742 | wr(scc, R14, BRSRC); /* BRG source = PCLK */ | ||
743 | OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */ | ||
744 | OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */ | ||
745 | } | ||
746 | |||
747 | /* | ||
748 | * Initialization according to the Z8530 manual (SGS-Thomson's version): | ||
749 | * | ||
750 | * 1. Modes and constants | ||
751 | * | ||
752 | * WR9 11000000 chip reset | ||
753 | * WR4 XXXXXXXX Tx/Rx control, async or sync mode | ||
754 | * WR1 0XX00X00 select W/REQ (optional) | ||
755 | * WR2 XXXXXXXX program interrupt vector | ||
756 | * WR3 XXXXXXX0 select Rx control | ||
757 | * WR5 XXXX0XXX select Tx control | ||
758 | * WR6 XXXXXXXX sync character | ||
759 | * WR7 XXXXXXXX sync character | ||
760 | * WR9 000X0XXX select interrupt control | ||
761 | * WR10 XXXXXXXX miscellaneous control (optional) | ||
762 | * WR11 XXXXXXXX clock control | ||
763 | * WR12 XXXXXXXX time constant lower byte (optional) | ||
764 | * WR13 XXXXXXXX time constant upper byte (optional) | ||
765 | * WR14 XXXXXXX0 miscellaneous control | ||
766 | * WR14 XXXSSSSS commands (optional) | ||
767 | * | ||
768 | * 2. Enables | ||
769 | * | ||
770 | * WR14 000SSSS1 baud rate enable | ||
771 | * WR3 SSSSSSS1 Rx enable | ||
772 | * WR5 SSSS1SSS Tx enable | ||
773 | * WR0 10000000 reset Tx CRG (optional) | ||
774 | * WR1 XSS00S00 DMA enable (optional) | ||
775 | * | ||
776 | * 3. Interrupt status | ||
777 | * | ||
778 | * WR15 XXXXXXXX enable external/status | ||
779 | * WR0 00010000 reset external status | ||
780 | * WR0 00010000 reset external status twice | ||
781 | * WR1 SSSXXSXX enable Rx, Tx and Ext/status | ||
782 | * WR9 000SXSSS enable master interrupt enable | ||
783 | * | ||
784 | * 1 = set to one, 0 = reset to zero | ||
785 | * X = user defined, S = same as previous init | ||
786 | * | ||
787 | * | ||
788 | * Note that the implementation differs in some points from above scheme. | ||
789 | * | ||
790 | */ | ||
791 | |||
792 | static void init_channel(struct scc_channel *scc) | ||
793 | { | ||
794 | del_timer(&scc->tx_t); | ||
795 | del_timer(&scc->tx_wdog); | ||
796 | |||
797 | disable_irq(scc->irq); | ||
798 | |||
799 | wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */ | ||
800 | wr(scc,R1,0); /* no W/REQ operation */ | ||
801 | wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */ | ||
802 | wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */ | ||
803 | wr(scc,R6,0); /* SDLC address zero (not used) */ | ||
804 | wr(scc,R7,FLAG); /* SDLC flag value */ | ||
805 | wr(scc,R9,VIS); /* vector includes status */ | ||
806 | wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */ | ||
807 | wr(scc,R14, 0); | ||
808 | |||
809 | |||
810 | /* set clock sources: | ||
811 | |||
812 | CLK_DPLL: normal halfduplex operation | ||
813 | |||
814 | RxClk: use DPLL | ||
815 | TxClk: use DPLL | ||
816 | TRxC mode DPLL output | ||
817 | |||
818 | CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem) | ||
819 | |||
820 | BayCom: others: | ||
821 | |||
822 | TxClk = pin RTxC TxClk = pin TRxC | ||
823 | RxClk = pin TRxC RxClk = pin RTxC | ||
824 | |||
825 | |||
826 | CLK_DIVIDER: | ||
827 | RxClk = use DPLL | ||
828 | TxClk = pin RTxC | ||
829 | |||
830 | BayCom: others: | ||
831 | pin TRxC = DPLL pin TRxC = BRG | ||
832 | (RxClk * 1) (RxClk * 32) | ||
833 | */ | ||
834 | |||
835 | |||
836 | switch(scc->modem.clocksrc) | ||
837 | { | ||
838 | case CLK_DPLL: | ||
839 | wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); | ||
840 | init_brg(scc); | ||
841 | break; | ||
842 | |||
843 | case CLK_DIVIDER: | ||
844 | wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI); | ||
845 | init_brg(scc); | ||
846 | break; | ||
847 | |||
848 | case CLK_EXTERNAL: | ||
849 | wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP); | ||
850 | OutReg(scc->ctrl, R14, DISDPLL); | ||
851 | break; | ||
852 | |||
853 | } | ||
854 | |||
855 | set_speed(scc); /* set baudrate */ | ||
856 | |||
857 | if(scc->enhanced) | ||
858 | { | ||
859 | or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */ | ||
860 | wr(scc,R7,AUTOEOM); | ||
861 | } | ||
862 | |||
863 | if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD)) | ||
864 | /* DCD is now ON */ | ||
865 | { | ||
866 | start_hunt(scc); | ||
867 | } | ||
868 | |||
869 | /* enable ABORT, DCD & SYNC/HUNT interrupts */ | ||
870 | |||
871 | wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE)); | ||
872 | |||
873 | Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ | ||
874 | Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */ | ||
875 | |||
876 | or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */ | ||
877 | |||
878 | scc->status = InReg(scc->ctrl,R0); /* read initial status */ | ||
879 | |||
880 | or(scc,R9,MIE); /* master interrupt enable */ | ||
881 | |||
882 | scc_init_timer(scc); | ||
883 | |||
884 | enable_irq(scc->irq); | ||
885 | } | ||
886 | |||
887 | |||
888 | |||
889 | |||
890 | /* ******************************************************************** */ | ||
891 | /* * SCC timer functions * */ | ||
892 | /* ******************************************************************** */ | ||
893 | |||
894 | |||
895 | /* ----> scc_key_trx sets the time constant for the baudrate | ||
896 | generator and keys the transmitter <---- */ | ||
897 | |||
898 | static void scc_key_trx(struct scc_channel *scc, char tx) | ||
899 | { | ||
900 | unsigned int time_const; | ||
901 | |||
902 | if (scc->brand & PRIMUS) | ||
903 | Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0)); | ||
904 | |||
905 | if (scc->modem.speed < 300) | ||
906 | scc->modem.speed = 1200; | ||
907 | |||
908 | time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2; | ||
909 | |||
910 | disable_irq(scc->irq); | ||
911 | |||
912 | if (tx) | ||
913 | { | ||
914 | or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */ | ||
915 | or(scc, R15, TxUIE); | ||
916 | } | ||
917 | |||
918 | if (scc->modem.clocksrc == CLK_DPLL) | ||
919 | { /* force simplex operation */ | ||
920 | if (tx) | ||
921 | { | ||
922 | #ifdef CONFIG_SCC_TRXECHO | ||
923 | cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */ | ||
924 | cl(scc, R15, DCDIE|SYNCIE); /* No DCD changes, please */ | ||
925 | #endif | ||
926 | set_brg(scc, time_const); /* reprogram baudrate generator */ | ||
927 | |||
928 | /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */ | ||
929 | wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR); | ||
930 | |||
931 | /* By popular demand: tx_inhibit */ | ||
932 | if (scc->kiss.tx_inhibit) | ||
933 | { | ||
934 | or(scc,R5, TxENAB); | ||
935 | scc->wreg[R5] |= RTS; | ||
936 | } else { | ||
937 | or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */ | ||
938 | } | ||
939 | } else { | ||
940 | cl(scc,R5,RTS|TxENAB); | ||
941 | |||
942 | set_brg(scc, time_const); /* reprogram baudrate generator */ | ||
943 | |||
944 | /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */ | ||
945 | wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP); | ||
946 | |||
947 | #ifndef CONFIG_SCC_TRXECHO | ||
948 | if (scc->kiss.softdcd) | ||
949 | #endif | ||
950 | { | ||
951 | or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE); | ||
952 | start_hunt(scc); | ||
953 | } | ||
954 | } | ||
955 | } else { | ||
956 | if (tx) | ||
957 | { | ||
958 | #ifdef CONFIG_SCC_TRXECHO | ||
959 | if (scc->kiss.fulldup == KISS_DUPLEX_HALF) | ||
960 | { | ||
961 | cl(scc, R3, RxENABLE); | ||
962 | cl(scc, R15, DCDIE|SYNCIE); | ||
963 | } | ||
964 | #endif | ||
965 | |||
966 | if (scc->kiss.tx_inhibit) | ||
967 | { | ||
968 | or(scc,R5, TxENAB); | ||
969 | scc->wreg[R5] |= RTS; | ||
970 | } else { | ||
971 | or(scc,R5,RTS|TxENAB); /* enable tx */ | ||
972 | } | ||
973 | } else { | ||
974 | cl(scc,R5,RTS|TxENAB); /* disable tx */ | ||
975 | |||
976 | if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) && | ||
977 | #ifndef CONFIG_SCC_TRXECHO | ||
978 | scc->kiss.softdcd) | ||
979 | #else | ||
980 | 1) | ||
981 | #endif | ||
982 | { | ||
983 | or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE); | ||
984 | start_hunt(scc); | ||
985 | } | ||
986 | } | ||
987 | } | ||
988 | |||
989 | enable_irq(scc->irq); | ||
990 | } | ||
991 | |||
992 | |||
993 | /* ----> SCC timer interrupt handler and friends. <---- */ | ||
994 | |||
995 | static void __scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when) | ||
996 | { | ||
997 | del_timer(&scc->tx_t); | ||
998 | |||
999 | if (when == 0) | ||
1000 | { | ||
1001 | handler((unsigned long) scc); | ||
1002 | } else | ||
1003 | if (when != TIMER_OFF) | ||
1004 | { | ||
1005 | scc->tx_t.data = (unsigned long) scc; | ||
1006 | scc->tx_t.function = handler; | ||
1007 | scc->tx_t.expires = jiffies + (when*HZ)/100; | ||
1008 | add_timer(&scc->tx_t); | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when) | ||
1013 | { | ||
1014 | unsigned long flags; | ||
1015 | |||
1016 | spin_lock_irqsave(&scc->lock, flags); | ||
1017 | __scc_start_tx_timer(scc, handler, when); | ||
1018 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1019 | } | ||
1020 | |||
1021 | static void scc_start_defer(struct scc_channel *scc) | ||
1022 | { | ||
1023 | unsigned long flags; | ||
1024 | |||
1025 | spin_lock_irqsave(&scc->lock, flags); | ||
1026 | del_timer(&scc->tx_wdog); | ||
1027 | |||
1028 | if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF) | ||
1029 | { | ||
1030 | scc->tx_wdog.data = (unsigned long) scc; | ||
1031 | scc->tx_wdog.function = t_busy; | ||
1032 | scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer; | ||
1033 | add_timer(&scc->tx_wdog); | ||
1034 | } | ||
1035 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1036 | } | ||
1037 | |||
1038 | static void scc_start_maxkeyup(struct scc_channel *scc) | ||
1039 | { | ||
1040 | unsigned long flags; | ||
1041 | |||
1042 | spin_lock_irqsave(&scc->lock, flags); | ||
1043 | del_timer(&scc->tx_wdog); | ||
1044 | |||
1045 | if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF) | ||
1046 | { | ||
1047 | scc->tx_wdog.data = (unsigned long) scc; | ||
1048 | scc->tx_wdog.function = t_maxkeyup; | ||
1049 | scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup; | ||
1050 | add_timer(&scc->tx_wdog); | ||
1051 | } | ||
1052 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1053 | } | ||
1054 | |||
1055 | /* | ||
1056 | * This is called from scc_txint() when there are no more frames to send. | ||
1057 | * Not exactly a timer function, but it is a close friend of the family... | ||
1058 | */ | ||
1059 | |||
1060 | static void scc_tx_done(struct scc_channel *scc) | ||
1061 | { | ||
1062 | /* | ||
1063 | * trx remains keyed in fulldup mode 2 until t_idle expires. | ||
1064 | */ | ||
1065 | |||
1066 | switch (scc->kiss.fulldup) | ||
1067 | { | ||
1068 | case KISS_DUPLEX_LINK: | ||
1069 | scc->stat.tx_state = TXS_IDLE2; | ||
1070 | if (scc->kiss.idletime != TIMER_OFF) | ||
1071 | scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100); | ||
1072 | break; | ||
1073 | case KISS_DUPLEX_OPTIMA: | ||
1074 | scc_notify(scc, HWEV_ALL_SENT); | ||
1075 | break; | ||
1076 | default: | ||
1077 | scc->stat.tx_state = TXS_BUSY; | ||
1078 | scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); | ||
1079 | } | ||
1080 | |||
1081 | netif_wake_queue(scc->dev); | ||
1082 | } | ||
1083 | |||
1084 | |||
1085 | static unsigned char Rand = 17; | ||
1086 | |||
1087 | static inline int is_grouped(struct scc_channel *scc) | ||
1088 | { | ||
1089 | int k; | ||
1090 | struct scc_channel *scc2; | ||
1091 | unsigned char grp1, grp2; | ||
1092 | |||
1093 | grp1 = scc->kiss.group; | ||
1094 | |||
1095 | for (k = 0; k < (Nchips * 2); k++) | ||
1096 | { | ||
1097 | scc2 = &SCC_Info[k]; | ||
1098 | grp2 = scc2->kiss.group; | ||
1099 | |||
1100 | if (scc2 == scc || !(scc2->dev && grp2)) | ||
1101 | continue; | ||
1102 | |||
1103 | if ((grp1 & 0x3f) == (grp2 & 0x3f)) | ||
1104 | { | ||
1105 | if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) ) | ||
1106 | return 1; | ||
1107 | |||
1108 | if ( (grp1 & RXGROUP) && scc2->dcd ) | ||
1109 | return 1; | ||
1110 | } | ||
1111 | } | ||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | /* DWAIT and SLOTTIME expired | ||
1116 | * | ||
1117 | * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer | ||
1118 | * else key trx and start txdelay | ||
1119 | * fulldup == 1: key trx and start txdelay | ||
1120 | * fulldup == 2: mintime expired, reset status or key trx and start txdelay | ||
1121 | */ | ||
1122 | |||
1123 | static void t_dwait(unsigned long channel) | ||
1124 | { | ||
1125 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1126 | |||
1127 | if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ | ||
1128 | { | ||
1129 | if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */ | ||
1130 | { | ||
1131 | scc->stat.tx_state = TXS_IDLE; | ||
1132 | netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */ | ||
1133 | return; | ||
1134 | } | ||
1135 | |||
1136 | scc->stat.tx_state = TXS_BUSY; | ||
1137 | } | ||
1138 | |||
1139 | if (scc->kiss.fulldup == KISS_DUPLEX_HALF) | ||
1140 | { | ||
1141 | Rand = Rand * 17 + 31; | ||
1142 | |||
1143 | if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) ) | ||
1144 | { | ||
1145 | scc_start_defer(scc); | ||
1146 | scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime); | ||
1147 | return ; | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | if ( !(scc->wreg[R5] & RTS) ) | ||
1152 | { | ||
1153 | scc_key_trx(scc, TX_ON); | ||
1154 | scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); | ||
1155 | } else { | ||
1156 | scc_start_tx_timer(scc, t_txdelay, 0); | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | |||
1161 | /* TXDELAY expired | ||
1162 | * | ||
1163 | * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog. | ||
1164 | */ | ||
1165 | |||
1166 | static void t_txdelay(unsigned long channel) | ||
1167 | { | ||
1168 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1169 | |||
1170 | scc_start_maxkeyup(scc); | ||
1171 | |||
1172 | if (scc->tx_buff == NULL) | ||
1173 | { | ||
1174 | disable_irq(scc->irq); | ||
1175 | scc_txint(scc); | ||
1176 | enable_irq(scc->irq); | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | |||
1181 | /* TAILTIME expired | ||
1182 | * | ||
1183 | * switch off transmitter. If we were stopped by Maxkeyup restart | ||
1184 | * transmission after 'mintime' seconds | ||
1185 | */ | ||
1186 | |||
1187 | static void t_tail(unsigned long channel) | ||
1188 | { | ||
1189 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1190 | unsigned long flags; | ||
1191 | |||
1192 | spin_lock_irqsave(&scc->lock, flags); | ||
1193 | del_timer(&scc->tx_wdog); | ||
1194 | scc_key_trx(scc, TX_OFF); | ||
1195 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1196 | |||
1197 | if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */ | ||
1198 | { | ||
1199 | scc->stat.tx_state = TXS_WAIT; | ||
1200 | scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); | ||
1201 | return; | ||
1202 | } | ||
1203 | |||
1204 | scc->stat.tx_state = TXS_IDLE; | ||
1205 | netif_wake_queue(scc->dev); | ||
1206 | } | ||
1207 | |||
1208 | |||
1209 | /* BUSY timeout | ||
1210 | * | ||
1211 | * throw away send buffers if DCD remains active too long. | ||
1212 | */ | ||
1213 | |||
1214 | static void t_busy(unsigned long channel) | ||
1215 | { | ||
1216 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1217 | |||
1218 | del_timer(&scc->tx_t); | ||
1219 | netif_stop_queue(scc->dev); /* don't pile on the wabbit! */ | ||
1220 | |||
1221 | scc_discard_buffers(scc); | ||
1222 | scc->stat.txerrs++; | ||
1223 | scc->stat.tx_state = TXS_IDLE; | ||
1224 | |||
1225 | netif_wake_queue(scc->dev); | ||
1226 | } | ||
1227 | |||
1228 | /* MAXKEYUP timeout | ||
1229 | * | ||
1230 | * this is our watchdog. | ||
1231 | */ | ||
1232 | |||
1233 | static void t_maxkeyup(unsigned long channel) | ||
1234 | { | ||
1235 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1236 | unsigned long flags; | ||
1237 | |||
1238 | spin_lock_irqsave(&scc->lock, flags); | ||
1239 | /* | ||
1240 | * let things settle down before we start to | ||
1241 | * accept new data. | ||
1242 | */ | ||
1243 | |||
1244 | netif_stop_queue(scc->dev); | ||
1245 | scc_discard_buffers(scc); | ||
1246 | |||
1247 | del_timer(&scc->tx_t); | ||
1248 | |||
1249 | cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */ | ||
1250 | cl(scc, R15, TxUIE); /* count it. */ | ||
1251 | OutReg(scc->ctrl, R0, RES_Tx_P); | ||
1252 | |||
1253 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1254 | |||
1255 | scc->stat.txerrs++; | ||
1256 | scc->stat.tx_state = TXS_TIMEOUT; | ||
1257 | scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); | ||
1258 | } | ||
1259 | |||
1260 | /* IDLE timeout | ||
1261 | * | ||
1262 | * in fulldup mode 2 it keys down the transmitter after 'idle' seconds | ||
1263 | * of inactivity. We will not restart transmission before 'mintime' | ||
1264 | * expires. | ||
1265 | */ | ||
1266 | |||
1267 | static void t_idle(unsigned long channel) | ||
1268 | { | ||
1269 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1270 | |||
1271 | del_timer(&scc->tx_wdog); | ||
1272 | |||
1273 | scc_key_trx(scc, TX_OFF); | ||
1274 | if(scc->kiss.mintime) | ||
1275 | scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); | ||
1276 | scc->stat.tx_state = TXS_WAIT; | ||
1277 | } | ||
1278 | |||
1279 | static void scc_init_timer(struct scc_channel *scc) | ||
1280 | { | ||
1281 | unsigned long flags; | ||
1282 | |||
1283 | spin_lock_irqsave(&scc->lock, flags); | ||
1284 | scc->stat.tx_state = TXS_IDLE; | ||
1285 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1286 | } | ||
1287 | |||
1288 | |||
1289 | /* ******************************************************************** */ | ||
1290 | /* * Set/get L1 parameters * */ | ||
1291 | /* ******************************************************************** */ | ||
1292 | |||
1293 | |||
1294 | /* | ||
1295 | * this will set the "hardware" parameters through KISS commands or ioctl() | ||
1296 | */ | ||
1297 | |||
1298 | #define CAST(x) (unsigned long)(x) | ||
1299 | |||
1300 | static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg) | ||
1301 | { | ||
1302 | switch (cmd) | ||
1303 | { | ||
1304 | case PARAM_TXDELAY: scc->kiss.txdelay=arg; break; | ||
1305 | case PARAM_PERSIST: scc->kiss.persist=arg; break; | ||
1306 | case PARAM_SLOTTIME: scc->kiss.slottime=arg; break; | ||
1307 | case PARAM_TXTAIL: scc->kiss.tailtime=arg; break; | ||
1308 | case PARAM_FULLDUP: scc->kiss.fulldup=arg; break; | ||
1309 | case PARAM_DTR: break; /* does someone need this? */ | ||
1310 | case PARAM_GROUP: scc->kiss.group=arg; break; | ||
1311 | case PARAM_IDLE: scc->kiss.idletime=arg; break; | ||
1312 | case PARAM_MIN: scc->kiss.mintime=arg; break; | ||
1313 | case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break; | ||
1314 | case PARAM_WAIT: scc->kiss.waittime=arg; break; | ||
1315 | case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break; | ||
1316 | case PARAM_TX: scc->kiss.tx_inhibit=arg; break; | ||
1317 | |||
1318 | case PARAM_SOFTDCD: | ||
1319 | scc->kiss.softdcd=arg; | ||
1320 | if (arg) | ||
1321 | { | ||
1322 | or(scc, R15, SYNCIE); | ||
1323 | cl(scc, R15, DCDIE); | ||
1324 | start_hunt(scc); | ||
1325 | } else { | ||
1326 | or(scc, R15, DCDIE); | ||
1327 | cl(scc, R15, SYNCIE); | ||
1328 | } | ||
1329 | break; | ||
1330 | |||
1331 | case PARAM_SPEED: | ||
1332 | if (arg < 256) | ||
1333 | scc->modem.speed=arg*100; | ||
1334 | else | ||
1335 | scc->modem.speed=arg; | ||
1336 | |||
1337 | if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */ | ||
1338 | set_speed(scc); | ||
1339 | break; | ||
1340 | |||
1341 | case PARAM_RTS: | ||
1342 | if ( !(scc->wreg[R5] & RTS) ) | ||
1343 | { | ||
1344 | if (arg != TX_OFF) | ||
1345 | scc_key_trx(scc, TX_ON); | ||
1346 | scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); | ||
1347 | } else { | ||
1348 | if (arg == TX_OFF) | ||
1349 | { | ||
1350 | scc->stat.tx_state = TXS_BUSY; | ||
1351 | scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); | ||
1352 | } | ||
1353 | } | ||
1354 | break; | ||
1355 | |||
1356 | case PARAM_HWEVENT: | ||
1357 | scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF); | ||
1358 | break; | ||
1359 | |||
1360 | default: return -EINVAL; | ||
1361 | } | ||
1362 | |||
1363 | return 0; | ||
1364 | } | ||
1365 | |||
1366 | |||
1367 | |||
1368 | static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd) | ||
1369 | { | ||
1370 | switch (cmd) | ||
1371 | { | ||
1372 | case PARAM_TXDELAY: return CAST(scc->kiss.txdelay); | ||
1373 | case PARAM_PERSIST: return CAST(scc->kiss.persist); | ||
1374 | case PARAM_SLOTTIME: return CAST(scc->kiss.slottime); | ||
1375 | case PARAM_TXTAIL: return CAST(scc->kiss.tailtime); | ||
1376 | case PARAM_FULLDUP: return CAST(scc->kiss.fulldup); | ||
1377 | case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd); | ||
1378 | case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0); | ||
1379 | case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0); | ||
1380 | case PARAM_SPEED: return CAST(scc->modem.speed); | ||
1381 | case PARAM_GROUP: return CAST(scc->kiss.group); | ||
1382 | case PARAM_IDLE: return CAST(scc->kiss.idletime); | ||
1383 | case PARAM_MIN: return CAST(scc->kiss.mintime); | ||
1384 | case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup); | ||
1385 | case PARAM_WAIT: return CAST(scc->kiss.waittime); | ||
1386 | case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer); | ||
1387 | case PARAM_TX: return CAST(scc->kiss.tx_inhibit); | ||
1388 | default: return NO_SUCH_PARAM; | ||
1389 | } | ||
1390 | |||
1391 | } | ||
1392 | |||
1393 | #undef CAST | ||
1394 | |||
1395 | /* ******************************************************************* */ | ||
1396 | /* * Send calibration pattern * */ | ||
1397 | /* ******************************************************************* */ | ||
1398 | |||
1399 | static void scc_stop_calibrate(unsigned long channel) | ||
1400 | { | ||
1401 | struct scc_channel *scc = (struct scc_channel *) channel; | ||
1402 | unsigned long flags; | ||
1403 | |||
1404 | spin_lock_irqsave(&scc->lock, flags); | ||
1405 | del_timer(&scc->tx_wdog); | ||
1406 | scc_key_trx(scc, TX_OFF); | ||
1407 | wr(scc, R6, 0); | ||
1408 | wr(scc, R7, FLAG); | ||
1409 | Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ | ||
1410 | Outb(scc->ctrl,RES_EXT_INT); | ||
1411 | |||
1412 | netif_wake_queue(scc->dev); | ||
1413 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1414 | } | ||
1415 | |||
1416 | |||
1417 | static void | ||
1418 | scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern) | ||
1419 | { | ||
1420 | unsigned long flags; | ||
1421 | |||
1422 | spin_lock_irqsave(&scc->lock, flags); | ||
1423 | netif_stop_queue(scc->dev); | ||
1424 | scc_discard_buffers(scc); | ||
1425 | |||
1426 | del_timer(&scc->tx_wdog); | ||
1427 | |||
1428 | scc->tx_wdog.data = (unsigned long) scc; | ||
1429 | scc->tx_wdog.function = scc_stop_calibrate; | ||
1430 | scc->tx_wdog.expires = jiffies + HZ*duration; | ||
1431 | add_timer(&scc->tx_wdog); | ||
1432 | |||
1433 | /* This doesn't seem to work. Why not? */ | ||
1434 | wr(scc, R6, 0); | ||
1435 | wr(scc, R7, pattern); | ||
1436 | |||
1437 | /* | ||
1438 | * Don't know if this works. | ||
1439 | * Damn, where is my Z8530 programming manual...? | ||
1440 | */ | ||
1441 | |||
1442 | Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ | ||
1443 | Outb(scc->ctrl,RES_EXT_INT); | ||
1444 | |||
1445 | scc_key_trx(scc, TX_ON); | ||
1446 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1447 | } | ||
1448 | |||
1449 | /* ******************************************************************* */ | ||
1450 | /* * Init channel structures, special HW, etc... * */ | ||
1451 | /* ******************************************************************* */ | ||
1452 | |||
1453 | /* | ||
1454 | * Reset the Z8530s and setup special hardware | ||
1455 | */ | ||
1456 | |||
1457 | static void z8530_init(void) | ||
1458 | { | ||
1459 | struct scc_channel *scc; | ||
1460 | int chip, k; | ||
1461 | unsigned long flags; | ||
1462 | char *flag; | ||
1463 | |||
1464 | |||
1465 | printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2); | ||
1466 | |||
1467 | flag=" "; | ||
1468 | for (k = 0; k < NR_IRQS; k++) | ||
1469 | if (Ivec[k].used) | ||
1470 | { | ||
1471 | printk("%s%d", flag, k); | ||
1472 | flag=","; | ||
1473 | } | ||
1474 | printk("\n"); | ||
1475 | |||
1476 | |||
1477 | /* reset and pre-init all chips in the system */ | ||
1478 | for (chip = 0; chip < Nchips; chip++) | ||
1479 | { | ||
1480 | scc=&SCC_Info[2*chip]; | ||
1481 | if (!scc->ctrl) continue; | ||
1482 | |||
1483 | /* Special SCC cards */ | ||
1484 | |||
1485 | if(scc->brand & EAGLE) /* this is an EAGLE card */ | ||
1486 | Outb(scc->special,0x08); /* enable interrupt on the board */ | ||
1487 | |||
1488 | if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */ | ||
1489 | Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */ | ||
1490 | |||
1491 | |||
1492 | /* Reset and pre-init Z8530 */ | ||
1493 | |||
1494 | spin_lock_irqsave(&scc->lock, flags); | ||
1495 | |||
1496 | Outb(scc->ctrl, 0); | ||
1497 | OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */ | ||
1498 | udelay(100); /* give it 'a bit' more time than required */ | ||
1499 | wr(scc, R2, chip*16); /* interrupt vector */ | ||
1500 | wr(scc, R9, VIS); /* vector includes status */ | ||
1501 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1502 | } | ||
1503 | |||
1504 | |||
1505 | Driver_Initialized = 1; | ||
1506 | } | ||
1507 | |||
1508 | /* | ||
1509 | * Allocate device structure, err, instance, and register driver | ||
1510 | */ | ||
1511 | |||
1512 | static int scc_net_alloc(const char *name, struct scc_channel *scc) | ||
1513 | { | ||
1514 | int err; | ||
1515 | struct net_device *dev; | ||
1516 | |||
1517 | dev = alloc_netdev(0, name, scc_net_setup); | ||
1518 | if (!dev) | ||
1519 | return -ENOMEM; | ||
1520 | |||
1521 | dev->priv = scc; | ||
1522 | scc->dev = dev; | ||
1523 | spin_lock_init(&scc->lock); | ||
1524 | init_timer(&scc->tx_t); | ||
1525 | init_timer(&scc->tx_wdog); | ||
1526 | |||
1527 | err = register_netdevice(dev); | ||
1528 | if (err) { | ||
1529 | printk(KERN_ERR "%s: can't register network device (%d)\n", | ||
1530 | name, err); | ||
1531 | free_netdev(dev); | ||
1532 | scc->dev = NULL; | ||
1533 | return err; | ||
1534 | } | ||
1535 | |||
1536 | return 0; | ||
1537 | } | ||
1538 | |||
1539 | |||
1540 | |||
1541 | /* ******************************************************************** */ | ||
1542 | /* * Network driver methods * */ | ||
1543 | /* ******************************************************************** */ | ||
1544 | |||
1545 | static unsigned char ax25_bcast[AX25_ADDR_LEN] = | ||
1546 | {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; | ||
1547 | static unsigned char ax25_nocall[AX25_ADDR_LEN] = | ||
1548 | {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; | ||
1549 | |||
1550 | /* ----> Initialize device <----- */ | ||
1551 | |||
1552 | static void scc_net_setup(struct net_device *dev) | ||
1553 | { | ||
1554 | SET_MODULE_OWNER(dev); | ||
1555 | dev->tx_queue_len = 16; /* should be enough... */ | ||
1556 | |||
1557 | dev->open = scc_net_open; | ||
1558 | dev->stop = scc_net_close; | ||
1559 | |||
1560 | dev->hard_start_xmit = scc_net_tx; | ||
1561 | dev->hard_header = ax25_encapsulate; | ||
1562 | dev->rebuild_header = ax25_rebuild_header; | ||
1563 | dev->set_mac_address = scc_net_set_mac_address; | ||
1564 | dev->get_stats = scc_net_get_stats; | ||
1565 | dev->do_ioctl = scc_net_ioctl; | ||
1566 | dev->tx_timeout = NULL; | ||
1567 | |||
1568 | memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); | ||
1569 | memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); | ||
1570 | |||
1571 | dev->flags = 0; | ||
1572 | |||
1573 | dev->type = ARPHRD_AX25; | ||
1574 | dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; | ||
1575 | dev->mtu = AX25_DEF_PACLEN; | ||
1576 | dev->addr_len = AX25_ADDR_LEN; | ||
1577 | |||
1578 | } | ||
1579 | |||
1580 | /* ----> open network device <---- */ | ||
1581 | |||
1582 | static int scc_net_open(struct net_device *dev) | ||
1583 | { | ||
1584 | struct scc_channel *scc = (struct scc_channel *) dev->priv; | ||
1585 | |||
1586 | if (!scc->init) | ||
1587 | return -EINVAL; | ||
1588 | |||
1589 | scc->tx_buff = NULL; | ||
1590 | skb_queue_head_init(&scc->tx_queue); | ||
1591 | |||
1592 | init_channel(scc); | ||
1593 | |||
1594 | netif_start_queue(dev); | ||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | /* ----> close network device <---- */ | ||
1599 | |||
1600 | static int scc_net_close(struct net_device *dev) | ||
1601 | { | ||
1602 | struct scc_channel *scc = (struct scc_channel *) dev->priv; | ||
1603 | unsigned long flags; | ||
1604 | |||
1605 | netif_stop_queue(dev); | ||
1606 | |||
1607 | spin_lock_irqsave(&scc->lock, flags); | ||
1608 | Outb(scc->ctrl,0); /* Make sure pointer is written */ | ||
1609 | wr(scc,R1,0); /* disable interrupts */ | ||
1610 | wr(scc,R3,0); | ||
1611 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1612 | |||
1613 | del_timer_sync(&scc->tx_t); | ||
1614 | del_timer_sync(&scc->tx_wdog); | ||
1615 | |||
1616 | scc_discard_buffers(scc); | ||
1617 | |||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | /* ----> receive frame, called from scc_rxint() <---- */ | ||
1622 | |||
1623 | static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) | ||
1624 | { | ||
1625 | if (skb->len == 0) { | ||
1626 | dev_kfree_skb_irq(skb); | ||
1627 | return; | ||
1628 | } | ||
1629 | |||
1630 | scc->dev_stat.rx_packets++; | ||
1631 | scc->dev_stat.rx_bytes += skb->len; | ||
1632 | |||
1633 | skb->dev = scc->dev; | ||
1634 | skb->protocol = htons(ETH_P_AX25); | ||
1635 | skb->mac.raw = skb->data; | ||
1636 | skb->pkt_type = PACKET_HOST; | ||
1637 | |||
1638 | netif_rx(skb); | ||
1639 | scc->dev->last_rx = jiffies; | ||
1640 | return; | ||
1641 | } | ||
1642 | |||
1643 | /* ----> transmit frame <---- */ | ||
1644 | |||
1645 | static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) | ||
1646 | { | ||
1647 | struct scc_channel *scc = (struct scc_channel *) dev->priv; | ||
1648 | unsigned long flags; | ||
1649 | char kisscmd; | ||
1650 | |||
1651 | if (skb->len > scc->stat.bufsize || skb->len < 2) { | ||
1652 | scc->dev_stat.tx_dropped++; /* bogus frame */ | ||
1653 | dev_kfree_skb(skb); | ||
1654 | return 0; | ||
1655 | } | ||
1656 | |||
1657 | scc->dev_stat.tx_packets++; | ||
1658 | scc->dev_stat.tx_bytes += skb->len; | ||
1659 | scc->stat.txframes++; | ||
1660 | |||
1661 | kisscmd = *skb->data & 0x1f; | ||
1662 | skb_pull(skb, 1); | ||
1663 | |||
1664 | if (kisscmd) { | ||
1665 | scc_set_param(scc, kisscmd, *skb->data); | ||
1666 | dev_kfree_skb(skb); | ||
1667 | return 0; | ||
1668 | } | ||
1669 | |||
1670 | spin_lock_irqsave(&scc->lock, flags); | ||
1671 | |||
1672 | if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) { | ||
1673 | struct sk_buff *skb_del; | ||
1674 | skb_del = skb_dequeue(&scc->tx_queue); | ||
1675 | dev_kfree_skb(skb_del); | ||
1676 | } | ||
1677 | skb_queue_tail(&scc->tx_queue, skb); | ||
1678 | dev->trans_start = jiffies; | ||
1679 | |||
1680 | |||
1681 | /* | ||
1682 | * Start transmission if the trx state is idle or | ||
1683 | * t_idle hasn't expired yet. Use dwait/persistence/slottime | ||
1684 | * algorithm for normal halfduplex operation. | ||
1685 | */ | ||
1686 | |||
1687 | if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) { | ||
1688 | scc->stat.tx_state = TXS_BUSY; | ||
1689 | if (scc->kiss.fulldup == KISS_DUPLEX_HALF) | ||
1690 | __scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime); | ||
1691 | else | ||
1692 | __scc_start_tx_timer(scc, t_dwait, 0); | ||
1693 | } | ||
1694 | spin_unlock_irqrestore(&scc->lock, flags); | ||
1695 | return 0; | ||
1696 | } | ||
1697 | |||
1698 | /* ----> ioctl functions <---- */ | ||
1699 | |||
1700 | /* | ||
1701 | * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg | ||
1702 | * SIOCSCCINI - initialize driver arg: --- | ||
1703 | * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg | ||
1704 | * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg | ||
1705 | * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg | ||
1706 | * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg | ||
1707 | * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg | ||
1708 | * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg | ||
1709 | */ | ||
1710 | |||
1711 | static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1712 | { | ||
1713 | struct scc_kiss_cmd kiss_cmd; | ||
1714 | struct scc_mem_config memcfg; | ||
1715 | struct scc_hw_config hwcfg; | ||
1716 | struct scc_calibrate cal; | ||
1717 | struct scc_channel *scc = (struct scc_channel *) dev->priv; | ||
1718 | int chan; | ||
1719 | unsigned char device_name[IFNAMSIZ]; | ||
1720 | void __user *arg = ifr->ifr_data; | ||
1721 | |||
1722 | |||
1723 | if (!Driver_Initialized) | ||
1724 | { | ||
1725 | if (cmd == SIOCSCCCFG) | ||
1726 | { | ||
1727 | int found = 1; | ||
1728 | |||
1729 | if (!capable(CAP_SYS_RAWIO)) return -EPERM; | ||
1730 | if (!arg) return -EFAULT; | ||
1731 | |||
1732 | if (Nchips >= SCC_MAXCHIPS) | ||
1733 | return -EINVAL; | ||
1734 | |||
1735 | if (copy_from_user(&hwcfg, arg, sizeof(hwcfg))) | ||
1736 | return -EFAULT; | ||
1737 | |||
1738 | if (hwcfg.irq == 2) hwcfg.irq = 9; | ||
1739 | |||
1740 | if (hwcfg.irq < 0 || hwcfg.irq >= NR_IRQS) | ||
1741 | return -EINVAL; | ||
1742 | |||
1743 | if (!Ivec[hwcfg.irq].used && hwcfg.irq) | ||
1744 | { | ||
1745 | if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL)) | ||
1746 | printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq); | ||
1747 | else | ||
1748 | Ivec[hwcfg.irq].used = 1; | ||
1749 | } | ||
1750 | |||
1751 | if (hwcfg.vector_latch && !Vector_Latch) { | ||
1752 | if (!request_region(hwcfg.vector_latch, 1, "scc vector latch")) | ||
1753 | printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch); | ||
1754 | else | ||
1755 | Vector_Latch = hwcfg.vector_latch; | ||
1756 | } | ||
1757 | |||
1758 | if (hwcfg.clock == 0) | ||
1759 | hwcfg.clock = SCC_DEFAULT_CLOCK; | ||
1760 | |||
1761 | #ifndef SCC_DONT_CHECK | ||
1762 | |||
1763 | if(request_region(hwcfg.ctrl_a, 1, "scc-probe")) | ||
1764 | { | ||
1765 | disable_irq(hwcfg.irq); | ||
1766 | Outb(hwcfg.ctrl_a, 0); | ||
1767 | OutReg(hwcfg.ctrl_a, R9, FHWRES); | ||
1768 | udelay(100); | ||
1769 | OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */ | ||
1770 | udelay(5); | ||
1771 | |||
1772 | if (InReg(hwcfg.ctrl_a,R13) != 0x55) | ||
1773 | found = 0; | ||
1774 | enable_irq(hwcfg.irq); | ||
1775 | release_region(hwcfg.ctrl_a, 1); | ||
1776 | } | ||
1777 | else | ||
1778 | found = 0; | ||
1779 | #endif | ||
1780 | |||
1781 | if (found) | ||
1782 | { | ||
1783 | SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a; | ||
1784 | SCC_Info[2*Nchips ].data = hwcfg.data_a; | ||
1785 | SCC_Info[2*Nchips ].irq = hwcfg.irq; | ||
1786 | SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b; | ||
1787 | SCC_Info[2*Nchips+1].data = hwcfg.data_b; | ||
1788 | SCC_Info[2*Nchips+1].irq = hwcfg.irq; | ||
1789 | |||
1790 | SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a; | ||
1791 | SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b; | ||
1792 | SCC_ctrl[Nchips].irq = hwcfg.irq; | ||
1793 | } | ||
1794 | |||
1795 | |||
1796 | for (chan = 0; chan < 2; chan++) | ||
1797 | { | ||
1798 | sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan); | ||
1799 | |||
1800 | SCC_Info[2*Nchips+chan].special = hwcfg.special; | ||
1801 | SCC_Info[2*Nchips+chan].clock = hwcfg.clock; | ||
1802 | SCC_Info[2*Nchips+chan].brand = hwcfg.brand; | ||
1803 | SCC_Info[2*Nchips+chan].option = hwcfg.option; | ||
1804 | SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc; | ||
1805 | |||
1806 | #ifdef SCC_DONT_CHECK | ||
1807 | printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n", | ||
1808 | device_name, | ||
1809 | SCC_Info[2*Nchips+chan].data, | ||
1810 | SCC_Info[2*Nchips+chan].ctrl); | ||
1811 | |||
1812 | #else | ||
1813 | printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n", | ||
1814 | device_name, | ||
1815 | chan? hwcfg.data_b : hwcfg.data_a, | ||
1816 | chan? hwcfg.ctrl_b : hwcfg.ctrl_a, | ||
1817 | found? "found" : "missing"); | ||
1818 | #endif | ||
1819 | |||
1820 | if (found) | ||
1821 | { | ||
1822 | request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl"); | ||
1823 | request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data"); | ||
1824 | if (Nchips+chan != 0 && | ||
1825 | scc_net_alloc(device_name, | ||
1826 | &SCC_Info[2*Nchips+chan])) | ||
1827 | return -EINVAL; | ||
1828 | } | ||
1829 | } | ||
1830 | |||
1831 | if (found) Nchips++; | ||
1832 | |||
1833 | return 0; | ||
1834 | } | ||
1835 | |||
1836 | if (cmd == SIOCSCCINI) | ||
1837 | { | ||
1838 | if (!capable(CAP_SYS_RAWIO)) | ||
1839 | return -EPERM; | ||
1840 | |||
1841 | if (Nchips == 0) | ||
1842 | return -EINVAL; | ||
1843 | |||
1844 | z8530_init(); | ||
1845 | return 0; | ||
1846 | } | ||
1847 | |||
1848 | return -EINVAL; /* confuse the user */ | ||
1849 | } | ||
1850 | |||
1851 | if (!scc->init) | ||
1852 | { | ||
1853 | if (cmd == SIOCSCCCHANINI) | ||
1854 | { | ||
1855 | if (!capable(CAP_NET_ADMIN)) return -EPERM; | ||
1856 | if (!arg) return -EINVAL; | ||
1857 | |||
1858 | scc->stat.bufsize = SCC_BUFSIZE; | ||
1859 | |||
1860 | if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem))) | ||
1861 | return -EINVAL; | ||
1862 | |||
1863 | /* default KISS Params */ | ||
1864 | |||
1865 | if (scc->modem.speed < 4800) | ||
1866 | { | ||
1867 | scc->kiss.txdelay = 36; /* 360 ms */ | ||
1868 | scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */ | ||
1869 | scc->kiss.slottime = 16; /* 160 ms */ | ||
1870 | scc->kiss.tailtime = 4; /* minimal reasonable value */ | ||
1871 | scc->kiss.fulldup = 0; /* CSMA */ | ||
1872 | scc->kiss.waittime = 50; /* 500 ms */ | ||
1873 | scc->kiss.maxkeyup = 10; /* 10 s */ | ||
1874 | scc->kiss.mintime = 3; /* 3 s */ | ||
1875 | scc->kiss.idletime = 30; /* 30 s */ | ||
1876 | scc->kiss.maxdefer = 120; /* 2 min */ | ||
1877 | scc->kiss.softdcd = 0; /* hardware dcd */ | ||
1878 | } else { | ||
1879 | scc->kiss.txdelay = 10; /* 100 ms */ | ||
1880 | scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */ | ||
1881 | scc->kiss.slottime = 8; /* 160 ms */ | ||
1882 | scc->kiss.tailtime = 1; /* minimal reasonable value */ | ||
1883 | scc->kiss.fulldup = 0; /* CSMA */ | ||
1884 | scc->kiss.waittime = 50; /* 500 ms */ | ||
1885 | scc->kiss.maxkeyup = 7; /* 7 s */ | ||
1886 | scc->kiss.mintime = 3; /* 3 s */ | ||
1887 | scc->kiss.idletime = 30; /* 30 s */ | ||
1888 | scc->kiss.maxdefer = 120; /* 2 min */ | ||
1889 | scc->kiss.softdcd = 0; /* hardware dcd */ | ||
1890 | } | ||
1891 | |||
1892 | scc->tx_buff = NULL; | ||
1893 | skb_queue_head_init(&scc->tx_queue); | ||
1894 | scc->init = 1; | ||
1895 | |||
1896 | return 0; | ||
1897 | } | ||
1898 | |||
1899 | return -EINVAL; | ||
1900 | } | ||
1901 | |||
1902 | switch(cmd) | ||
1903 | { | ||
1904 | case SIOCSCCRESERVED: | ||
1905 | return -ENOIOCTLCMD; | ||
1906 | |||
1907 | case SIOCSCCSMEM: | ||
1908 | if (!capable(CAP_SYS_RAWIO)) return -EPERM; | ||
1909 | if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) | ||
1910 | return -EINVAL; | ||
1911 | scc->stat.bufsize = memcfg.bufsize; | ||
1912 | return 0; | ||
1913 | |||
1914 | case SIOCSCCGSTAT: | ||
1915 | if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat))) | ||
1916 | return -EINVAL; | ||
1917 | return 0; | ||
1918 | |||
1919 | case SIOCSCCGKISS: | ||
1920 | if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) | ||
1921 | return -EINVAL; | ||
1922 | kiss_cmd.param = scc_get_param(scc, kiss_cmd.command); | ||
1923 | if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd))) | ||
1924 | return -EINVAL; | ||
1925 | return 0; | ||
1926 | |||
1927 | case SIOCSCCSKISS: | ||
1928 | if (!capable(CAP_NET_ADMIN)) return -EPERM; | ||
1929 | if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd))) | ||
1930 | return -EINVAL; | ||
1931 | return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param); | ||
1932 | |||
1933 | case SIOCSCCCAL: | ||
1934 | if (!capable(CAP_SYS_RAWIO)) return -EPERM; | ||
1935 | if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0) | ||
1936 | return -EINVAL; | ||
1937 | |||
1938 | scc_start_calibrate(scc, cal.time, cal.pattern); | ||
1939 | return 0; | ||
1940 | |||
1941 | default: | ||
1942 | return -ENOIOCTLCMD; | ||
1943 | |||
1944 | } | ||
1945 | |||
1946 | return -EINVAL; | ||
1947 | } | ||
1948 | |||
1949 | /* ----> set interface callsign <---- */ | ||
1950 | |||
1951 | static int scc_net_set_mac_address(struct net_device *dev, void *addr) | ||
1952 | { | ||
1953 | struct sockaddr *sa = (struct sockaddr *) addr; | ||
1954 | memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); | ||
1955 | return 0; | ||
1956 | } | ||
1957 | |||
1958 | /* ----> get statistics <---- */ | ||
1959 | |||
1960 | static struct net_device_stats *scc_net_get_stats(struct net_device *dev) | ||
1961 | { | ||
1962 | struct scc_channel *scc = (struct scc_channel *) dev->priv; | ||
1963 | |||
1964 | scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over; | ||
1965 | scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under; | ||
1966 | scc->dev_stat.rx_fifo_errors = scc->stat.rx_over; | ||
1967 | scc->dev_stat.tx_fifo_errors = scc->stat.tx_under; | ||
1968 | |||
1969 | return &scc->dev_stat; | ||
1970 | } | ||
1971 | |||
1972 | /* ******************************************************************** */ | ||
1973 | /* * dump statistics to /proc/net/z8530drv * */ | ||
1974 | /* ******************************************************************** */ | ||
1975 | |||
1976 | #ifdef CONFIG_PROC_FS | ||
1977 | |||
1978 | static inline struct scc_channel *scc_net_seq_idx(loff_t pos) | ||
1979 | { | ||
1980 | int k; | ||
1981 | |||
1982 | for (k = 0; k < Nchips*2; ++k) { | ||
1983 | if (!SCC_Info[k].init) | ||
1984 | continue; | ||
1985 | if (pos-- == 0) | ||
1986 | return &SCC_Info[k]; | ||
1987 | } | ||
1988 | return NULL; | ||
1989 | } | ||
1990 | |||
1991 | static void *scc_net_seq_start(struct seq_file *seq, loff_t *pos) | ||
1992 | { | ||
1993 | return *pos ? scc_net_seq_idx(*pos - 1) : SEQ_START_TOKEN; | ||
1994 | |||
1995 | } | ||
1996 | |||
1997 | static void *scc_net_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
1998 | { | ||
1999 | unsigned k; | ||
2000 | struct scc_channel *scc = v; | ||
2001 | ++*pos; | ||
2002 | |||
2003 | for (k = (v == SEQ_START_TOKEN) ? 0 : (scc - SCC_Info)+1; | ||
2004 | k < Nchips*2; ++k) { | ||
2005 | if (SCC_Info[k].init) | ||
2006 | return &SCC_Info[k]; | ||
2007 | } | ||
2008 | return NULL; | ||
2009 | } | ||
2010 | |||
2011 | static void scc_net_seq_stop(struct seq_file *seq, void *v) | ||
2012 | { | ||
2013 | } | ||
2014 | |||
2015 | static int scc_net_seq_show(struct seq_file *seq, void *v) | ||
2016 | { | ||
2017 | if (v == SEQ_START_TOKEN) { | ||
2018 | seq_puts(seq, "z8530drv-"VERSION"\n"); | ||
2019 | } else if (!Driver_Initialized) { | ||
2020 | seq_puts(seq, "not initialized\n"); | ||
2021 | } else if (!Nchips) { | ||
2022 | seq_puts(seq, "chips missing\n"); | ||
2023 | } else { | ||
2024 | const struct scc_channel *scc = v; | ||
2025 | const struct scc_stat *stat = &scc->stat; | ||
2026 | const struct scc_kiss *kiss = &scc->kiss; | ||
2027 | |||
2028 | |||
2029 | /* dev data ctrl irq clock brand enh vector special option | ||
2030 | * baud nrz clocksrc softdcd bufsize | ||
2031 | * rxints txints exints spints | ||
2032 | * rcvd rxerrs over / xmit txerrs under / nospace bufsize | ||
2033 | * txd pers slot tail ful wait min maxk idl defr txof grp | ||
2034 | * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | ||
2035 | * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ## | ||
2036 | */ | ||
2037 | |||
2038 | seq_printf(seq, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n", | ||
2039 | scc->dev->name, | ||
2040 | scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand, | ||
2041 | scc->enhanced, Vector_Latch, scc->special, | ||
2042 | scc->option); | ||
2043 | seq_printf(seq, "\t%lu %d %d %d %d\n", | ||
2044 | scc->modem.speed, scc->modem.nrz, | ||
2045 | scc->modem.clocksrc, kiss->softdcd, | ||
2046 | stat->bufsize); | ||
2047 | seq_printf(seq, "\t%lu %lu %lu %lu\n", | ||
2048 | stat->rxints, stat->txints, stat->exints, stat->spints); | ||
2049 | seq_printf(seq, "\t%lu %lu %d / %lu %lu %d / %d %d\n", | ||
2050 | stat->rxframes, stat->rxerrs, stat->rx_over, | ||
2051 | stat->txframes, stat->txerrs, stat->tx_under, | ||
2052 | stat->nospace, stat->tx_state); | ||
2053 | |||
2054 | #define K(x) kiss->x | ||
2055 | seq_printf(seq, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n", | ||
2056 | K(txdelay), K(persist), K(slottime), K(tailtime), | ||
2057 | K(fulldup), K(waittime), K(mintime), K(maxkeyup), | ||
2058 | K(idletime), K(maxdefer), K(tx_inhibit), K(group)); | ||
2059 | #undef K | ||
2060 | #ifdef SCC_DEBUG | ||
2061 | { | ||
2062 | int reg; | ||
2063 | |||
2064 | seq_printf(seq, "\tW "); | ||
2065 | for (reg = 0; reg < 16; reg++) | ||
2066 | seq_printf(seq, "%2.2x ", scc->wreg[reg]); | ||
2067 | seq_printf(seq, "\n"); | ||
2068 | |||
2069 | seq_printf(seq, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1)); | ||
2070 | for (reg = 3; reg < 8; reg++) | ||
2071 | seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg)); | ||
2072 | seq_printf(seq, "XX "); | ||
2073 | for (reg = 9; reg < 16; reg++) | ||
2074 | seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg)); | ||
2075 | seq_printf(seq, "\n"); | ||
2076 | } | ||
2077 | #endif | ||
2078 | seq_putc(seq, '\n'); | ||
2079 | } | ||
2080 | |||
2081 | return 0; | ||
2082 | } | ||
2083 | |||
2084 | static struct seq_operations scc_net_seq_ops = { | ||
2085 | .start = scc_net_seq_start, | ||
2086 | .next = scc_net_seq_next, | ||
2087 | .stop = scc_net_seq_stop, | ||
2088 | .show = scc_net_seq_show, | ||
2089 | }; | ||
2090 | |||
2091 | |||
2092 | static int scc_net_seq_open(struct inode *inode, struct file *file) | ||
2093 | { | ||
2094 | return seq_open(file, &scc_net_seq_ops); | ||
2095 | } | ||
2096 | |||
2097 | static struct file_operations scc_net_seq_fops = { | ||
2098 | .owner = THIS_MODULE, | ||
2099 | .open = scc_net_seq_open, | ||
2100 | .read = seq_read, | ||
2101 | .llseek = seq_lseek, | ||
2102 | .release = seq_release_private, | ||
2103 | }; | ||
2104 | |||
2105 | #endif /* CONFIG_PROC_FS */ | ||
2106 | |||
2107 | |||
2108 | /* ******************************************************************** */ | ||
2109 | /* * Init SCC driver * */ | ||
2110 | /* ******************************************************************** */ | ||
2111 | |||
2112 | static int __init scc_init_driver (void) | ||
2113 | { | ||
2114 | char devname[IFNAMSIZ]; | ||
2115 | |||
2116 | printk(banner); | ||
2117 | |||
2118 | sprintf(devname,"%s0", SCC_DriverName); | ||
2119 | |||
2120 | rtnl_lock(); | ||
2121 | if (scc_net_alloc(devname, SCC_Info)) { | ||
2122 | rtnl_unlock(); | ||
2123 | printk(KERN_ERR "z8530drv: cannot initialize module\n"); | ||
2124 | return -EIO; | ||
2125 | } | ||
2126 | rtnl_unlock(); | ||
2127 | |||
2128 | proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops); | ||
2129 | |||
2130 | return 0; | ||
2131 | } | ||
2132 | |||
2133 | static void __exit scc_cleanup_driver(void) | ||
2134 | { | ||
2135 | io_port ctrl; | ||
2136 | int k; | ||
2137 | struct scc_channel *scc; | ||
2138 | struct net_device *dev; | ||
2139 | |||
2140 | if (Nchips == 0 && (dev = SCC_Info[0].dev)) | ||
2141 | { | ||
2142 | unregister_netdev(dev); | ||
2143 | free_netdev(dev); | ||
2144 | } | ||
2145 | |||
2146 | /* Guard against chip prattle */ | ||
2147 | local_irq_disable(); | ||
2148 | |||
2149 | for (k = 0; k < Nchips; k++) | ||
2150 | if ( (ctrl = SCC_ctrl[k].chan_A) ) | ||
2151 | { | ||
2152 | Outb(ctrl, 0); | ||
2153 | OutReg(ctrl,R9,FHWRES); /* force hardware reset */ | ||
2154 | udelay(50); | ||
2155 | } | ||
2156 | |||
2157 | /* To unload the port must be closed so no real IRQ pending */ | ||
2158 | for (k=0; k < NR_IRQS ; k++) | ||
2159 | if (Ivec[k].used) free_irq(k, NULL); | ||
2160 | |||
2161 | local_irq_enable(); | ||
2162 | |||
2163 | /* Now clean up */ | ||
2164 | for (k = 0; k < Nchips*2; k++) | ||
2165 | { | ||
2166 | scc = &SCC_Info[k]; | ||
2167 | if (scc->ctrl) | ||
2168 | { | ||
2169 | release_region(scc->ctrl, 1); | ||
2170 | release_region(scc->data, 1); | ||
2171 | } | ||
2172 | if (scc->dev) | ||
2173 | { | ||
2174 | unregister_netdev(scc->dev); | ||
2175 | free_netdev(scc->dev); | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | |||
2180 | if (Vector_Latch) | ||
2181 | release_region(Vector_Latch, 1); | ||
2182 | |||
2183 | proc_net_remove("z8530drv"); | ||
2184 | } | ||
2185 | |||
2186 | MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>"); | ||
2187 | MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards"); | ||
2188 | MODULE_SUPPORTED_DEVICE("Z8530 based SCC cards for Amateur Radio"); | ||
2189 | MODULE_LICENSE("GPL"); | ||
2190 | module_init(scc_init_driver); | ||
2191 | module_exit(scc_cleanup_driver); | ||
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 | |||
diff --git a/drivers/net/hamradio/yam1200.h b/drivers/net/hamradio/yam1200.h new file mode 100644 index 000000000000..53ca8a3903a7 --- /dev/null +++ b/drivers/net/hamradio/yam1200.h | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * | ||
3 | * File yam1k2b5.mcs converted to h format by mcs2h | ||
4 | * | ||
5 | * (C) F6FBB 1998 | ||
6 | * | ||
7 | * Tue Aug 25 20:24:08 1998 | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | static unsigned char bits_1200[]= { | ||
12 | 0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xf3,0xcb,0xff,0xdb,0xfc,0xf2, | ||
13 | 0xff,0xf6,0xff,0x3c,0xbf,0xfd,0xbf,0xdf,0x6e,0x3f,0x6f,0xf1,0x7d,0xb4,0xfd,0xbf, | ||
14 | 0xdf,0x6f,0x3f,0x6f,0xf7,0x0b,0xff,0xdb,0xfd,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, | ||
15 | 0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xef,0xff,0xff,0xff, | ||
16 | 0xfd,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xbf, | ||
17 | 0xff,0xff,0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfc,0xff,0xfe,0xff,0xff,0xff,0xf0, | ||
18 | 0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
19 | 0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xf1,0xff,0xff,0xfe,0x7f,0xbf,0xff, | ||
20 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xff,0xff,0xf0,0x9f, | ||
21 | 0xff,0xff,0xff,0xfe,0xff,0xfd,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xff, | ||
22 | 0xff,0xff,0xfb,0xff,0xfb,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
23 | 0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xf0,0x5f,0xff, | ||
24 | 0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
25 | 0xff,0xbf,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
26 | 0xff,0xff,0xff,0xff,0xff,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, | ||
27 | 0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, | ||
28 | 0xff,0xff,0xff,0xfd,0xff,0xbf,0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xfb, | ||
29 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff, | ||
30 | 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff, | ||
31 | 0xff,0xff,0xf7,0xff,0xff,0xf1,0xff,0xff,0xf7,0xbf,0xe7,0xff,0xff,0xff,0xff,0xfb, | ||
32 | 0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, | ||
33 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
34 | 0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
35 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdb, | ||
36 | 0xff,0xff,0xf5,0xa5,0xfd,0x4b,0x6e,0xef,0x33,0x32,0xdd,0xd3,0x4a,0xd6,0x92,0xfe, | ||
37 | 0xb3,0x3f,0xbd,0xf1,0xfa,0xdb,0xfe,0xf7,0xf6,0x96,0xbd,0xbd,0xff,0xbd,0xff,0xed, | ||
38 | 0x7f,0x6b,0x7f,0xfb,0xdf,0xfe,0xfb,0xfe,0x90,0xcf,0xff,0xff,0xff,0xfe,0xbe,0xef, | ||
39 | 0xff,0xff,0xdb,0x5f,0xf6,0xff,0xf6,0x8f,0xfd,0xa5,0xdd,0xff,0xff,0xff,0xff,0x6f, | ||
40 | 0x7f,0xdb,0xf1,0xfc,0xbf,0xff,0x6f,0xff,0xef,0xfc,0x5b,0x5d,0xda,0xdf,0xf4,0xff, | ||
41 | 0xf2,0xff,0xfd,0xbf,0xff,0xff,0xff,0xd0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, | ||
42 | 0xff,0xfb,0xef,0xb7,0xfc,0x33,0xff,0xfb,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0, | ||
43 | 0x0f,0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x72,0x0f,0xf1,0x6f,0xff,0xfe,0x94,0x3f, | ||
44 | 0xff,0xff,0xff,0x7b,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf0, | ||
45 | 0xf7,0xef,0xb7,0xfc,0x33,0xff,0xff,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,0x0f, | ||
46 | 0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x73,0x8f,0xf2,0x6f,0xff,0xfe,0x94,0x3f,0xff, | ||
47 | 0xff,0xff,0x7d,0x9f,0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x9e, | ||
48 | 0xff,0xfc,0xef,0xd3,0xfb,0xff,0x7f,0xf5,0x5f,0xfe,0x59,0xff,0xff,0xff,0xfc,0xf1, | ||
49 | 0xfe,0x7f,0xff,0xff,0xfa,0x17,0xff,0xe7,0xef,0xef,0xff,0xff,0x3f,0xf1,0xff,0xff, | ||
50 | 0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xfc,0xea, | ||
51 | 0xff,0xf0,0xff,0xff,0xbf,0xf9,0x3f,0xb1,0xef,0xff,0xd7,0xff,0xfb,0xff,0xf0,0xff, | ||
52 | 0xff,0xf3,0xff,0xdf,0xff,0x7b,0xff,0xfd,0xff,0xf6,0xff,0xbf,0xff,0xff,0xbf,0xff, | ||
53 | 0xff,0xff,0xda,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x01,0x00,0x00,0x02,0x02, | ||
54 | 0x02,0x02,0x00,0x40,0x40,0x40,0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00, | ||
55 | 0x00,0x00,0x00,0x00,0x19,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, | ||
56 | 0x00,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfb,0xff,0xfd,0xff, | ||
57 | 0xff,0x7f,0xff,0xff,0xbf,0xff,0xef,0xff,0xff,0xfd,0xff,0xff,0xf1,0xff,0xdf,0xff, | ||
58 | 0xff,0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf, | ||
59 | 0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xdf,0xff,0x7f,0xff,0xff,0xff,0xff, | ||
60 | 0xdf,0xdf,0xff,0xef,0xff,0x9e,0xef,0xff,0xff,0x7f,0xff,0xf1,0xef,0xff,0xff,0xff, | ||
61 | 0xf7,0xfa,0xbf,0xff,0xff,0xfe,0x47,0xef,0xff,0xbd,0xf6,0xff,0xff,0xdf,0xf5,0xf0, | ||
62 | 0xf0,0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x01,0x02,0x08, | ||
63 | 0x16,0x00,0x00,0x00,0x80,0x00,0x01,0x02,0x00,0x80,0x01,0x0c,0x02,0x00,0x00,0x01, | ||
64 | 0x00,0x00,0x20,0x00,0x00,0x06,0x00,0x20,0x00,0x10,0x00,0x14,0x00,0x04,0xc1,0xf0, | ||
65 | 0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f, | ||
66 | 0xec,0xff,0xff,0xfa,0xff,0xbf,0xff,0x6f,0xff,0xe1,0xff,0xff,0xff,0xff,0xbd,0xfe, | ||
67 | 0x46,0xff,0xef,0x7f,0xcd,0xdf,0xff,0xff,0xfd,0xff,0xbd,0xff,0x7f,0x7f,0xf0,0x4f, | ||
68 | 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
69 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
70 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff, | ||
71 | 0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa4,0xbc,0xcd,0x6d,0x6b,0x6f,0x5b,0xdc,0x33, | ||
72 | 0x5a,0xf6,0xf7,0xf6,0xb3,0x3f,0xbd,0xc1,0xfa,0x5a,0xf6,0xf6,0xb6,0xf7,0xff,0xbd, | ||
73 | 0xbb,0x3c,0xce,0xcf,0x34,0xef,0x33,0xbb,0xcc,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff, | ||
74 | 0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xd6,0xff,0xfd,0xfd,0xbf,0xff,0xad, | ||
75 | 0xbf,0xf9,0x7f,0x6f,0xfc,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0xff,0xda,0xdb,0xfc, | ||
76 | 0xdb,0xff,0x76,0x8f,0xf6,0xff,0xcd,0xab,0xfe,0xfb,0xff,0xd0,0xff,0xff,0xff,0xff, | ||
77 | 0xfe,0xff,0x9f,0xff,0xf4,0x20,0xaf,0x6d,0x0b,0xc1,0x7b,0xff,0xff,0xff,0xcb,0xff, | ||
78 | 0x3f,0xf0,0xef,0x7f,0x0f,0xf1,0xc3,0x3c,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x0b, | ||
79 | 0x1d,0x6a,0x64,0x05,0x6b,0x99,0x01,0xff,0xfd,0xef,0xf0,0x2f,0xff,0xff,0xff,0xfe, | ||
80 | 0xff,0xff,0xff,0xf4,0x00,0x2f,0xcc,0x0b,0xc3,0x7f,0xff,0xff,0xff,0x0a,0xdf,0xbf, | ||
81 | 0xfd,0x7f,0xff,0xff,0xf1,0xc3,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x4a,0x0e, | ||
82 | 0x96,0x64,0x02,0x97,0x99,0x10,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff, | ||
83 | 0xff,0xff,0xfe,0x84,0xf9,0xd5,0x27,0xf1,0x7f,0xff,0xf8,0xeb,0xdf,0xf3,0xcf,0x3f, | ||
84 | 0x1f,0xff,0xf7,0x11,0xff,0xcf,0xff,0xfe,0x67,0xff,0xff,0xff,0xff,0xc4,0xff,0xff, | ||
85 | 0xb3,0xa1,0xff,0xf9,0xe0,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff, | ||
86 | 0xff,0xfb,0x7f,0xe0,0xff,0xc7,0xfe,0x7f,0x3f,0xff,0xfd,0x77,0x8d,0x7f,0x0f,0xff, | ||
87 | 0xc3,0xff,0xf1,0xbf,0x8f,0xcf,0xff,0xff,0xdd,0x7b,0xff,0xf6,0xfa,0xf7,0xff,0x40, | ||
88 | 0x9f,0xf9,0x7f,0xd8,0xff,0xff,0xfa,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, | ||
89 | 0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x00,0x10, | ||
90 | 0x00,0x01,0x00,0x10,0x20,0x20,0x00,0x00,0x10,0x00,0x04,0x01,0x05,0x00,0x00,0x00, | ||
91 | 0x00,0x40,0x40,0x00,0x00,0x3c,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff, | ||
92 | 0xff,0xff,0xfe,0x7f,0x7f,0xff,0xef,0xff,0xff,0xdf,0xff,0xff,0xdf,0xff,0xef,0xf7, | ||
93 | 0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xfc,0xfd,0xff,0x7f, | ||
94 | 0x7e,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0xff,0xff, | ||
95 | 0xff,0xff,0xfe,0xeb,0xfd,0x6f,0xff,0xf7,0xfe,0xf5,0x7f,0xff,0xff,0x7f,0xbf,0xb1, | ||
96 | 0xff,0xff,0x9f,0xbf,0xfb,0xff,0xfe,0xff,0xfe,0xff,0xf7,0xeb,0xdf,0xbf,0x5f,0xdd, | ||
97 | 0xff,0xdb,0xfd,0xd0,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x00,0x42,0x00, | ||
98 | 0x00,0x00,0x30,0x18,0x04,0x08,0x09,0x21,0x82,0x80,0x02,0x00,0x08,0x00,0x01,0x00, | ||
99 | 0x00,0x00,0x0c,0x20,0x10,0x00,0x11,0x00,0x44,0x84,0x00,0x20,0x20,0x84,0x80,0x00, | ||
100 | 0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xf7,0xff,0xfb,0xdd,0xf9,0xff, | ||
101 | 0xda,0xff,0xdc,0xdd,0xfc,0xfb,0xff,0xbf,0xfb,0x3e,0xd7,0x96,0xfe,0x61,0xf7,0xff, | ||
102 | 0x7f,0xff,0x3f,0xfd,0xff,0xdf,0xcf,0xf7,0xdf,0xf7,0xbf,0xfd,0xff,0xfe,0xef,0xef, | ||
103 | 0xfe,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
104 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, | ||
105 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
106 | 0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf3,0xbd,0xfd,0x4b,0x74,0xcf, | ||
107 | 0x73,0x5b,0xcb,0x3b,0xdf,0xfe,0xf7,0xfe,0xd3,0x75,0xac,0xa1,0xfb,0xdf,0xfe,0xf7, | ||
108 | 0x76,0x96,0xb5,0x24,0xbd,0xa5,0xad,0x49,0x2f,0x69,0x2b,0x52,0x5b,0xbd,0xff,0xff, | ||
109 | 0xf0,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0xff,0xcc, | ||
110 | 0xa7,0xfb,0xad,0xff,0x7f,0x6f,0xff,0x6d,0x7f,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff, | ||
111 | 0x6f,0xff,0xdb,0xff,0xdb,0xff,0xf6,0x97,0xf6,0xff,0xb5,0xb5,0xff,0xff,0xff,0xd0, | ||
112 | 0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa5,0xbc,0x43,0xfc,0x7c,0x03,0xe7, | ||
113 | 0xff,0xff,0x20,0xff,0xff,0xff,0xcc,0xfd,0x7d,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59, | ||
114 | 0xba,0x56,0x66,0x6a,0xad,0x9a,0xa9,0x9a,0x97,0xa5,0xaa,0xbb,0xff,0xff,0xf0,0x0f, | ||
115 | 0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xfd,0xf7,0xfd,0x43,0xff,0xfd,0x6b,0xe7,0xff, | ||
116 | 0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0x3f,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,0xb5, | ||
117 | 0xa6,0x66,0x6a,0xad,0x9a,0xa9,0x99,0x6b,0x5a,0xaa,0xff,0xff,0xb7,0xf0,0x3f,0xff, | ||
118 | 0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x9c,0xf7,0xfd,0xd2,0x41,0xff,0xff,0xf2,0x7f, | ||
119 | 0x8f,0xff,0xff,0x3d,0xf3,0xff,0x17,0xf1,0xff,0xff,0xff,0xff,0xff,0x7f,0xdf,0xfc, | ||
120 | 0x8f,0x38,0xff,0xef,0x23,0xff,0xfb,0xf7,0xc8,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff, | ||
121 | 0xff,0xfe,0xf5,0x7f,0xff,0xfd,0xff,0xe4,0xff,0xeb,0xff,0xcf,0xbf,0xfa,0xff,0xab, | ||
122 | 0xef,0xff,0xfb,0xff,0xf3,0xfd,0x61,0xff,0xff,0xff,0xff,0xfa,0xff,0xfb,0xfd,0x0d, | ||
123 | 0xff,0xfe,0xff,0x43,0x7f,0xfe,0xbf,0xd0,0xfd,0xff,0xfa,0xf0,0x3f,0xff,0xff,0xff, | ||
124 | 0xfe,0xf3,0xc0,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x00,0x60,0xc0,0x40,0x00,0x00, | ||
125 | 0x00,0x00,0x34,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x00, | ||
126 | 0x00,0x03,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x3c,0xf0,0x3f,0xff,0xff,0xff,0xfe, | ||
127 | 0xfd,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff, | ||
128 | 0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfd,0xff, | ||
129 | 0xff,0xff,0xff,0xfe,0xfe,0x5f,0xff,0xff,0xcb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0, | ||
130 | 0xff,0xff,0xfd,0xff,0xef,0xe3,0xde,0xee,0xd9,0xc5,0x93,0xff,0xff,0xfe,0xfe,0xff, | ||
131 | 0xfb,0xee,0xfe,0xf1,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xbf,0xf7,0xff,0xff,0x7f, | ||
132 | 0xaf,0xbd,0xdf,0xdf,0xfb,0xf3,0xf3,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x34, | ||
133 | 0x00,0x06,0x61,0x00,0x18,0x01,0xa0,0x05,0x17,0x00,0x20,0x05,0x28,0x20,0x00,0x00, | ||
134 | 0x05,0x00,0x41,0x00,0x00,0x40,0x00,0x09,0x00,0x01,0x20,0x86,0x82,0x08,0x40,0x03, | ||
135 | 0x80,0x30,0x70,0x08,0x14,0x02,0xc1,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, | ||
136 | 0xff,0xff,0xbd,0xef,0xfb,0xff,0xff,0xfb,0x9c,0x7f,0xef,0xdf,0xff,0xbf,0xeb,0xde, | ||
137 | 0xff,0xc1,0x7f,0xff,0xfb,0x7f,0xff,0xff,0xff,0x5f,0xff,0xff,0xff,0xdf,0xbf,0xef, | ||
138 | 0x3f,0xf7,0x8f,0xef,0x7f,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, | ||
139 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
140 | 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
141 | 0xff,0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbd, | ||
142 | 0xdf,0xef,0x7d,0x6d,0x2b,0x5a,0x5d,0xd2,0xdf,0xf6,0x92,0xb6,0xb2,0xb3,0xac,0xa1, | ||
143 | 0xfb,0xdf,0xfe,0xf1,0xee,0xf5,0xf6,0xbc,0x6b,0xbd,0x7d,0xaf,0x1a,0xef,0x5f,0x6b, | ||
144 | 0xc6,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, | ||
145 | 0xf6,0xff,0xf6,0xb7,0xfd,0xad,0xfd,0xbf,0xf3,0x6f,0xff,0x6f,0xff,0xdb,0xd1,0xfd, | ||
146 | 0xbf,0xff,0x6f,0xf5,0x6b,0xbc,0x5b,0x3c,0xda,0xef,0x16,0xaf,0x16,0xff,0xcd,0xab, | ||
147 | 0xff,0x6f,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xbf,0xff,0xff, | ||
148 | 0xff,0x6c,0x03,0x10,0xc1,0xf3,0xff,0xf3,0x3a,0xf3,0xca,0xff,0xaf,0xf1,0xff,0xff, | ||
149 | 0xff,0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff, | ||
150 | 0xff,0x5f,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff, | ||
151 | 0xea,0x0f,0x50,0xc3,0xf3,0x7f,0xff,0xf3,0xf3,0xc3,0xff,0xaf,0xf1,0xff,0xff,0xff, | ||
152 | 0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,0xff, | ||
153 | 0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xd7,0xff,0xff,0x5f,0xc1, | ||
154 | 0x3f,0xf7,0x5e,0xf5,0xce,0x9e,0x5f,0x3f,0x17,0xff,0xf3,0xe1,0xff,0xff,0xff,0xff, | ||
155 | 0xd8,0xff,0xfa,0xfe,0x67,0xff,0xfe,0xbf,0x5a,0xff,0xff,0xaf,0xf5,0xff,0xff,0xff, | ||
156 | 0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfd,0xff,0xf7,0xff,0xfd,0x4e,0x3d, | ||
157 | 0x3f,0xe7,0x0b,0xbf,0x8f,0xf9,0xff,0xeb,0xe3,0xff,0xe1,0xff,0xff,0xfc,0xff,0xc7, | ||
158 | 0x9f,0xff,0x3e,0x39,0xe5,0xff,0xcf,0x9b,0xf9,0xff,0xff,0xc5,0xff,0xff,0xfa,0xf0, | ||
159 | 0x5f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, | ||
160 | 0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x20, | ||
161 | 0x00,0x01,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xf0,0x4f, | ||
162 | 0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xbf, | ||
163 | 0x3f,0xff,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf1,0xff,0xff,0xff,0xff,0xf7,0xff,0xf7, | ||
164 | 0xff,0xed,0xff,0xfb,0xfe,0xff,0x7f,0xff,0x7f,0xdf,0xff,0xff,0xdd,0xf0,0x3f,0xff, | ||
165 | 0xff,0xff,0xfe,0xf0,0xff,0xff,0xf3,0xff,0xf7,0xff,0xfe,0x5f,0xff,0xf7,0xff,0xff, | ||
166 | 0xdf,0xff,0xff,0xff,0xf7,0xfe,0x7b,0xf1,0xff,0xfd,0xfd,0xff,0xdf,0xdf,0xff,0x7d, | ||
167 | 0x73,0xf9,0xff,0xc3,0x7e,0xfe,0xff,0xef,0xd7,0xff,0xcf,0xd0,0xf0,0x6f,0xff,0xff, | ||
168 | 0xff,0xfe,0xf8,0x30,0x00,0x00,0x40,0x04,0x00,0x01,0x41,0x20,0x00,0x04,0x00,0x02, | ||
169 | 0xd5,0x09,0x00,0x02,0x80,0x02,0x01,0x00,0x00,0x00,0x0a,0x04,0x00,0x07,0x00,0x01, | ||
170 | 0x50,0x01,0x80,0x02,0x61,0x40,0x41,0x0c,0x14,0x08,0xc1,0xf0,0x9f,0xff,0xff,0xff, | ||
171 | 0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xdf,0xcb,0x5f,0xfe,0xef,0xff,0xfe, | ||
172 | 0xff,0x3f,0xff,0x7f,0xfd,0xc1,0xff,0xff,0x7f,0xff,0xdf,0xfd,0xfc,0xfd,0xf7,0xee, | ||
173 | 0xff,0xff,0x4e,0xff,0xdf,0xcf,0xdb,0xeb,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe, | ||
174 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
175 | 0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
176 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0x7f, | ||
177 | 0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, | ||
178 | 0xf7,0xfb,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
179 | 0xff,0xff,0x7f,0xff,0xff,0xff,0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdd,0xff, | ||
180 | 0xff,0xff,0xa5,0xff,0x6f,0x6b,0xe9,0x6f,0xda,0xca,0xfb,0xdd,0xee,0xf7,0xf6,0xb2, | ||
181 | 0xb3,0xa4,0xa1,0x5b,0x5b,0xf6,0xd7,0xf4,0xf7,0x7b,0xbd,0xbd,0xad,0xcf,0xef,0x7f, | ||
182 | 0x6b,0x7f,0x3b,0xdf,0xdb,0xff,0xff,0x30,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, | ||
183 | 0xff,0xff,0xff,0xf6,0xfe,0x96,0xff,0xfd,0xb5,0xfd,0xbf,0xad,0x7f,0xff,0x6f,0xff, | ||
184 | 0xde,0xd1,0xad,0xad,0xe9,0xff,0xf1,0xec,0xef,0xde,0x3f,0xcb,0xff,0xf6,0xff,0x32, | ||
185 | 0xff,0xc5,0xbd,0xff,0xff,0xff,0xd0,0xbf,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xf4, | ||
186 | 0x28,0xbf,0xff,0xfd,0xfb,0xd3,0xff,0xff,0x42,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3, | ||
187 | 0xc1,0xff,0x33,0xff,0xc0,0x15,0x6b,0x70,0xff,0xf0,0xf2,0x4f,0xff,0xfc,0x3e,0x97, | ||
188 | 0x3c,0xff,0xff,0xfd,0xef,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x78, | ||
189 | 0xbf,0xff,0xfd,0xf3,0xef,0x55,0xff,0x7e,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,0xc1, | ||
190 | 0xff,0x33,0xff,0xc0,0x15,0x6f,0xff,0x0f,0xf0,0xf0,0x0f,0xff,0xfc,0x3d,0x6b,0xc3, | ||
191 | 0xff,0xff,0xfe,0xf7,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff, | ||
192 | 0xff,0x23,0xf8,0x7f,0xff,0x4e,0xff,0xff,0xff,0xfb,0xf9,0x17,0xff,0xf6,0xf1,0xff, | ||
193 | 0xcf,0xef,0xff,0xff,0x13,0xdf,0xe6,0x2f,0xc7,0xff,0xff,0xe7,0xc1,0xfd,0xff,0xfe, | ||
194 | 0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xfe,0xae,0xff, | ||
195 | 0xff,0x7f,0x3b,0x3f,0xfc,0x7f,0xfc,0xef,0xff,0xfc,0xe2,0x7b,0xff,0xf1,0xfd,0xed, | ||
196 | 0xef,0xff,0xff,0x35,0x73,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, | ||
197 | 0xff,0xfa,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, | ||
198 | 0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x00,0x0c,0x04,0x01,0x40,0x40,0x00, | ||
199 | 0x00,0x30,0x28,0x04,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00, | ||
200 | 0x38,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xfb,0xff,0x7f, | ||
201 | 0xff,0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xdf,0xdf,0xff, | ||
202 | 0xff,0xff,0xff,0xed,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xbf,0xbf,0xff,0xff,0xc3, | ||
203 | 0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xfd,0xff,0xbf,0xff,0xff,0xfd,0xff,0xff, | ||
204 | 0xff,0xff,0xff,0xfd,0x7b,0xff,0x7f,0xff,0xbd,0xff,0xf1,0xef,0xff,0xff,0xfd,0xdf, | ||
205 | 0xfd,0xfb,0xff,0xff,0xbf,0xbe,0xff,0xcd,0x7f,0xfc,0xf7,0xf7,0x6f,0xbf,0xd8,0xf0, | ||
206 | 0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x00,0xa0,0x00,0x00, | ||
207 | 0xc0,0x00,0x00,0x20,0x34,0x00,0x00,0x00,0x0c,0x81,0x00,0x20,0xa4,0x20,0x00,0x10, | ||
208 | 0x08,0x04,0x48,0x08,0x00,0x40,0x93,0x00,0x10,0x00,0x38,0x18,0x20,0xc1,0xf0,0x3f, | ||
209 | 0xff,0xff,0xff,0xfe,0xff,0xfb,0xff,0xff,0xb9,0xdf,0xfe,0xb3,0xff,0xff,0xe7,0xfd, | ||
210 | 0xff,0xff,0x3b,0xff,0x7f,0xff,0xbf,0xff,0xc1,0xff,0xfc,0xff,0xff,0x3f,0x77,0xfe, | ||
211 | 0xfe,0xcf,0xff,0xbf,0xfd,0xbf,0xff,0xfe,0xed,0xf2,0xfd,0xf7,0xff,0xf0,0x2f,0xff, | ||
212 | 0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
213 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
214 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff, | ||
215 | 0xff,0xfe,0xff,0xff,0xff,0xf3,0xad,0xcf,0xef,0x70,0xc9,0x73,0x3b,0xdf,0x5b,0x4a, | ||
216 | 0xf6,0xb7,0xfe,0xd7,0xf5,0xbc,0xc1,0x33,0xca,0xd6,0xb7,0x6e,0xf7,0xfb,0xbd,0xc5, | ||
217 | 0x24,0xcf,0x6f,0x2f,0x4d,0x2b,0xba,0x5a,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff, | ||
218 | 0xfe,0xbf,0xff,0xff,0xff,0xff,0xf6,0xf6,0xd7,0xff,0xff,0xad,0xbd,0xff,0xff,0xff, | ||
219 | 0xef,0xf7,0x7f,0xfc,0x5b,0xb1,0xfd,0xbd,0x75,0x6f,0xef,0x6a,0xfd,0x5b,0xfb,0xdb, | ||
220 | 0x3a,0xbf,0x8e,0x9f,0xff,0xbf,0xfd,0xff,0x6f,0xff,0xd0,0x6f,0xff,0xff,0xff,0xfe, | ||
221 | 0xff,0xbb,0xff,0xf0,0x3f,0xff,0xff,0xfd,0xfb,0x7f,0xde,0xff,0xff,0x5a,0xd6,0xbf, | ||
222 | 0xd8,0x2a,0xbf,0xbf,0xf1,0xe5,0xff,0xcc,0xc0,0xa9,0x70,0xff,0xf3,0x3c,0x3c,0xfd, | ||
223 | 0x57,0xfd,0x98,0x03,0x00,0xc3,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff, | ||
224 | 0xff,0xff,0xff,0x3d,0xbf,0xff,0xfd,0xfb,0xff,0xdb,0xff,0xff,0x0f,0xfc,0x3f,0xd8, | ||
225 | 0x2a,0xbf,0xbf,0xf1,0xef,0xff,0xcc,0xc0,0x96,0xbe,0xff,0xf3,0x3f,0xff,0xfd,0x57, | ||
226 | 0xfd,0x99,0x0f,0xff,0xc3,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xff,0xff, | ||
227 | 0xff,0xf1,0xe7,0xff,0xff,0xf3,0x8e,0x7b,0xff,0xa8,0xff,0xdf,0x7f,0x8e,0x78,0x73, | ||
228 | 0xff,0xf1,0x51,0x62,0xff,0xfc,0x4b,0xff,0xf3,0xff,0x7e,0xcf,0xf9,0xff,0xfd,0xff, | ||
229 | 0xff,0x7f,0xff,0xe0,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, | ||
230 | 0xfb,0xfd,0xae,0xff,0xfc,0xfe,0x6f,0x3f,0xf8,0xfd,0x77,0xaf,0xfe,0x37,0xfe,0x7b, | ||
231 | 0xff,0xb1,0x8c,0xff,0xef,0xfd,0xf8,0xe7,0xbf,0xff,0xf1,0xfe,0x3e,0xf7,0xfe,0x95, | ||
232 | 0x3e,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00, | ||
233 | 0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x08, | ||
234 | 0x41,0x80,0x10,0x00,0x00,0x08,0x10,0x84,0x00,0x0c,0x04,0x02,0x61,0x00,0x00,0x81, | ||
235 | 0x00,0x00,0x00,0x00,0x3d,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff, | ||
236 | 0xff,0xff,0x7f,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, | ||
237 | 0x7f,0xbf,0xf7,0x7f,0xef,0xff,0xef,0xff,0xf7,0xfd,0xff,0xff,0xfd,0x7f,0xff,0xbe, | ||
238 | 0xdf,0xff,0xff,0xd9,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0x7f,0xfb,0xff, | ||
239 | 0xfb,0xff,0xbf,0xff,0xf3,0x7f,0xfb,0xfd,0xeb,0x7f,0xdf,0xfa,0xff,0xde,0xf0,0xed, | ||
240 | 0xff,0xb1,0xf7,0xf9,0x1f,0xb5,0x5b,0xfe,0x7e,0xf7,0xbe,0xfd,0x7f,0x5f,0xb5,0xf7, | ||
241 | 0xff,0xff,0xd0,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x01,0x00,0x07,0x42,0x01, | ||
242 | 0x00,0x6a,0x18,0x50,0x80,0x00,0x00,0x02,0x40,0x01,0x01,0x20,0x01,0x01,0x24,0x14, | ||
243 | 0x21,0x10,0x02,0x08,0x07,0x08,0x00,0x40,0x10,0x80,0x58,0x00,0x84,0x80,0x18,0x10, | ||
244 | 0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xff,0xdb,0xb7,0xf3, | ||
245 | 0xdf,0x7c,0xf8,0x74,0xff,0xff,0x6f,0x7d,0x3f,0x7e,0xec,0x7f,0xc1,0xf5,0xff,0xcf, | ||
246 | 0x6f,0x9f,0xf9,0xdf,0xbe,0xe5,0xe7,0xff,0xd7,0xf3,0xdd,0xfb,0xff,0xfc,0xff,0xbf, | ||
247 | 0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
248 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, | ||
249 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
250 | 0xf0,0x2f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xff,0xb4,0xcf,0xef,0x77,0x6f,0x73, | ||
251 | 0x3a,0x4a,0x3a,0xcb,0xd4,0xf7,0x2e,0xd6,0xbd,0xbd,0xa1,0x3b,0xdf,0xd6,0xf7,0xee, | ||
252 | 0xd3,0x35,0xbd,0xfb,0xbd,0xce,0xeb,0x2b,0x4d,0x2f,0xbb,0xda,0xff,0xff,0xfe,0xb0, | ||
253 | 0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdf,0x5f,0x36,0xaf,0x3f,0xed,0xb7, | ||
254 | 0xf5,0xfd,0xf3,0x2b,0xef,0x77,0xff,0xfb,0xda,0xb1,0xbd,0xa3,0x77,0x69,0x7f,0x4f, | ||
255 | 0xff,0xdb,0xfa,0x5b,0xff,0xf2,0xfe,0xff,0x96,0xff,0xff,0xfe,0xdf,0xff,0xd0,0xaf, | ||
256 | 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x8f,0xfd,0x40,0x6f,0x9e,0x83,0x5a,0x0f, | ||
257 | 0xfa,0xc3,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xd0,0x00,0xfe,0xbf,0xcd,0x3f,0xf0, | ||
258 | 0xef,0xfc,0xc5,0x0c,0x3f,0xfd,0x68,0x0b,0xff,0xff,0xff,0xfe,0xdf,0xf0,0xff,0xff, | ||
259 | 0xff,0xff,0xfe,0xff,0xbb,0xff,0xfd,0x85,0xff,0xd4,0x6f,0x9f,0xc3,0x5a,0x0f,0xff, | ||
260 | 0xff,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xf0,0xfb,0xc2,0xbf,0xfc,0x00,0x37,0xef, | ||
261 | 0xfc,0xcd,0xbc,0x3f,0xff,0x0c,0xbf,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff, | ||
262 | 0xff,0xfe,0xff,0xff,0xff,0xff,0xd9,0xf7,0xd1,0xb7,0x7e,0x7f,0xf1,0xe4,0xfd,0xff, | ||
263 | 0xfb,0xfb,0xff,0x5f,0xff,0x7f,0xb1,0xbc,0x0f,0x67,0xeb,0xb8,0x3f,0xff,0xe2,0xff, | ||
264 | 0xe9,0xff,0xfd,0xe3,0xff,0x3f,0x9f,0xc2,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff, | ||
265 | 0xfe,0xf5,0x7f,0xff,0xf0,0x3f,0xbc,0xff,0xd5,0xf5,0xce,0x3f,0xfe,0xff,0xfe,0x6d, | ||
266 | 0xff,0xf1,0xbf,0x7b,0xff,0xf1,0xfd,0xff,0x4f,0xff,0x87,0xff,0xae,0xff,0xb1,0xf8, | ||
267 | 0xfe,0xff,0xff,0x78,0x01,0xb9,0xff,0xff,0xff,0xfa,0xf0,0x2f,0xff,0xff,0xff,0xfe, | ||
268 | 0xf3,0xc0,0x00,0x00,0x00,0x04,0x02,0x13,0x02,0x00,0x80,0x40,0x00,0x90,0x10,0x00, | ||
269 | 0x10,0x00,0x02,0x00,0x01,0x20,0x80,0x12,0x10,0x00,0x40,0x08,0x00,0x04,0x00,0x00, | ||
270 | 0x02,0x00,0x01,0x40,0x00,0x80,0x00,0x00,0x3c,0xf0,0xef,0xff,0xff,0xff,0xfe,0xfd, | ||
271 | 0x1f,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xf7,0xdf,0xf7,0xff, | ||
272 | 0xf7,0xfb,0xeb,0xd1,0xff,0xff,0xff,0xff,0xef,0xf7,0xff,0xff,0xfb,0xff,0xfe,0xff, | ||
273 | 0xff,0x7e,0xff,0xfb,0xff,0xff,0xff,0xdb,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf0,0xff, | ||
274 | 0xff,0xb7,0xeb,0xf7,0xdf,0xff,0xfe,0xf5,0x6b,0xe7,0xed,0xf7,0x3e,0xec,0xff,0x54, | ||
275 | 0xef,0x6f,0xf1,0xf5,0xaf,0x6f,0xf6,0xfd,0xff,0xdd,0x7b,0xff,0xef,0xbf,0x7f,0xff, | ||
276 | 0xff,0xf7,0xff,0xf3,0x5f,0xf7,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00, | ||
277 | 0x80,0x40,0x04,0x00,0x81,0x2c,0x04,0x24,0x00,0x02,0x01,0xc8,0x02,0x00,0x02,0x24, | ||
278 | 0x00,0x01,0xb4,0x42,0xdc,0x44,0x02,0x15,0x90,0x02,0x03,0x48,0x39,0x10,0x02,0x24, | ||
279 | 0xa0,0xba,0x00,0x00,0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, | ||
280 | 0xfe,0xfc,0xf7,0xf0,0xee,0xb6,0x5d,0xfd,0xf5,0xff,0xdb,0xf7,0x7f,0x7f,0xbe,0xff, | ||
281 | 0xc1,0xfe,0xbf,0xfa,0xfa,0x5f,0xff,0xad,0xff,0xef,0xff,0x7f,0xdf,0x7f,0xfe,0xbf, | ||
282 | 0xb7,0x94,0xbf,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, | ||
283 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, | ||
284 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
285 | 0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xfb,0xb5,0xff, | ||
286 | 0xef,0x7c,0xeb,0x2b,0x52,0x5b,0x3b,0xda,0xd4,0xf3,0x36,0x96,0xb5,0xbd,0xf1,0xfb, | ||
287 | 0xda,0xee,0xf6,0xfe,0xd3,0x35,0xbd,0xdf,0xad,0xcf,0xef,0x7e,0xcd,0x6b,0xbb,0xdf, | ||
288 | 0xff,0xff,0xfd,0xb0,0xef,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xd3,0x5f,0xf6, | ||
289 | 0xff,0xf6,0xff,0xfd,0xad,0xfd,0xff,0x7f,0xef,0xff,0x6f,0x7f,0xdb,0xf1,0xa5,0xa3, | ||
290 | 0x7f,0x6f,0x6b,0x4f,0xff,0xdb,0xfb,0xcb,0xff,0xf6,0xff,0xf4,0xd7,0xfd,0xbf,0xfe, | ||
291 | 0xdf,0xff,0xd0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdf,0xff,0xff,0xff, | ||
292 | 0x3f,0x7f,0xfc,0xe5,0xff,0x20,0xfe,0xff,0xff,0xdf,0x7f,0xff,0xf1,0x7f,0xff,0xfe, | ||
293 | 0xff,0xf0,0x7c,0x3d,0x4f,0xf3,0xc3,0x3f,0xff,0xff,0x6f,0xc3,0xff,0x0f,0xff,0xff, | ||
294 | 0xaf,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0xb7,0xe0,0x0f,0xff,0xff,0x2b, | ||
295 | 0xff,0x7d,0xbf,0xff,0xdf,0xff,0xff,0xf8,0x9f,0x7f,0xff,0xf1,0x55,0xff,0xff,0xff, | ||
296 | 0xfd,0x7c,0x3c,0xff,0xf3,0xc3,0x3f,0xff,0xff,0xef,0xc3,0xff,0xdf,0xff,0xff,0xff, | ||
297 | 0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0x9f,0xbf,0x7f, | ||
298 | 0xf9,0x19,0x47,0x8e,0xe7,0x9f,0x3f,0x17,0xff,0xfc,0x81,0xc1,0x7e,0xf3,0xd9,0xf9, | ||
299 | 0x73,0xdf,0xf4,0x7f,0xfa,0xff,0xff,0xff,0xfb,0x7f,0x77,0xc7,0xff,0xff,0xff,0xf0, | ||
300 | 0x2f,0xff,0xff,0xff,0xfe,0xf5,0xf7,0xff,0xfb,0xff,0xf7,0x3f,0xfc,0xbf,0x3e,0x3f, | ||
301 | 0xec,0xff,0x81,0xaf,0xfe,0x4f,0xf3,0xbb,0xff,0xf0,0x7e,0xff,0x6f,0xff,0x87,0xff, | ||
302 | 0xbb,0xff,0xd5,0xfc,0xff,0x7f,0xfc,0x6f,0xff,0xef,0xe7,0xff,0xff,0xfa,0xf0,0x3f, | ||
303 | 0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, | ||
304 | 0x00,0x30,0x10,0x60,0x20,0x00,0x08,0x00,0x01,0x20,0x80,0x00,0x10,0x00,0x04,0x00, | ||
305 | 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x40,0x00,0x08,0x20,0x3c,0xf0,0x6f,0xff, | ||
306 | 0xff,0xff,0xfe,0xf5,0xbf,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x7f,0xfe,0x3f,0xff, | ||
307 | 0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xf1,0xdf,0xdf,0xff,0xff,0xff,0x7f,0xdf,0xff, | ||
308 | 0xfd,0xbd,0xff,0xff,0xff,0xfb,0xdf,0xff,0xff,0xff,0xff,0x5b,0xf0,0xff,0xff,0xff, | ||
309 | 0xff,0xfe,0xf0,0xbf,0xbf,0xbf,0xff,0xf7,0xfb,0xff,0xfe,0xee,0xfa,0xff,0xff,0xff, | ||
310 | 0x3d,0x3b,0xff,0xff,0xfe,0xfb,0xf1,0xff,0xbf,0x7b,0xff,0xff,0xef,0xff,0xbf,0xff, | ||
311 | 0xff,0xff,0xff,0xff,0xfe,0xff,0xf7,0xef,0xff,0xfb,0xd0,0xf0,0xdf,0xff,0xff,0xff, | ||
312 | 0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x00,0x0b,0x10,0x05,0x01,0x00,0x08,0x00,0x02, | ||
313 | 0x01,0x01,0x00,0x00,0x10,0x01,0xc8,0x08,0x00,0x00,0x00,0x00,0x42,0x02,0x00,0x00, | ||
314 | 0x00,0x80,0x02,0x00,0x00,0x40,0x24,0x80,0x00,0xc1,0xf0,0x3f,0xff,0xff,0xff,0xfe, | ||
315 | 0xff,0xff,0xff,0xff,0xf7,0xfd,0xf7,0xfa,0xef,0xee,0xf9,0xfd,0xff,0xf7,0xfe,0xbf, | ||
316 | 0x1f,0xfd,0x9e,0xfd,0xd1,0xef,0xff,0xf7,0x7f,0x9f,0xff,0xef,0xff,0xf6,0xff,0xfe, | ||
317 | 0xfe,0x7b,0xff,0xbd,0xff,0x7e,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, | ||
318 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
319 | 0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
320 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,0xff, | ||
321 | 0xff,0xf7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xfd,0xff,0xff,0xdf,0xff, | ||
322 | 0xff,0x5f,0xf1,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
323 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xef,0xff, | ||
324 | 0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfb,0xff,0xff,0xef,0xfb,0xfd, | ||
325 | 0xff,0xf1,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
326 | 0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf7,0xff,0xff,0xff, | ||
327 | 0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xe7,0xff, | ||
328 | 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
329 | 0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, | ||
330 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfb,0xff,0xfb,0xf1, | ||
331 | 0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
332 | 0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, | ||
333 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7b,0xff,0xff,0xff,0x7f,0xff,0xf1,0xff, | ||
334 | 0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
335 | 0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xff,0xff, | ||
336 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x57,0xff,0xfe,0xbf,0xfb,0xf1,0xff,0xff, | ||
337 | 0xfd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
338 | 0xd7,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, | ||
339 | 0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xef,0x2f,0xf1,0x3c,0xbf,0xbc, | ||
340 | 0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, | ||
341 | 0x01,0xe2,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
342 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
343 | 0xff,0xff,0xff,0xff,0xff,0xff }; | ||
diff --git a/drivers/net/hamradio/yam9600.h b/drivers/net/hamradio/yam9600.h new file mode 100644 index 000000000000..5ed1fe6ff43e --- /dev/null +++ b/drivers/net/hamradio/yam9600.h | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * | ||
3 | * File yam111.mcs converted to h format by mcs2h | ||
4 | * | ||
5 | * (C) F6FBB 1998 | ||
6 | * | ||
7 | * Tue Aug 25 20:23:03 1998 | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | static unsigned char bits_9600[]= { | ||
12 | 0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xfb,0xcb,0xff,0xdb,0xfe,0xf2, | ||
13 | 0xff,0xf6,0xff,0x9c,0xbf,0xfd,0xbf,0xef,0x2e,0x3f,0x6f,0xf1,0xfd,0xb4,0xfd,0xbf, | ||
14 | 0xff,0x6f,0xff,0x6f,0xff,0x0b,0xff,0xdb,0xff,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, | ||
15 | 0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xff,0xff,0xff,0xf7,0xff,0xff,0xff, | ||
16 | 0xfb,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0x7f,0xf1,0xff,0xfe,0xff,0xbf,0xbf, | ||
17 | 0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xf0, | ||
18 | 0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xf7, | ||
19 | 0xff,0xff,0xf7,0xef,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0x7e,0xff,0xff, | ||
20 | 0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0xdf, | ||
21 | 0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
22 | 0xff,0xff,0xef,0xff,0xf3,0xfb,0xfe,0xff,0xf1,0xff,0xfd,0xff,0xff,0xff,0xff,0xff, | ||
23 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdf,0xff,0xf0,0x7f,0xff, | ||
24 | 0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
25 | 0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff, | ||
26 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, | ||
27 | 0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, | ||
28 | 0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5, | ||
29 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, | ||
30 | 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xef,0xff,0x7f,0xff,0xef, | ||
31 | 0xff,0xef,0xff,0x7f,0xef,0xf1,0xff,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, | ||
32 | 0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe, | ||
33 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
34 | 0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
35 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff, | ||
36 | 0xff,0xff,0xff,0xbd,0xff,0xef,0x7f,0xef,0x7f,0xfb,0xdf,0xd3,0x5a,0xfe,0xd7,0xd6, | ||
37 | 0xf7,0x7f,0xbd,0xf1,0xbb,0x5d,0xd6,0xf7,0xfe,0x96,0xff,0xbd,0xaf,0xad,0xbf,0xef, | ||
38 | 0x7f,0x6b,0x7f,0xfb,0xd6,0xfe,0xf7,0xff,0x10,0xef,0xff,0xff,0xff,0xfe,0xbe,0xef, | ||
39 | 0xff,0xff,0xdb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xbf,0xff,0x7f,0xff,0x7f, | ||
40 | 0xdf,0xdb,0xf1,0xfd,0x35,0xff,0x6f,0xff,0x6f,0xff,0xdb,0xff,0xcb,0xff,0xf6,0xff, | ||
41 | 0xf2,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, | ||
42 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff, | ||
43 | 0xff,0xf1,0x24,0xf0,0xff,0xff,0xcf,0xef,0x3f,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f, | ||
44 | 0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, | ||
45 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,0xff, | ||
46 | 0xf1,0x00,0xf0,0xff,0xff,0xcf,0xdf,0xff,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,0xff, | ||
47 | 0xff,0xff,0x7d,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, | ||
48 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfe,0x7f,0xdf,0xff,0xff,0xff,0xf1, | ||
49 | 0xff,0xcf,0xff,0xf3,0xff,0x97,0xff,0xff,0x8f,0xe7,0xff,0xff,0xfc,0x71,0xff,0xff, | ||
50 | 0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xff,0xff, | ||
51 | 0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xf7,0xef,0xff,0xff,0xfc,0x7b,0xff,0xf1,0x3f, | ||
52 | 0xff,0xef,0xff,0xcf,0xe3,0xe3,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xbf,0xff, | ||
53 | 0xbf,0xff,0xda,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x00,0x00,0x00,0x00,0x00, | ||
54 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, | ||
55 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, | ||
56 | 0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff, | ||
57 | 0xff,0xff,0xff,0xff,0xff,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0x9f,0xff, | ||
58 | 0xff,0xff,0xf7,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
59 | 0xdb,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xdf,0xff,0xff,0xff,0xff,0xff,0xff, | ||
60 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xdf,0xbf,0xf1,0xfe,0xfd,0xf7,0xff, | ||
61 | 0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xfd,0xf2, | ||
62 | 0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, | ||
63 | 0x00,0x00,0x00,0x02,0x00,0x90,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x04,0x24,0x00, | ||
64 | 0x40,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0xc0,0xf0, | ||
65 | 0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
66 | 0xff,0xff,0xbf,0xff,0xff,0x6f,0xff,0xdf,0xff,0xd1,0xff,0xfe,0xff,0xff,0xff,0xff, | ||
67 | 0xff,0xff,0xdf,0xff,0xfb,0xff,0xfb,0xef,0xff,0xff,0xee,0xff,0xff,0x7f,0xf0,0xdf, | ||
68 | 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
69 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
70 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff, | ||
71 | 0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xad,0xff,0x69,0x2a,0xed,0x6b,0xfb,0xdf,0x3a, | ||
72 | 0xdc,0xf4,0x96,0xee,0xb3,0x3d,0x35,0xc1,0xbb,0xdd,0xfe,0xf6,0xfe,0xd6,0xb5,0xad, | ||
73 | 0xbf,0xa5,0xad,0x49,0x2f,0x4f,0x2b,0xda,0x5f,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff, | ||
74 | 0xff,0xfe,0xbf,0xff,0xff,0xfb,0x5b,0xf7,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xa5, | ||
75 | 0xf3,0x6f,0xf3,0x6e,0xfa,0x7b,0xd1,0xfd,0xb5,0x77,0x6f,0xe9,0x6f,0xff,0xdb,0xfb, | ||
76 | 0xdb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0x3f,0xfe,0xf7,0xff,0xd0,0x4f,0xff,0xff,0xff, | ||
77 | 0xfe,0xff,0x9f,0xff,0xff,0x0f,0xff,0xc0,0x3f,0x9c,0x03,0xff,0xff,0x8b,0xa5,0xfe, | ||
78 | 0x80,0x3e,0xc2,0xbf,0xac,0xb1,0x24,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xa3, | ||
79 | 0xff,0xfd,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe, | ||
80 | 0xff,0xff,0xff,0xff,0x0f,0xff,0xc0,0x3f,0xd4,0x6b,0xff,0xff,0xdb,0xff,0xfe,0x86, | ||
81 | 0xbf,0xc2,0xbf,0x30,0xa1,0x24,0xff,0xff,0xff,0xff,0xcc,0xff,0x0f,0xff,0xa3,0xff, | ||
82 | 0x05,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff, | ||
83 | 0xff,0xff,0xfb,0xc7,0xff,0xc4,0xff,0xff,0x7f,0xff,0xec,0xfe,0x7f,0xdf,0xd8,0xb9, | ||
84 | 0x47,0xfc,0x36,0xc1,0xdf,0xff,0xff,0xf9,0xff,0xf3,0xff,0xf7,0xff,0xfc,0xff,0xfd, | ||
85 | 0x3f,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff, | ||
86 | 0xff,0xff,0xff,0xfe,0xff,0xff,0x7e,0xbd,0x3f,0xff,0x2b,0xfe,0x2f,0xf5,0xa3,0xfc, | ||
87 | 0x5b,0xfe,0x61,0x9f,0x7f,0xef,0xff,0xff,0xa7,0xfb,0xff,0xff,0xfa,0xfe,0xff,0x33, | ||
88 | 0xf1,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, | ||
89 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x24,0x04, | ||
90 | 0x00,0x01,0x00,0x80,0x40,0x00,0x08,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x02,0x00, | ||
91 | 0x00,0x00,0x00,0x00,0x01,0x3d,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xfd,0xbd,0xff,0xfd, | ||
92 | 0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,0xf6,0xef,0xbf,0xf7,0xff,0x73,0xeb, | ||
93 | 0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xfd,0xfe,0xff,0xff, | ||
94 | 0xff,0xff,0xff,0xff,0xd9,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,0xbf,0x7f,0xff,0xff, | ||
95 | 0xff,0x7f,0xff,0xff,0xde,0xff,0xff,0xef,0xdd,0xde,0x77,0xf2,0xfb,0xed,0xe7,0xf1, | ||
96 | 0x73,0xfd,0xfd,0xdf,0xff,0x7d,0xbe,0xdf,0xff,0xfb,0xff,0xef,0xff,0xef,0xff,0xff, | ||
97 | 0xff,0xff,0xff,0xd0,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x02,0x00,0x22, | ||
98 | 0x40,0xc0,0x00,0x00,0x00,0x08,0x00,0x02,0x41,0x02,0x12,0x00,0x21,0x87,0x81,0x00, | ||
99 | 0x00,0x80,0x04,0x0b,0x28,0x01,0xb0,0x00,0x82,0x00,0x40,0x00,0x00,0x00,0x00,0x00, | ||
100 | 0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xfd,0xff, | ||
101 | 0xf7,0xff,0xfe,0x7f,0xed,0x79,0xff,0xde,0xeb,0x7f,0x74,0xf7,0xf7,0xe1,0xf9,0xff, | ||
102 | 0xf6,0x5f,0x7f,0xff,0xff,0xff,0xd7,0xdb,0xef,0xff,0xbb,0xff,0xff,0xff,0xcc,0xff, | ||
103 | 0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
104 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, | ||
105 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
106 | 0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x3d,0xcd,0x49,0x7f,0x6f, | ||
107 | 0x2b,0xba,0x5c,0xd2,0xda,0xf6,0xf3,0x3e,0xf7,0xff,0xbd,0xf1,0xfa,0xdf,0xfe,0xf7, | ||
108 | 0xcc,0xf6,0xbb,0xa5,0xb3,0xad,0xbf,0x6f,0x7d,0x6f,0x6b,0xdb,0xdf,0xbd,0xff,0xfe, | ||
109 | 0xb0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xfb,0xdb,0x57,0xf6,0xfe,0x9f,0xd5, | ||
110 | 0xb7,0xff,0xaf,0xe5,0x3f,0xff,0xff,0x6f,0xff,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0x69, | ||
111 | 0x6c,0xdf,0xda,0xdf,0xcb,0xff,0xf6,0xff,0x76,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0, | ||
112 | 0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfd,0xbd,0x08,0x03,0x89,0x4f,0x5a, | ||
113 | 0x0f,0xf0,0xff,0xf8,0xbf,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xf3, | ||
114 | 0xfa,0xa0,0xf0,0xf2,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff, | ||
115 | 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xfd,0x00,0x6b,0xff,0xff,0x5a,0x0f, | ||
116 | 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xb3,0xf5, | ||
117 | 0x50,0xf0,0xf0,0xff,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff, | ||
118 | 0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xbc,0xff,0xe4,0xe7,0x71,0xff,0xf9,0xc4,0xf4, | ||
119 | 0x7f,0x7f,0xcf,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xfb,0xf7,0x73,0xbf,0x14, | ||
120 | 0xff,0xe6,0xff,0xff,0xe1,0x7d,0xff,0xff,0xe7,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff, | ||
121 | 0xff,0xfe,0xf5,0xff,0xff,0xfe,0xd2,0xfa,0xff,0xc4,0xf4,0x5c,0xbf,0xfa,0xff,0xff, | ||
122 | 0xec,0x7e,0xbf,0xff,0xff,0xff,0xf1,0xff,0xff,0xef,0xff,0xff,0x6b,0xdb,0xff,0xdf, | ||
123 | 0xf9,0xfb,0xbf,0xff,0xf1,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf0,0xbf,0xff,0xff,0xff, | ||
124 | 0xfe,0xf3,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x80,0x00, | ||
125 | 0x00,0x00,0x00,0x40,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x20,0x00,0x00,0x00,0x00, | ||
126 | 0x01,0x00,0x01,0x00,0x00,0x80,0x02,0x00,0x01,0x3c,0xf0,0x5f,0xff,0xff,0xff,0xfe, | ||
127 | 0xfd,0xbf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0x7f,0xff,0xdf,0xff,0xef,0xff, | ||
128 | 0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff, | ||
129 | 0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xc3,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf0, | ||
130 | 0xff,0xdf,0xff,0xff,0xf7,0x23,0xff,0xff,0xfd,0xff,0xef,0xff,0xfe,0x7f,0x7d,0xf7, | ||
131 | 0xfe,0xff,0x7f,0x71,0xff,0xfb,0x7f,0xff,0xff,0xff,0x6e,0xfd,0xf7,0xfd,0xff,0xbf, | ||
132 | 0xff,0xbf,0xf9,0xfd,0xff,0xdf,0xef,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x30, | ||
133 | 0x40,0x01,0x00,0x83,0x00,0x00,0x00,0x0c,0x06,0x08,0x04,0x26,0x26,0x00,0x00,0x06, | ||
134 | 0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x70,0x08,0x80,0x00,0x20,0x01,0x20, | ||
135 | 0x00,0x02,0x00,0x30,0x00,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, | ||
136 | 0xff,0xff,0x7b,0x3f,0xf7,0xff,0xd7,0xfe,0xfe,0xfb,0xfe,0x3b,0xfe,0xbd,0xff,0x2f, | ||
137 | 0xff,0x71,0xff,0xfb,0x7f,0xe7,0xff,0xf9,0xef,0xff,0xd7,0xfa,0xff,0xb7,0xbb,0xfe, | ||
138 | 0xff,0xff,0x74,0xff,0xf7,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, | ||
139 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
140 | 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
141 | 0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xb5, | ||
142 | 0xbd,0x6f,0x7c,0xeb,0x7f,0xfb,0xdb,0xd3,0x4b,0xee,0xd6,0xf6,0xb7,0xfd,0xac,0xa1, | ||
143 | 0xfb,0xdf,0xfe,0xf7,0xf4,0x96,0xbd,0xb4,0xc5,0xa5,0xaf,0x6f,0x69,0x4f,0x7f,0xba, | ||
144 | 0xdb,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, | ||
145 | 0xf6,0xff,0xf6,0xff,0xbd,0xbf,0xa5,0xbf,0xff,0x7d,0x7f,0xef,0xff,0xfb,0xf1,0xfd, | ||
146 | 0xbf,0xff,0x6f,0xff,0x6b,0x7a,0xdb,0xff,0xdb,0xdf,0xf6,0xfe,0xb6,0xfd,0xfd,0xbf, | ||
147 | 0xfe,0xf7,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf4,0x2f,0xff, | ||
148 | 0xfc,0x43,0x6b,0xff,0xff,0xff,0x0d,0xff,0xfc,0x33,0x3f,0xf0,0x5f,0xf1,0xff,0xff, | ||
149 | 0xff,0xff,0xf9,0xde,0xf0,0x4c,0xfe,0x77,0xaf,0xff,0xff,0xef,0xff,0xf0,0xff,0xdb, | ||
150 | 0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xfe,0xf7,0xff,0xf0,0x2f,0xff,0xfd, | ||
151 | 0x43,0x7f,0xff,0xff,0xf1,0x0f,0xff,0xfc,0x33,0x3f,0xff,0xaf,0xf1,0xff,0xff,0xff, | ||
152 | 0xff,0xf6,0xd7,0xff,0xbc,0xfd,0xbd,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, | ||
153 | 0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xfb,0xf1, | ||
154 | 0xbf,0xff,0xf9,0xfd,0xcf,0xf2,0x70,0xff,0x1f,0x9f,0xf3,0xf1,0xff,0xff,0xff,0xff, | ||
155 | 0xfc,0xf7,0xff,0x13,0x9f,0xfc,0xff,0xff,0x84,0xf7,0xff,0xff,0x47,0xff,0xff,0xff, | ||
156 | 0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xf1,0xfc,0xff,0xfe,0xfe,0x79, | ||
157 | 0x3f,0xff,0x1d,0x46,0xcf,0xff,0xcf,0xfc,0x7b,0xff,0xf1,0xff,0xff,0xff,0xff,0xed, | ||
158 | 0xf3,0xab,0xff,0xcb,0xff,0xf8,0xff,0xfc,0xf5,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0, | ||
159 | 0x8f,0xff,0xff,0xff,0xfe,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, | ||
160 | 0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x20, | ||
161 | 0x0c,0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x01,0x3c,0xf0,0x7f, | ||
162 | 0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff, | ||
163 | 0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xef,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, | ||
164 | 0xff,0xdf,0xff,0xff,0xfb,0xf7,0x7f,0xff,0xfe,0xff,0xff,0xbf,0xdb,0xf0,0xff,0xff, | ||
165 | 0xff,0xff,0xfe,0xf0,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0x7f,0xf7,0xff, | ||
166 | 0xbf,0xbf,0xcf,0xff,0xff,0xff,0x3e,0xf1,0x7f,0xff,0xff,0xef,0xff,0xff,0xff,0xfe, | ||
167 | 0xff,0xfd,0xff,0xbf,0xbd,0xfe,0xff,0xfb,0xf7,0xdf,0xfb,0xd0,0xf0,0x9f,0xff,0xff, | ||
168 | 0xff,0xfe,0xf8,0x30,0x20,0x00,0x40,0x01,0x80,0xc0,0x30,0x00,0x00,0x20,0x00,0x10, | ||
169 | 0x50,0x88,0x20,0x00,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00, | ||
170 | 0x00,0x00,0x01,0x80,0x08,0x00,0x00,0xa0,0x00,0x10,0xc1,0xf0,0xef,0xff,0xff,0xff, | ||
171 | 0xfe,0xfd,0xef,0x7f,0xff,0xff,0xbf,0xff,0xf7,0xff,0xef,0xfb,0xfd,0x77,0xef,0xbf, | ||
172 | 0xf7,0x7f,0xff,0xff,0xbf,0xd1,0x7f,0xff,0xff,0xf7,0xff,0xff,0xff,0xff,0xaf,0xff, | ||
173 | 0xdf,0xf7,0xfb,0xff,0xfd,0xff,0xfc,0xff,0xfd,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, | ||
174 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
175 | 0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
176 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff, | ||
177 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, | ||
178 | 0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
179 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x3f,0xff,0xff,0xff,0xfe,0xdd,0xff, | ||
180 | 0xff,0xff,0xa5,0xfd,0x6f,0x7d,0x6d,0x7f,0x52,0xdf,0x5a,0x4b,0xee,0xb6,0xee,0xf2, | ||
181 | 0xbb,0xac,0xa1,0x5b,0x4d,0xd6,0xf7,0xfe,0xb2,0xbd,0x35,0xb5,0xb5,0xdd,0x6f,0x7f, | ||
182 | 0xe9,0x5f,0x52,0xdf,0xbd,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, | ||
183 | 0xff,0xdb,0xfe,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xb5,0xbf,0xf9,0x7f,0x6f,0xff, | ||
184 | 0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0x69,0x7f,0xdb,0xff,0xd3,0xff,0xf6,0xfe,0xf2, | ||
185 | 0xff,0xad,0xbf,0xff,0xff,0xff,0xd0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5, | ||
186 | 0x30,0x0f,0xff,0xff,0xfd,0x6b,0xca,0xff,0xf0,0x0f,0xd6,0xbf,0xcf,0x3f,0xff,0xff, | ||
187 | 0xf1,0xff,0xff,0xff,0xca,0xfe,0xbf,0xff,0xf0,0x05,0xaf,0x0f,0xff,0xfc,0xf0,0xcf, | ||
188 | 0xf0,0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0x30, | ||
189 | 0x0f,0xff,0xff,0xfc,0x3f,0xca,0xff,0x0f,0x0f,0xd6,0xbf,0xff,0xff,0xf5,0x5f,0xf1, | ||
190 | 0xff,0x8b,0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xfc,0xf0,0xcf,0xf0, | ||
191 | 0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xcf,0xff, | ||
192 | 0xff,0xbf,0x9f,0x3f,0xfe,0xfc,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xf7,0xf1,0xff, | ||
193 | 0xdf,0xfe,0x7e,0x3f,0x9f,0xf4,0xfc,0x7f,0xfc,0xff,0xff,0x3f,0xff,0x3f,0xfe,0x3f, | ||
194 | 0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfb,0xff,0xfe,0xff, | ||
195 | 0xff,0xff,0xff,0xbf,0xfb,0xff,0xf8,0xed,0xff,0x8f,0xff,0xbb,0xff,0xb1,0xf3,0xef, | ||
196 | 0x8f,0xf7,0xff,0xff,0xdb,0xff,0xff,0xff,0xef,0xbf,0xfd,0x79,0xbf,0xbf,0xff,0xff, | ||
197 | 0xff,0xfb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x04,0x00,0x00, | ||
198 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04,0x08,0x08,0x01,0x01,0x00,0x90, | ||
199 | 0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x00,0x01, | ||
200 | 0x3c,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
201 | 0xff,0xff,0xff,0xff,0x9f,0xff,0xaf,0xdf,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, | ||
202 | 0xbf,0xef,0xff,0xff,0xff,0xed,0xff,0xff,0xff,0xef,0xff,0xbf,0xff,0xff,0xff,0xc3, | ||
203 | 0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xfd,0xff,0xff,0xff,0xfb,0xff,0xbb,0xff, | ||
204 | 0xff,0xff,0x7f,0xf6,0xff,0x7f,0xfb,0xfd,0xed,0xff,0xf1,0xff,0xfe,0x7f,0xff,0xff, | ||
205 | 0xff,0x5f,0xff,0xf7,0xff,0x7e,0xff,0xfd,0xff,0xef,0xff,0xff,0xff,0xef,0xf0,0xf0, | ||
206 | 0x8f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x80,0x00,0x04,0x00,0x00,0x40,0x02,0x00,0x03, | ||
207 | 0x00,0x05,0x04,0x20,0x00,0x00,0x01,0xd0,0x00,0x81,0x00,0x20,0x04,0x04,0x00,0x00, | ||
208 | 0x81,0x04,0x08,0x80,0x10,0x00,0xc0,0x00,0x00,0x00,0x20,0x00,0x08,0xc1,0xf0,0x6f, | ||
209 | 0xff,0xff,0xff,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xf3,0xfd,0xff,0xed,0xfc, | ||
210 | 0xff,0xff,0x9f,0xfb,0xfd,0xff,0xff,0xff,0xf1,0xff,0xff,0x7f,0xfb,0x3e,0xff,0x9f, | ||
211 | 0xff,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0x6f,0xff, | ||
212 | 0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
213 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
214 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff, | ||
215 | 0xff,0xfe,0xff,0xff,0xff,0xfd,0xbd,0xff,0xef,0x7c,0xeb,0x7f,0xfb,0xdb,0xfa,0xdc, | ||
216 | 0xee,0xf7,0xf6,0xd7,0xf5,0x2d,0xa1,0xbb,0xdd,0xee,0xf7,0x54,0xf7,0xfb,0x2c,0xb5, | ||
217 | 0xb4,0xbd,0x6b,0x6f,0xef,0x6f,0xbb,0xdf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff, | ||
218 | 0xfe,0xbf,0xff,0xff,0xff,0xfb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xff,0xbf,0xef, | ||
219 | 0x6f,0xff,0x6f,0xfa,0xdb,0xf1,0xc5,0xbd,0xf5,0x6f,0xff,0x6f,0xca,0xdb,0xff,0xdb, | ||
220 | 0xfb,0xf6,0x97,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x9f,0xff,0xff,0xff,0xfe, | ||
221 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0x7f,0xff,0xff,0xe7,0x63,0xff,0xff, | ||
222 | 0xff,0xfc,0x77,0xdf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff, | ||
223 | 0xc3,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff, | ||
224 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
225 | 0xfc,0xff,0xcf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,0xc3, | ||
226 | 0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff, | ||
227 | 0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xbf,0xff,0xca,0xff,0x9f,0xff,0xfa,0xb9,0xe7, | ||
228 | 0x9f,0xf3,0x81,0xff,0xff,0xfc,0x73,0xd7,0xff,0xff,0x77,0xff,0xfd,0xff,0xfc,0xff, | ||
229 | 0xff,0xff,0xff,0xcf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, | ||
230 | 0xff,0xf7,0xde,0xff,0xfe,0x7e,0xff,0xbf,0xff,0xbf,0xf1,0xb3,0xff,0xff,0xe3,0xfb, | ||
231 | 0xff,0xe1,0x1f,0x7f,0xff,0xf8,0x78,0xff,0xfb,0x1e,0xff,0xf7,0xfe,0xe7,0xff,0xff, | ||
232 | 0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00, | ||
233 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x04,0x00, | ||
234 | 0x01,0x80,0x40,0x40,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, | ||
235 | 0x80,0x00,0x00,0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xff, | ||
236 | 0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xf7,0xf1, | ||
237 | 0xfd,0xff,0xff,0xff,0xdf,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, | ||
238 | 0xff,0xff,0xff,0xdb,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xdf,0xff,0xff,0x7f, | ||
239 | 0xff,0xff,0xff,0xbe,0xd7,0xff,0xed,0xbd,0x7e,0xbf,0xfe,0xf6,0x7f,0xbf,0x71,0xff, | ||
240 | 0xff,0xda,0xff,0xf9,0xff,0xbf,0x7f,0xfe,0xff,0x6f,0x7f,0xff,0xff,0xff,0xff,0xff, | ||
241 | 0x7f,0xff,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x42,0x00,0x00,0x00,0x00, | ||
242 | 0x80,0xc1,0x00,0x00,0x90,0x00,0xc4,0x00,0x00,0x12,0x20,0x43,0x22,0x81,0x84,0x00, | ||
243 | 0x00,0x14,0x00,0x01,0x00,0x08,0x80,0x00,0x02,0x00,0x02,0x00,0x04,0x02,0x00,0x00, | ||
244 | 0x10,0xc1,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfd,0xff,0xff,0xdd,0xfe,0xff, | ||
245 | 0xb6,0x76,0xe5,0xbc,0xf9,0xf7,0xaf,0x5f,0xbf,0xfc,0xdf,0xcf,0xf1,0xff,0xef,0x79, | ||
246 | 0xff,0xbd,0xff,0xef,0xff,0xff,0xf7,0x6f,0x5f,0xff,0xff,0xfd,0xef,0xef,0xbf,0xff, | ||
247 | 0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
248 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, | ||
249 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
250 | 0xf0,0xff,0xff,0xff,0xff,0xfe,0xdb,0xff,0xff,0xfd,0x2d,0xff,0x69,0x2a,0xef,0x77, | ||
251 | 0xbb,0xdd,0x5a,0xdf,0xf6,0xf6,0xd6,0xf7,0x7d,0xbd,0xd1,0xb2,0x4a,0xd6,0xb2,0xbe, | ||
252 | 0x97,0xf5,0xbd,0xb3,0xad,0xff,0xef,0x7f,0x69,0x6b,0xfb,0xdf,0xff,0xff,0xff,0xf0, | ||
253 | 0x2f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0x9f,0xd4,0xbf, | ||
254 | 0xed,0xaf,0xff,0x6b,0x6f,0xf7,0xff,0xdd,0xdb,0x31,0xfd,0xbf,0xff,0x6f,0x7f,0xff, | ||
255 | 0xff,0xdb,0xff,0xcb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x8f, | ||
256 | 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff, | ||
257 | 0xa5,0xff,0xff,0xff,0xdf,0xb7,0xff,0xff,0xf1,0xff,0xff,0xff,0xf7,0xe9,0x6a,0xbf, | ||
258 | 0xff,0xff,0xfd,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xaf,0xf0,0x4f,0xff, | ||
259 | 0xff,0xff,0xfe,0xfe,0xdf,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,0xa5, | ||
260 | 0xff,0xff,0xff,0xc0,0x37,0xff,0xff,0xf1,0x99,0x8e,0xdc,0x7f,0xe9,0x6a,0xbf,0xff, | ||
261 | 0xf0,0x0f,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, | ||
262 | 0xff,0xfe,0xff,0xff,0xff,0xff,0x07,0xff,0xc0,0xbe,0xff,0xff,0xcf,0xef,0x9f,0xff, | ||
263 | 0xff,0xfb,0xff,0xe7,0xff,0xff,0xa1,0xe3,0xce,0x3c,0x58,0x3f,0xf3,0xff,0xfd,0xef, | ||
264 | 0xf9,0xff,0xff,0xf7,0xf1,0x7f,0xff,0xcb,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, | ||
265 | 0xfe,0xf5,0x7f,0xff,0xf0,0xff,0xfe,0xff,0xc4,0x75,0xe7,0xb9,0xff,0xff,0xff,0xef, | ||
266 | 0xff,0xc7,0x37,0x3b,0xff,0xf0,0x13,0x9e,0x0f,0xf4,0xff,0xfe,0xfb,0xff,0xff,0xf9, | ||
267 | 0xfc,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xef,0xff,0xff,0xff,0xfe, | ||
268 | 0xf3,0xc0,0x01,0x00,0x00,0x02,0x00,0x02,0x22,0x00,0x00,0xc0,0x40,0x00,0x40,0x00, | ||
269 | 0x04,0x08,0x04,0x0a,0x01,0x01,0x10,0x20,0x20,0x00,0x00,0x04,0x08,0x08,0x04,0x00, | ||
270 | 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x3c,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xfd, | ||
271 | 0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0xcf,0x9d,0xff, | ||
272 | 0xff,0xf7,0xfd,0xf1,0xff,0xff,0xff,0xee,0xbf,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, | ||
273 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xff, | ||
274 | 0xff,0xff,0xf7,0xf7,0xff,0xff,0xfe,0xbf,0xf7,0xff,0xff,0x5b,0xff,0xbf,0xf7,0xff, | ||
275 | 0xfd,0x7f,0x71,0xfd,0xff,0xed,0xf7,0xfe,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, | ||
276 | 0xff,0xff,0xef,0xff,0x7f,0xff,0xd0,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf8,0x30,0x11, | ||
277 | 0x00,0x48,0x60,0x40,0x82,0x60,0x24,0x60,0x00,0xcc,0x00,0x80,0x04,0x01,0x00,0x00, | ||
278 | 0x14,0x01,0x0c,0x04,0x00,0x30,0x00,0x00,0x00,0x08,0x08,0x00,0x01,0x00,0xc2,0x00, | ||
279 | 0x00,0x02,0x00,0x80,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, | ||
280 | 0xf7,0x7b,0xff,0xf3,0xeb,0xbf,0xff,0xf7,0xff,0xff,0xff,0xe7,0x5d,0x3f,0xff,0xf6, | ||
281 | 0xd1,0xfd,0xff,0xeb,0xf7,0x3d,0xff,0xff,0xff,0x5f,0xff,0x7f,0x7f,0xf3,0xff,0xff, | ||
282 | 0xef,0xfd,0xbf,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, | ||
283 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, | ||
284 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
285 | 0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xb5,0xdf, | ||
286 | 0x6f,0x7d,0x69,0x7f,0xfb,0xdf,0x52,0x5f,0xf6,0xf7,0xfe,0xf6,0xf3,0xbd,0xb1,0xda, | ||
287 | 0xcd,0xfe,0xf6,0xee,0xd2,0xbd,0xa5,0xaf,0xbd,0xff,0x6f,0x7c,0xeb,0x2b,0xfa,0xda, | ||
288 | 0xff,0xfe,0xdf,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6, | ||
289 | 0xff,0xf6,0xff,0xbd,0xbf,0xcd,0xbf,0xeb,0x6f,0xf7,0x6f,0xdf,0xdb,0x51,0xfd,0xbd, | ||
290 | 0xff,0x6f,0xff,0x6f,0xfb,0x5b,0xff,0xdb,0xff,0xf6,0xfe,0xf6,0xfd,0xfd,0xbf,0xfe, | ||
291 | 0xf7,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfa,0x50,0xff,0xff,0xff, | ||
292 | 0xf0,0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0xfc,0xff,0xff, | ||
293 | 0xf7,0xdb,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff, | ||
294 | 0xaf,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xa0,0xff,0xff,0xff,0xf0, | ||
295 | 0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff, | ||
296 | 0xf3,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,0xff, | ||
297 | 0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0x9f,0xf0,0x7f, | ||
298 | 0xff,0xf9,0xfc,0x4f,0xf3,0xff,0x27,0xeb,0xff,0xfc,0x81,0xfc,0x7f,0xfe,0x7b,0xff, | ||
299 | 0xf7,0xff,0x12,0x7f,0xff,0xff,0xff,0xff,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, | ||
300 | 0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xdf,0xfe,0xff,0xfc,0x7e,0x7f,0xbf, | ||
301 | 0xff,0xff,0xaf,0xef,0xff,0xdf,0xdf,0xfb,0xff,0xf1,0xc3,0xfe,0x6f,0xf1,0xcf,0x3f, | ||
302 | 0xfb,0xff,0xff,0xcf,0xfe,0xff,0xff,0xfe,0x7f,0xbf,0xff,0xff,0xbf,0xfa,0xf0,0xdf, | ||
303 | 0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00, | ||
304 | 0x20,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, | ||
305 | 0x00,0x00,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x80,0x00,0x02,0x3c,0xf0,0x2f,0xff, | ||
306 | 0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
307 | 0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xf1,0xff,0x7f,0xff,0xff,0xff,0xff,0xef,0xff, | ||
308 | 0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x2f,0xff,0xff, | ||
309 | 0xff,0xfe,0xf0,0xff,0xff,0xff,0xfb,0xff,0xbf,0xff,0xff,0xff,0xff,0xf7,0xbf,0xfb, | ||
310 | 0xff,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xf7,0xbf,0xfb,0xff,0xff,0xff,0x7f,0xde,0xff, | ||
311 | 0xff,0xff,0xff,0xff,0xff,0xed,0xf7,0xff,0xff,0x7f,0xd0,0xf0,0x3f,0xff,0xff,0xff, | ||
312 | 0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x80, | ||
313 | 0x20,0x01,0x01,0x92,0x00,0x01,0x01,0x00,0xe0,0x1c,0x60,0x20,0x30,0x08,0x08,0x00, | ||
314 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xc1,0xf0,0x6f,0xff,0xff,0xff,0xfe, | ||
315 | 0xff,0xff,0xff,0xff,0xff,0xdb,0xfe,0xff,0xff,0xdf,0xff,0xfc,0x7f,0xfb,0xbf,0xff, | ||
316 | 0xff,0xff,0xff,0xff,0xf1,0xf6,0xff,0xf7,0x7e,0x3f,0xff,0x7f,0xff,0xff,0xff,0xf7, | ||
317 | 0xff,0xff,0xff,0xed,0xff,0xdf,0xff,0xb7,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, | ||
318 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
319 | 0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
320 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, | ||
321 | 0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xbf,0xff,0xdf, | ||
322 | 0x57,0xef,0xf1,0xfd,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfb,0xff, | ||
323 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, | ||
324 | 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xdf,0xff, | ||
325 | 0xff,0xf1,0xfd,0xff,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
326 | 0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xf7,0xfd,0xff,0xff, | ||
327 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xff, | ||
328 | 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
329 | 0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, | ||
330 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, | ||
331 | 0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
332 | 0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, | ||
333 | 0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0x6f,0xff,0xfe,0xbf,0xff,0xf1,0xff, | ||
334 | 0xf7,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd, | ||
335 | 0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
336 | 0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0x57,0xff,0xfd,0xbf,0xff,0xf1,0xff,0xef, | ||
337 | 0xfe,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff, | ||
338 | 0xde,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, | ||
339 | 0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xe7,0x2f,0xf1,0x3c,0xbf,0xfd, | ||
340 | 0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, | ||
341 | 0x02,0x01,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
342 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
343 | 0xff,0xff,0xff,0xff,0xff,0xff }; | ||
diff --git a/drivers/net/hamradio/z8530.h b/drivers/net/hamradio/z8530.h new file mode 100644 index 000000000000..8bef548572aa --- /dev/null +++ b/drivers/net/hamradio/z8530.h | |||
@@ -0,0 +1,245 @@ | |||
1 | |||
2 | /* 8530 Serial Communications Controller Register definitions */ | ||
3 | #define FLAG 0x7e | ||
4 | |||
5 | /* Write Register 0 */ | ||
6 | #define R0 0 /* Register selects */ | ||
7 | #define R1 1 | ||
8 | #define R2 2 | ||
9 | #define R3 3 | ||
10 | #define R4 4 | ||
11 | #define R5 5 | ||
12 | #define R6 6 | ||
13 | #define R7 7 | ||
14 | #define R8 8 | ||
15 | #define R9 9 | ||
16 | #define R10 10 | ||
17 | #define R11 11 | ||
18 | #define R12 12 | ||
19 | #define R13 13 | ||
20 | #define R14 14 | ||
21 | #define R15 15 | ||
22 | |||
23 | #define NULLCODE 0 /* Null Code */ | ||
24 | #define POINT_HIGH 0x8 /* Select upper half of registers */ | ||
25 | #define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ | ||
26 | #define SEND_ABORT 0x18 /* HDLC Abort */ | ||
27 | #define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ | ||
28 | #define RES_Tx_P 0x28 /* Reset TxINT Pending */ | ||
29 | #define ERR_RES 0x30 /* Error Reset */ | ||
30 | #define RES_H_IUS 0x38 /* Reset highest IUS */ | ||
31 | |||
32 | #define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ | ||
33 | #define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ | ||
34 | #define RES_EOM_L 0xC0 /* Reset EOM latch */ | ||
35 | |||
36 | /* Write Register 1 */ | ||
37 | |||
38 | #define EXT_INT_ENAB 0x1 /* Ext Int Enable */ | ||
39 | #define TxINT_ENAB 0x2 /* Tx Int Enable */ | ||
40 | #define PAR_SPEC 0x4 /* Parity is special condition */ | ||
41 | |||
42 | #define RxINT_DISAB 0 /* Rx Int Disable */ | ||
43 | #define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ | ||
44 | #define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ | ||
45 | #define INT_ERR_Rx 0x18 /* Int on error only */ | ||
46 | |||
47 | #define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ | ||
48 | #define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ | ||
49 | #define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ | ||
50 | |||
51 | /* Write Register #2 (Interrupt Vector) */ | ||
52 | |||
53 | /* Write Register 3 */ | ||
54 | |||
55 | #define RxENABLE 0x1 /* Rx Enable */ | ||
56 | #define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ | ||
57 | #define ADD_SM 0x4 /* Address Search Mode (SDLC) */ | ||
58 | #define RxCRC_ENAB 0x8 /* Rx CRC Enable */ | ||
59 | #define ENT_HM 0x10 /* Enter Hunt Mode */ | ||
60 | #define AUTO_ENAB 0x20 /* Auto Enables */ | ||
61 | #define Rx5 0x0 /* Rx 5 Bits/Character */ | ||
62 | #define Rx7 0x40 /* Rx 7 Bits/Character */ | ||
63 | #define Rx6 0x80 /* Rx 6 Bits/Character */ | ||
64 | #define Rx8 0xc0 /* Rx 8 Bits/Character */ | ||
65 | |||
66 | /* Write Register 4 */ | ||
67 | |||
68 | #define PAR_ENA 0x1 /* Parity Enable */ | ||
69 | #define PAR_EVEN 0x2 /* Parity Even/Odd* */ | ||
70 | |||
71 | #define SYNC_ENAB 0 /* Sync Modes Enable */ | ||
72 | #define SB1 0x4 /* 1 stop bit/char */ | ||
73 | #define SB15 0x8 /* 1.5 stop bits/char */ | ||
74 | #define SB2 0xc /* 2 stop bits/char */ | ||
75 | |||
76 | #define MONSYNC 0 /* 8 Bit Sync character */ | ||
77 | #define BISYNC 0x10 /* 16 bit sync character */ | ||
78 | #define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ | ||
79 | #define EXTSYNC 0x30 /* External Sync Mode */ | ||
80 | |||
81 | #define X1CLK 0x0 /* x1 clock mode */ | ||
82 | #define X16CLK 0x40 /* x16 clock mode */ | ||
83 | #define X32CLK 0x80 /* x32 clock mode */ | ||
84 | #define X64CLK 0xC0 /* x64 clock mode */ | ||
85 | |||
86 | /* Write Register 5 */ | ||
87 | |||
88 | #define TxCRC_ENAB 0x1 /* Tx CRC Enable */ | ||
89 | #define RTS 0x2 /* RTS */ | ||
90 | #define SDLC_CRC 0x4 /* SDLC/CRC-16 */ | ||
91 | #define TxENAB 0x8 /* Tx Enable */ | ||
92 | #define SND_BRK 0x10 /* Send Break */ | ||
93 | #define Tx5 0x0 /* Tx 5 bits (or less)/character */ | ||
94 | #define Tx7 0x20 /* Tx 7 bits/character */ | ||
95 | #define Tx6 0x40 /* Tx 6 bits/character */ | ||
96 | #define Tx8 0x60 /* Tx 8 bits/character */ | ||
97 | #define DTR 0x80 /* DTR */ | ||
98 | |||
99 | /* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ | ||
100 | |||
101 | /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ | ||
102 | |||
103 | /* Write Register 8 (transmit buffer) */ | ||
104 | |||
105 | /* Write Register 9 (Master interrupt control) */ | ||
106 | #define VIS 1 /* Vector Includes Status */ | ||
107 | #define NV 2 /* No Vector */ | ||
108 | #define DLC 4 /* Disable Lower Chain */ | ||
109 | #define MIE 8 /* Master Interrupt Enable */ | ||
110 | #define STATHI 0x10 /* Status high */ | ||
111 | #define NORESET 0 /* No reset on write to R9 */ | ||
112 | #define CHRB 0x40 /* Reset channel B */ | ||
113 | #define CHRA 0x80 /* Reset channel A */ | ||
114 | #define FHWRES 0xc0 /* Force hardware reset */ | ||
115 | |||
116 | /* Write Register 10 (misc control bits) */ | ||
117 | #define BIT6 1 /* 6 bit/8bit sync */ | ||
118 | #define LOOPMODE 2 /* SDLC Loop mode */ | ||
119 | #define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ | ||
120 | #define MARKIDLE 8 /* Mark/flag on idle */ | ||
121 | #define GAOP 0x10 /* Go active on poll */ | ||
122 | #define NRZ 0 /* NRZ mode */ | ||
123 | #define NRZI 0x20 /* NRZI mode */ | ||
124 | #define FM1 0x40 /* FM1 (transition = 1) */ | ||
125 | #define FM0 0x60 /* FM0 (transition = 0) */ | ||
126 | #define CRCPS 0x80 /* CRC Preset I/O */ | ||
127 | |||
128 | /* Write Register 11 (Clock Mode control) */ | ||
129 | #define TRxCXT 0 /* TRxC = Xtal output */ | ||
130 | #define TRxCTC 1 /* TRxC = Transmit clock */ | ||
131 | #define TRxCBR 2 /* TRxC = BR Generator Output */ | ||
132 | #define TRxCDP 3 /* TRxC = DPLL output */ | ||
133 | #define TRxCOI 4 /* TRxC O/I */ | ||
134 | #define TCRTxCP 0 /* Transmit clock = RTxC pin */ | ||
135 | #define TCTRxCP 8 /* Transmit clock = TRxC pin */ | ||
136 | #define TCBR 0x10 /* Transmit clock = BR Generator output */ | ||
137 | #define TCDPLL 0x18 /* Transmit clock = DPLL output */ | ||
138 | #define RCRTxCP 0 /* Receive clock = RTxC pin */ | ||
139 | #define RCTRxCP 0x20 /* Receive clock = TRxC pin */ | ||
140 | #define RCBR 0x40 /* Receive clock = BR Generator output */ | ||
141 | #define RCDPLL 0x60 /* Receive clock = DPLL output */ | ||
142 | #define RTxCX 0x80 /* RTxC Xtal/No Xtal */ | ||
143 | |||
144 | /* Write Register 12 (lower byte of baud rate generator time constant) */ | ||
145 | |||
146 | /* Write Register 13 (upper byte of baud rate generator time constant) */ | ||
147 | |||
148 | /* Write Register 14 (Misc control bits) */ | ||
149 | #define BRENABL 1 /* Baud rate generator enable */ | ||
150 | #define BRSRC 2 /* Baud rate generator source */ | ||
151 | #define DTRREQ 4 /* DTR/Request function */ | ||
152 | #define AUTOECHO 8 /* Auto Echo */ | ||
153 | #define LOOPBAK 0x10 /* Local loopback */ | ||
154 | #define SEARCH 0x20 /* Enter search mode */ | ||
155 | #define RMC 0x40 /* Reset missing clock */ | ||
156 | #define DISDPLL 0x60 /* Disable DPLL */ | ||
157 | #define SSBR 0x80 /* Set DPLL source = BR generator */ | ||
158 | #define SSRTxC 0xa0 /* Set DPLL source = RTxC */ | ||
159 | #define SFMM 0xc0 /* Set FM mode */ | ||
160 | #define SNRZI 0xe0 /* Set NRZI mode */ | ||
161 | |||
162 | /* Write Register 15 (external/status interrupt control) */ | ||
163 | #define ZCIE 2 /* Zero count IE */ | ||
164 | #define DCDIE 8 /* DCD IE */ | ||
165 | #define SYNCIE 0x10 /* Sync/hunt IE */ | ||
166 | #define CTSIE 0x20 /* CTS IE */ | ||
167 | #define TxUIE 0x40 /* Tx Underrun/EOM IE */ | ||
168 | #define BRKIE 0x80 /* Break/Abort IE */ | ||
169 | |||
170 | |||
171 | /* Read Register 0 */ | ||
172 | #define Rx_CH_AV 0x1 /* Rx Character Available */ | ||
173 | #define ZCOUNT 0x2 /* Zero count */ | ||
174 | #define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ | ||
175 | #define DCD 0x8 /* DCD */ | ||
176 | #define SYNC_HUNT 0x10 /* Sync/hunt */ | ||
177 | #define CTS 0x20 /* CTS */ | ||
178 | #define TxEOM 0x40 /* Tx underrun */ | ||
179 | #define BRK_ABRT 0x80 /* Break/Abort */ | ||
180 | |||
181 | /* Read Register 1 */ | ||
182 | #define ALL_SNT 0x1 /* All sent */ | ||
183 | /* Residue Data for 8 Rx bits/char programmed */ | ||
184 | #define RES3 0x8 /* 0/3 */ | ||
185 | #define RES4 0x4 /* 0/4 */ | ||
186 | #define RES5 0xc /* 0/5 */ | ||
187 | #define RES6 0x2 /* 0/6 */ | ||
188 | #define RES7 0xa /* 0/7 */ | ||
189 | #define RES8 0x6 /* 0/8 */ | ||
190 | #define RES18 0xe /* 1/8 */ | ||
191 | #define RES28 0x0 /* 2/8 */ | ||
192 | /* Special Rx Condition Interrupts */ | ||
193 | #define PAR_ERR 0x10 /* Parity error */ | ||
194 | #define Rx_OVR 0x20 /* Rx Overrun Error */ | ||
195 | #define CRC_ERR 0x40 /* CRC/Framing Error */ | ||
196 | #define END_FR 0x80 /* End of Frame (SDLC) */ | ||
197 | |||
198 | /* Read Register 2 (channel b only) - Interrupt vector */ | ||
199 | |||
200 | /* Read Register 3 (interrupt pending register) ch a only */ | ||
201 | #define CHBEXT 0x1 /* Channel B Ext/Stat IP */ | ||
202 | #define CHBTxIP 0x2 /* Channel B Tx IP */ | ||
203 | #define CHBRxIP 0x4 /* Channel B Rx IP */ | ||
204 | #define CHAEXT 0x8 /* Channel A Ext/Stat IP */ | ||
205 | #define CHATxIP 0x10 /* Channel A Tx IP */ | ||
206 | #define CHARxIP 0x20 /* Channel A Rx IP */ | ||
207 | |||
208 | /* Read Register 8 (receive data register) */ | ||
209 | |||
210 | /* Read Register 10 (misc status bits) */ | ||
211 | #define ONLOOP 2 /* On loop */ | ||
212 | #define LOOPSEND 0x10 /* Loop sending */ | ||
213 | #define CLK2MIS 0x40 /* Two clocks missing */ | ||
214 | #define CLK1MIS 0x80 /* One clock missing */ | ||
215 | |||
216 | /* Read Register 12 (lower byte of baud rate generator constant) */ | ||
217 | |||
218 | /* Read Register 13 (upper byte of baud rate generator constant) */ | ||
219 | |||
220 | /* Read Register 15 (value of WR 15) */ | ||
221 | |||
222 | /* Z85C30/Z85230 Enhanced SCC register definitions */ | ||
223 | |||
224 | /* Write Register 7' (SDLC/HDLC Programmable Enhancements) */ | ||
225 | #define AUTOTXF 0x01 /* Auto Tx Flag */ | ||
226 | #define AUTOEOM 0x02 /* Auto EOM Latch Reset */ | ||
227 | #define AUTORTS 0x04 /* Auto RTS */ | ||
228 | #define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */ | ||
229 | #define RXFIFOH 0x08 /* Z85230: Int on RX FIFO half full */ | ||
230 | #define FASTDTR 0x10 /* Fast DTR/REQ Mode */ | ||
231 | #define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */ | ||
232 | #define TXFIFOE 0x20 /* Z85230: Int on TX FIFO completely empty */ | ||
233 | #define EXTRDEN 0x40 /* Extended Read Enabled */ | ||
234 | |||
235 | /* Write Register 15 (external/status interrupt control) */ | ||
236 | #define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */ | ||
237 | #define FIFOE 4 /* FIFO Enable */ | ||
238 | |||
239 | /* Read Register 6 (frame status FIFO) */ | ||
240 | #define BCLSB 0xff /* LSB of 14 bits count */ | ||
241 | |||
242 | /* Read Register 7 (frame status FIFO) */ | ||
243 | #define BCMSB 0x3f /* MSB of 14 bits count */ | ||
244 | #define FDA 0x40 /* FIFO Data Available Status */ | ||
245 | #define FOS 0x80 /* FIFO Overflow Status */ | ||