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