11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hdlcdrv.c -- HDLC packet radio network driver. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Please note that the GPL allows you to use the driver, NOT the radio. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In order to use the radio, you need a license from the communications 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * authority of your country. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The driver was derived from Donald Beckers skeleton.c 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written 1993-94 by Donald Becker. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * History: 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.1 21.09.1996 Started 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 18.10.1996 Changed to new user space access routines 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (copy_{to,from}_user) 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.2 21.11.1996 various small changes 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.3 03.03.1997 fixed (hopefully) IP not working with ax.25 as a module 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.4 16.04.1997 init code/data tagged 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.5 30.07.1997 made HDLC buffers bigger (solves a problem with the 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * soundmodem driver) 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.6 05.04.1998 add spinlocks 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.7 03.08.1999 removed some old compatibility cruft 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0.8 12.02.2000 adapted to softnet driver interface 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/capability.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdlcdrv.h> 598b5b46718113166b5f6bcdf40e67ea867461e209Ralf Baechle#include <linux/random.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ax25.h> 61c4bc7ee2e474819d3932e8d726fdf7cb0bdc00c1Ralf Baechle#include <asm/uaccess.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/crc-ccitt.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define KISS_VERBOSE 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_TXDELAY 1 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_PERSIST 2 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_SLOTTIME 3 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_TXTAIL 4 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_FULLDUP 5 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_HARDWARE 6 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARAM_RETURN 255 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the CRC routines are stolen from WAMPES 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by Dieter Deyke 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*---------------------------------------------------------------------------*/ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void append_crc_ccitt(unsigned char *buffer, int len) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int crc = crc_ccitt(0xffff, buffer, len) ^ 0xffff; 91ae6134bdf3197206fba95563d755d2fa50d90dddMicah Dowty buffer += len; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buffer++ = crc; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buffer++ = crc >> 8; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*---------------------------------------------------------------------------*/ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int check_crc_ccitt(const unsigned char *buf, int cnt) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*---------------------------------------------------------------------------*/ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int calc_crc_ccitt(const unsigned char *buf, int cnt) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int crc = 0xffff; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; cnt > 0; cnt--) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds crc ^= 0xffff; 113807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return crc & 0xffff; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------------------------------------------------------- */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define tenms_to_2flags(s,tenms) ((tenms * s->par.bitrate) / 100 / 16) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------------------------------------------------------- */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The HDLC routines 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlc_rx_add_bytes(struct hdlcdrv_state *s, unsigned int bits, 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int added = 0; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (s->hdlcrx.rx_state && num >= 8) { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlcrx.len >= sizeof(s->hdlcrx.buffer)) { 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.rx_state = 0; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *s->hdlcrx.bp++ = bits >> (32-num); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.len++; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num -= 8; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds added += 8; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return added; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pkt_len; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *cp; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlcrx.len < 4) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!check_crc_ccitt(s->hdlcrx.buffer, s->hdlcrx.len)) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(skb = dev_alloc_skb(pkt_len))) { 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: memory squeeze, dropping packet\n", dev->name); 1575a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger dev->stats.rx_dropped++; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = skb_put(skb, pkt_len); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *cp++ = 0; /* KISS kludge */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); 16356cb515628e6a831bb76783f282a71f7285dad33Arnaldo Carvalho de Melo skb->protocol = ax25_type_trans(skb, dev); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 1655a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger dev->stats.rx_packets++; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hdlcdrv_receiver(struct net_device *dev, struct hdlcdrv_state *s) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask1, mask2, mask3, mask4, mask5, mask6, word; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s || s->magic != HDLCDRV_MAGIC) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds word = hdlcdrv_hbuf_get(&s->hdlcrx.hbuf); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef HDLCDRV_DEBUG 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdrv_add_bitbuffer_word(&s->bitbuf_hdlc, word); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* HDLCDRV_DEBUG */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.bitstream >>= 16; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.bitstream |= word << 16; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.bitbuf >>= 16; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.bitbuf |= word << 16; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.numbits += 16; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00, 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i >= 0; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask5 <<= 1, mask6 = (mask6 << 1) | 1) { 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((s->hdlcrx.bitstream & mask1) == mask1) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.rx_state = 0; /* abort received */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((s->hdlcrx.bitstream & mask2) == mask3) { 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* flag received */ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlcrx.rx_state) { 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds << (8+i), 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.numbits 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -8-i); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_rx_flag(dev, s); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.len = 0; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.bp = s->hdlcrx.buffer; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.rx_state = 1; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.numbits = i; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((s->hdlcrx.bitstream & mask4) == mask5) { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* stuffed bit */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.numbits--; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.bitbuf = (s->hdlcrx.bitbuf & (~mask6)) | 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s->hdlcrx.bitbuf & mask6) << 1); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.numbits -= hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf, 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.numbits); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(0, &s->hdlcrx.in_hdlc_rx); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------------------------------------------------------- */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void do_kiss_params(struct hdlcdrv_state *s, 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data, unsigned long len) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef KISS_VERBOSE 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKP(a,b) printk(KERN_INFO "hdlcdrv.c: channel params: " a "\n", b) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* KISS_VERBOSE */ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKP(a,b) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* KISS_VERBOSE */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len < 2) 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(data[0]) { 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARAM_TXDELAY: 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.tx_delay = data[1]; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKP("TX delay = %ums", 10 * s->ch_params.tx_delay); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARAM_PERSIST: 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.ppersist = data[1]; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKP("p persistence = %u", s->ch_params.ppersist); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARAM_SLOTTIME: 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.slottime = data[1]; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKP("slot time = %ums", s->ch_params.slottime); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARAM_TXTAIL: 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.tx_tail = data[1]; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKP("TX tail = %ums", s->ch_params.tx_tail); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PARAM_FULLDUP: 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.fulldup = !!data[1]; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKP("%s duplex", s->ch_params.fulldup ? "full" : "half"); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef PKP 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------------------------------------------------------- */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask1, mask2, mask3; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pkt_len; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s || s->magic != HDLCDRV_MAGIC) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlctx.numbits >= 16) { 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hdlcdrv_hbuf_full(&s->hdlctx.hbuf)) { 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(0, &s->hdlctx.in_hdlc_tx); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdrv_hbuf_put(&s->hdlctx.hbuf, s->hdlctx.bitbuf); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitbuf >>= 16; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numbits -= 16; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (s->hdlctx.tx_state) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(0, &s->hdlctx.in_hdlc_tx); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlctx.numflags) { 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags--; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitbuf |= 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x7e7e << s->hdlctx.numbits; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numbits += 16; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlctx.tx_state == 1) { 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(0, &s->hdlctx.in_hdlc_tx); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(skb = s->skb)) { 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flgs = tenms_to_2flags(s, s->ch_params.tx_tail); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flgs < 2) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flgs = 2; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 1; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags = flgs; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->skb = NULL; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len = skb->len-1; /* strip KISS byte */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 0; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags = 1; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_irq(skb); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 320d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data_offset(skb, 1, 321d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo s->hdlctx.buffer, 322d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo pkt_len); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_irq(skb); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bp = s->hdlctx.buffer; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds append_crc_ccitt(s->hdlctx.buffer, pkt_len); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.len = pkt_len+2; /* the appended CRC */ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 2; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitstream = 0; 3295a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger dev->stats.tx_packets++; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s->hdlctx.len) { 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 0; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags = 1; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.len--; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitbuf |= *s->hdlctx.bp << 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numbits; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitstream >>= 8; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitstream |= (*s->hdlctx.bp++) << 16; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask1 = 0x1f000; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask2 = 0x10000; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask3 = 0xffffffff >> (31-s->hdlctx.numbits); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numbits += 8; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask3 = (mask3 << 1) | 1) { 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((s->hdlctx.bitstream & mask1) != mask1) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitstream &= ~mask2; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitbuf = 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (s->hdlctx.bitbuf & mask3) | 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((s->hdlctx.bitbuf & 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (~mask3)) << 1); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numbits++; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask3 = (mask3 << 1) | 1; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------------------------------------------------------- */ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void start_tx(struct net_device *dev, struct hdlcdrv_state *s) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 0; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags = tenms_to_2flags(s, s->ch_params.tx_delay); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitbuf = s->hdlctx.bitstream = s->hdlctx.numbits = 0; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlcdrv_transmitter(dev, s); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.ptt = 1; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ptt_keyed++; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---------------------------------------------------------------------- */ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s) 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || !s->skb) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->ch_params.fulldup) { 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_tx(dev, s); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->hdlcrx.dcd) { 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.slotcnt = s->ch_params.slottime; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((--s->hdlctx.slotcnt) > 0) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.slotcnt = s->ch_params.slottime; 3928b5b46718113166b5f6bcdf40e67ea867461e209Ralf Baechle if ((random32() % 256) > s->ch_params.ppersist) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_tx(dev, s); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ===================== network driver interface ========================= 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40236e4d64a82d9a91a73a2b9b32117aedfe2211fb3Stephen Hemmingerstatic netdev_tx_t hdlcdrv_send_packet(struct sk_buff *skb, 40336e4d64a82d9a91a73a2b9b32117aedfe2211fb3Stephen Hemminger struct net_device *dev) 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *sm = netdev_priv(dev); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->data[0] != 0) { 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_kiss_params(sm, skb->data, skb->len); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 4106ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sm->skb) 4135b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy return NETDEV_TX_LOCKED; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sm->skb = skb; 4166ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdrv_set_mac_address(struct net_device *dev, void *addr) 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr *sa = (struct sockaddr *)addr; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* addr is an AX.25 shifted ASCII mac address */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open/initialize the board. This is called (in the current kernel) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sometime after booting when the 'ifconfig' program is run. 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine should set everything up anew at each open, even 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registers that "should" only need to be set once at boot, so that 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is non-reboot way to recover if something goes wrong. 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdrv_open(struct net_device *dev) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *s = netdev_priv(dev); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s->ops || !s->ops->open) 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialise some variables 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->opened = 1; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.in_hdlc_rx = 0; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.rx_state = 0; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.in_hdlc_tx = 0; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 1; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags = 0; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.ptt = 0; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.slotcnt = s->ch_params.slottime; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.calibrate = 0; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = s->ops->open(dev); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i) 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The inverse routine to hdlcdrv_open(). 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdrv_close(struct net_device *dev) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *s = netdev_priv(dev); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->ops && s->ops->close) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = s->ops->close(dev); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->skb) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(s->skb); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->skb = NULL; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->opened = 0; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *s = netdev_priv(dev); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_ioctl bi; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd != SIOCDEVPRIVATE) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->ops && s->ops->ioctl) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return s->ops->ioctl(dev, ifr, &bi, cmd); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (bi.cmd) { 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->ops && s->ops->ioctl) 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return s->ops->ioctl(dev, ifr, &bi, cmd); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_GETCHANNELPAR: 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cp.tx_delay = s->ch_params.tx_delay; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cp.tx_tail = s->ch_params.tx_tail; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cp.slottime = s->ch_params.slottime; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cp.ppersist = s->ch_params.ppersist; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cp.fulldup = s->ch_params.fulldup; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_SETCHANNELPAR: 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_NET_ADMIN)) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.tx_delay = bi.data.cp.tx_delay; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.tx_tail = bi.data.cp.tx_tail; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.slottime = bi.data.cp.slottime; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.ppersist = bi.data.cp.ppersist; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params.fulldup = bi.data.cp.fulldup; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.slotcnt = 1; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_GETMODEMPAR: 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.iobase = dev->base_addr; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.irq = dev->irq; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.dma = dev->dma; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.dma2 = s->ptt_out.dma2; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.seriobase = s->ptt_out.seriobase; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.pariobase = s->ptt_out.pariobase; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.mp.midiiobase = s->ptt_out.midiiobase; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_SETMODEMPAR: 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev)) 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = bi.data.mp.iobase; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = bi.data.mp.irq; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dma = bi.data.mp.dma; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ptt_out.dma2 = bi.data.mp.dma2; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ptt_out.seriobase = bi.data.mp.seriobase; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ptt_out.pariobase = bi.data.mp.pariobase; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ptt_out.midiiobase = bi.data.mp.midiiobase; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_GETSTAT: 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cs.ptt = hdlcdrv_ptt(s); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cs.dcd = s->hdlcrx.dcd; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.cs.ptt_keyed = s->ptt_keyed; 5595a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger bi.data.cs.tx_packets = dev->stats.tx_packets; 5605a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger bi.data.cs.tx_errors = dev->stats.tx_errors; 5615a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger bi.data.cs.rx_packets = dev->stats.rx_packets; 5625a7616af604caf0d436a1ed0d4298bb25cd77d67Stephen Hemminger bi.data.cs.rx_errors = dev->stats.rx_errors; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_OLDGETSTAT: 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.ocs.ptt = hdlcdrv_ptt(s); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.ocs.dcd = s->hdlcrx.dcd; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.ocs.ptt_keyed = s->ptt_keyed; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_CALIBRATE: 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!capable(CAP_SYS_RAWIO)) 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_GETSAMPLES: 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef HDLCDRV_DEBUG 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* HDLCDRV_DEBUG */ 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->bitbuf_channel.rd == s->bitbuf_channel.wr) 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.bits = 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_channel.buffer[s->bitbuf_channel.rd]; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_channel.rd = (s->bitbuf_channel.rd+1) % 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(s->bitbuf_channel.buffer); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* HDLCDRV_DEBUG */ 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_GETBITS: 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef HDLCDRV_DEBUG 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* HDLCDRV_DEBUG */ 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->bitbuf_hdlc.rd == s->bitbuf_hdlc.wr) 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.bits = 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_hdlc.buffer[s->bitbuf_hdlc.rd]; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_hdlc.rd = (s->bitbuf_hdlc.rd+1) % 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(s->bitbuf_hdlc.buffer); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* HDLCDRV_DEBUG */ 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HDLCDRVCTL_DRIVERNAME: 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->ops && s->ops->drvname) { 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncpy(bi.data.drivername, s->ops->drvname, 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(bi.data.drivername)); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bi.data.drivername[0] = '\0'; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6212d8b223d81a385a746befc7facf93680f4185533Stephen Hemmingerstatic const struct net_device_ops hdlcdrv_netdev = { 6222d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger .ndo_open = hdlcdrv_open, 6232d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger .ndo_stop = hdlcdrv_close, 6242d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger .ndo_start_xmit = hdlcdrv_send_packet, 6252d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger .ndo_do_ioctl = hdlcdrv_ioctl, 6262d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger .ndo_set_mac_address = hdlcdrv_set_mac_address, 6272d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger}; 6282d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize fields in hdlcdrv 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hdlcdrv_setup(struct net_device *dev) 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const struct hdlcdrv_channel_params dflt_ch_params = { 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20, 2, 10, 40, 0 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *s = netdev_priv(dev); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialize the hdlcdrv_state struct 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ch_params = dflt_ch_params; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ptt_keyed = 0; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&s->hdlcrx.hbuf.lock); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.in_hdlc_rx = 0; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlcrx.rx_state = 0; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&s->hdlctx.hbuf.lock); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.in_hdlc_tx = 0; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.tx_state = 1; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.numflags = 0; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.ptt = 0; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.slotcnt = s->ch_params.slottime; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->hdlctx.calibrate = 0; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef HDLCDRV_DEBUG 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_channel.rd = s->bitbuf_channel.wr = 0; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_channel.shreg = 0x80; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_hdlc.rd = s->bitbuf_hdlc.wr = 0; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->bitbuf_hdlc.shreg = 0x80; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* HDLCDRV_DEBUG */ 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in the fields of the device structure */ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->skb = NULL; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6732d8b223d81a385a746befc7facf93680f4185533Stephen Hemminger dev->netdev_ops = &hdlcdrv_netdev; 6743b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger dev->header_ops = &ax25_header_ops; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->type = ARPHRD_AX25; /* AF_AX25 device */ 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ 68015b1c0e822f578306332d4f4c449250db5c5dcebRalf Baechle memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); 68115b1c0e822f578306332d4f4c449250db5c5dcebRalf Baechle memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_queue_len = 16; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops, 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int privsize, const char *ifname, 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int baseaddr, unsigned int irq, 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int dma) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *s; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(ops == NULL); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (privsize < sizeof(struct hdlcdrv_state)) 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds privsize = sizeof(struct hdlcdrv_state); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_netdev(privsize, ifname, hdlcdrv_setup); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialize part of the hdlcdrv_state struct 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = netdev_priv(dev); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->magic = HDLCDRV_MAGIC; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ops = ops; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = baseaddr; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dma = dma; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) { 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "hdlcdrv: cannot register net " 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "device %s\n", dev->name); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = ERR_PTR(err); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hdlcdrv_unregister(struct net_device *dev) 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hdlcdrv_state *s = netdev_priv(dev); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(s->magic != HDLCDRV_MAGIC); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s->opened && s->ops->close) 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->ops->close(dev); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(hdlcdrv_receiver); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(hdlcdrv_transmitter); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(hdlcdrv_arbitrate); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(hdlcdrv_register); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(hdlcdrv_unregister); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init hdlcdrv_init_driver(void) 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n"); 752b953ff2238661cd95513a8f2837197c6f77a642fMichal Marek printk(KERN_INFO "hdlcdrv: version 0.8\n"); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit hdlcdrv_cleanup_driver(void) 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "hdlcdrv: cleanup\n"); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(hdlcdrv_init_driver); 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(hdlcdrv_cleanup_driver); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------- */ 772