11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************************************************************* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Filename: wrapper.c 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version: 1.2 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description: IrDA SIR async wrapper layer 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Status: Stable 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Dag Brattli <dagb@cs.uit.no> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created at: Mon Aug 4 20:40:53 1997 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified at: Fri Jan 28 13:21:09 2000 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified by: Dag Brattli <dagb@cs.uit.no> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified at: Fri May 28 3:11 CST 1999 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All Rights Reserved. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License as 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation; either version 2 of 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the License, or (at your option) any later version. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23db955170d40601d9925f01712782fbe3ce362b7eMarcin Garski * Neither Dag Brattli nor University of Tromsø admit liability nor 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provide warranty for any of this software. This material is 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided "AS-IS" and at no charge. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ********************************************************************/ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/wrapper.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/crc.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irlap.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irlap_frame.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/irda/irda_device.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************** FRAME WRAPPING **************************/ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unwrap and unstuff SIR frames 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note : at FIR and MIR, HDLC framing is used and usually handled 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the controller, so we come here only for SIR... Jean II 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function stuff_byte (byte, buf) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Byte stuff one single byte and put the result in buffer pointed to by 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buf. The buffer must at all times be able to have two bytes inserted. 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is in a tight loop, better inline it, so need to be prior to callers. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2000 bytes on P6 200MHz, non-inlined ~370us, inline ~170us) - Jean II 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int stuff_byte(__u8 byte, __u8 *buf) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (byte) { 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BOF: /* FALLTHROUGH */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EOF: /* FALLTHROUGH */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CE: 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Insert transparently coded */ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = CE; /* Send link escape */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = byte^IRDA_TRANS; /* Complement bit 5 */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 2; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* break; */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Non-special value, no transparency required */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = byte; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* break; */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_wrap (skb, *tx_buff, buffsize) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Makes a new buffer with wrapping and stuffing, should check that 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we don't get tx buffer overflow. 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize) 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int xbofs; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union { 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u16 value; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 bytes[2]; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } fcs; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize variables */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fcs.value = INIT_FCS; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = 0; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send XBOF's for required min. turn time and for the negotiated 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * additional XBOFS 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cb->magic != LAP_MAGIC) { 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will happen for all frames sent from user-space. 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Nothing to worry about, but we set the default number of 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BOF's 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1090dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __func__); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xbofs = 10; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xbofs = cb->xbofs + cb->xbofs_delay; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1140dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(4, "%s(), xbofs=%d\n", __func__, xbofs); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that we never use more than 115 + 48 xbofs */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xbofs > 163) { 1180dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __func__, 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xbofs); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xbofs = 163; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(tx_buff + n, XBOF, xbofs); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += xbofs; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start of packet character BOF */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_buff[n++] = BOF; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Insert frame and calc CRC */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i < skb->len; i++) { 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check for the possibility of tx buffer overflow. We use 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bufsize-5 since the maximum number of bytes that can be 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transmitted after this point is 5. 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(n >= (buffsize-5)) { 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_ERROR("%s(), tx buffer overflow (n=%d)\n", 1380dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison __func__, n); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return n; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += stuff_byte(skb->data[i], tx_buff+n); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fcs.value = irda_fcs(fcs.value, skb->data[i]); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Insert CRC in little endian format (LSB first) */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fcs.value = ~fcs.value; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __LITTLE_ENDIAN 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += stuff_byte(fcs.bytes[0], tx_buff+n); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += stuff_byte(fcs.bytes[1], tx_buff+n); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* ifdef __BIG_ENDIAN */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += stuff_byte(fcs.bytes[1], tx_buff+n); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += stuff_byte(fcs.bytes[0], tx_buff+n); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_buff[n++] = EOF; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return n; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(async_wrap_skb); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* FRAME UNWRAPPING *************************/ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unwrap and unstuff SIR frames 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete rewrite by Jean II : 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * More inline, faster, more compact, more logical. Jean II 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (16 bytes on P6 200MHz, old 5 to 7 us, new 4 to 6 us) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (24 bytes on P6 200MHz, old 9 to 10 us, new 7 to 8 us) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (for reference, 115200 b/s is 1 byte every 69 us) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And reduce wrapper.o by ~900B in the process ;-) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Then, we have the addition of ZeroCopy, which is optional 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (i.e. the driver must initiate it) and improve final processing. 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2005 B frame + EOF on P6 200MHz, without 30 to 50 us, with 10 to 25 us) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note : at FIR and MIR, HDLC framing is used and usually handled 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the controller, so we come here only for SIR... Jean II 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can also choose where we want to do the CRC calculation. We can 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do it "inline", as we receive the bytes, or "postponed", when 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * receiving the End-Of-Frame. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (16 bytes on P6 200MHz, inlined 4 to 6 us, postponed 4 to 5 us) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (24 bytes on P6 200MHz, inlined 7 to 8 us, postponed 5 to 7 us) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * With ZeroCopy : 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2005 B frame on P6 200MHz, inlined 10 to 25 us, postponed 140 to 180 us) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Without ZeroCopy : 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (2005 B frame on P6 200MHz, inlined 30 to 50 us, postponed 150 to 180 us) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (Note : numbers taken with irq disabled) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From those numbers, it's not clear which is the best strategy, because 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we end up running through a lot of data one way or another (i.e. cache 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * misses). I personally prefer to avoid the huge latency spike of the 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "postponed" solution, because it come just at the time when we have 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lot's of protocol processing to do and it will hurt our ability to 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reach low link turnaround times... Jean II 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//#define POSTPONE_RX_CRC 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_bump (buf, len, stats) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Got a frame, make a copy of it, and pass it up the stack! We can try 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to inline it since it's only called from state_inside_frame 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasync_bump(struct net_device *dev, 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats, 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobuff_t *rx_buff) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *newskb; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *dataskb; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int docopy; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if we need to copy the data to a new skb or not. 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the driver doesn't use ZeroCopy Rx, we have to do it. 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * With ZeroCopy Rx, the rx_buff already point to a valid 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb. But, if the frame is small, it is more efficient to 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copy it to save memory (copy will be fast anyway - that's 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called Rx-copy-break). Jean II */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds docopy = ((rx_buff->skb == NULL) || 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (rx_buff->len < IRDA_RX_COPY_THRESHOLD)); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate a new skb */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newskb = dev_alloc_skb(docopy ? rx_buff->len + 1 : rx_buff->truesize); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!newskb) { 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_dropped++; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We could deliver the current skb if doing ZeroCopy Rx, 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but this would stall the Rx path. Better drop the 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet... Jean II */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Align IP header to 20 bytes (i.e. increase skb->data) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note this is only useful with IrLAN, as PPP has a variable 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * header size (2 or 1 bytes) - Jean II */ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(newskb, 1); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(docopy) { 241cc53ded272ecf8d62c9f3b48baadc5165a0b6d7bJoe Perches /* Copy data without CRC (length already checked) */ 24227d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo skb_copy_to_linear_data(newskb, rx_buff->data, 24327d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo rx_buff->len - 2); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Deliver this skb */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dataskb = newskb; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We are using ZeroCopy. Deliver old skb */ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dataskb = rx_buff->skb; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* And hook the new skb to the rx_buff */ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->skb = newskb; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->head = newskb->data; /* NOT newskb->head */ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //printk(KERN_DEBUG "ZeroCopy : len = %d, dataskb = %p, newskb = %p\n", rx_buff->len, dataskb, newskb); 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set proper length on skb (without CRC) */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(dataskb, rx_buff->len - 2); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Feed it to IrLAP layer */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dataskb->dev = dev; 260459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo skb_reset_mac_header(dataskb); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dataskb->protocol = htons(ETH_P_IRDA); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(dataskb); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_packets++; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_bytes += rx_buff->len; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clean up rx_buff (redundant with async_unwrap_bof() ???) */ 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->data = rx_buff->head; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->len = 0; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_unwrap_bof(dev, byte) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle Beginning Of Frame character received within a frame 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasync_unwrap_bof(struct net_device *dev, 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats, 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobuff_t *rx_buff, __u8 byte) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(rx_buff->state) { 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case LINK_ESCAPE: 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case INSIDE_FRAME: 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not supposed to happen, the previous frame is not 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * finished - Jean II */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_DEBUG(1, "%s(), Discarding incomplete frame\n", 2900dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison __func__); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_errors++; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_missed_errors++; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irda_device_set_media_busy(dev, TRUE); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OUTSIDE_FRAME: 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BEGIN_FRAME: 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2996819bc2e1e46c71711a8dddf4040e706b02973c0YOSHIFUJI Hideaki /* We may receive multiple BOF at the start of frame */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now receiving frame */ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = BEGIN_FRAME; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->in_frame = TRUE; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Time to initialize receive buffer */ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->data = rx_buff->head; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->len = 0; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->fcs = INIT_FCS; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_unwrap_eof(dev, byte) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle End Of Frame character received within a frame 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasync_unwrap_eof(struct net_device *dev, 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats, 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobuff_t *rx_buff, __u8 byte) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef POSTPONE_RX_CRC 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(rx_buff->state) { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OUTSIDE_FRAME: 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Probably missed the BOF */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_errors++; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_missed_errors++; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irda_device_set_media_busy(dev, TRUE); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BEGIN_FRAME: 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case LINK_ESCAPE: 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case INSIDE_FRAME: 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Note : in the case of BEGIN_FRAME and LINK_ESCAPE, 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the fcs will most likely not match and generate an 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * error, as expected - Jean II */ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = OUTSIDE_FRAME; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->in_frame = FALSE; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef POSTPONE_RX_CRC 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we haven't done the CRC as we receive bytes, we 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * must do it now... Jean II */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 0; i < rx_buff->len; i++) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->fcs = irda_fcs(rx_buff->fcs, 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->data[i]); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Test FCS and signal success if the frame is good */ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_buff->fcs == GOOD_FCS) { 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Deliver frame */ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_bump(dev, stats, rx_buff); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wrong CRC, discard frame! */ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irda_device_set_media_busy(dev, TRUE); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3630dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_DEBUG(1, "%s(), crc error\n", __func__); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_errors++; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->rx_crc_errors++; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_unwrap_ce(dev, byte) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle Character Escape character received within a frame 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasync_unwrap_ce(struct net_device *dev, 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats, 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobuff_t *rx_buff, __u8 byte) 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(rx_buff->state) { 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OUTSIDE_FRAME: 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Activate carrier sense */ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irda_device_set_media_busy(dev, TRUE); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case LINK_ESCAPE: 3890dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison IRDA_WARNING("%s: state not defined\n", __func__); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BEGIN_FRAME: 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case INSIDE_FRAME: 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Stuffed byte coming */ 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = LINK_ESCAPE; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_unwrap_other(dev, byte) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle other characters received within a frame 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasync_unwrap_other(struct net_device *dev, 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats, 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobuff_t *rx_buff, __u8 byte) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(rx_buff->state) { 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This is on the critical path, case are ordered by 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * probability (most frequent first) - Jean II */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case INSIDE_FRAME: 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Must be the next byte of the frame */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_buff->len < rx_buff->truesize) { 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->data[rx_buff->len++] = byte; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef POSTPONE_RX_CRC 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n", 4240dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison __func__); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = OUTSIDE_FRAME; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case LINK_ESCAPE: 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stuffed char, complement bit 5 of byte 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * following CE, IrLAP p.114 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte ^= IRDA_TRANS; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_buff->len < rx_buff->truesize) { 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->data[rx_buff->len++] = byte; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef POSTPONE_RX_CRC 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = INSIDE_FRAME; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n", 4430dc47877a3de00ceadea0005189656ae8dc52669Harvey Harrison __func__); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = OUTSIDE_FRAME; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OUTSIDE_FRAME: 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Activate carrier sense */ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(byte != XBOF) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irda_device_set_media_busy(dev, TRUE); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BEGIN_FRAME: 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->data[rx_buff->len++] = byte; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef POSTPONE_RX_CRC 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_buff->state = INSIDE_FRAME; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function async_unwrap_char (dev, rx_buff, byte) 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse and de-stuff frame received from the IrDA-port 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the main entry point for SIR drivers. 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid async_unwrap_char(struct net_device *dev, 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats *stats, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobuff_t *rx_buff, __u8 byte) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(byte) { 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CE: 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_unwrap_ce(dev, stats, rx_buff, byte); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BOF: 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_unwrap_bof(dev, stats, rx_buff, byte); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EOF: 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_unwrap_eof(dev, stats, rx_buff, byte); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds async_unwrap_other(dev, stats, rx_buff, byte); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(async_unwrap_char); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 493