2005-04-17 02:20:36 +04:00
/*
* isdnhdlc . c - - General purpose ISDN HDLC decoder .
*
2009-07-08 21:11:09 +04:00
* Copyright ( C )
2009-07-08 22:31:42 +04:00
* 2009 Karsten Keil < keil @ b1 - systems . de >
2009-07-08 21:11:09 +04:00
* 2002 Wolfgang Mües < wolfgang @ iksw - muees . de >
* 2001 Frode Isaksen < fisaksen @ bewan . com >
* 2001 Kai Germaschewski < kai . germaschewski @ gmx . de >
2005-04-17 02:20:36 +04:00
*
2009-07-08 21:11:09 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
2005-04-17 02:20:36 +04:00
*
2009-07-08 21:11:09 +04:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2009-07-08 21:11:09 +04:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/crc-ccitt.h>
2009-07-08 16:21:12 +04:00
# include <linux/isdn/hdlc.h>
2009-07-08 22:31:42 +04:00
# include <linux/bitrev.h>
2005-04-17 02:20:36 +04:00
/*-------------------------------------------------------------------*/
2007-10-20 01:21:04 +04:00
MODULE_AUTHOR ( " Wolfgang Mües <wolfgang@iksw-muees.de>, "
2005-04-17 02:20:36 +04:00
" Frode Isaksen <fisaksen@bewan.com>, "
" Kai Germaschewski <kai.germaschewski@gmx.de> " ) ;
MODULE_DESCRIPTION ( " General purpose ISDN HDLC decoder " ) ;
MODULE_LICENSE ( " GPL " ) ;
/*-------------------------------------------------------------------*/
enum {
2009-07-08 21:11:09 +04:00
HDLC_FAST_IDLE , HDLC_GET_FLAG_B0 , HDLC_GETFLAG_B1A6 , HDLC_GETFLAG_B7 ,
HDLC_GET_DATA , HDLC_FAST_FLAG
2005-04-17 02:20:36 +04:00
} ;
enum {
2009-07-08 21:11:09 +04:00
HDLC_SEND_DATA , HDLC_SEND_CRC1 , HDLC_SEND_FAST_FLAG ,
HDLC_SEND_FIRST_FLAG , HDLC_SEND_CRC2 , HDLC_SEND_CLOSING_FLAG ,
HDLC_SEND_IDLE1 , HDLC_SEND_FAST_IDLE , HDLC_SENDFLAG_B0 ,
2009-07-08 22:58:33 +04:00
HDLC_SENDFLAG_B1A6 , HDLC_SENDFLAG_B7 , STOPPED , HDLC_SENDFLAG_ONE
2005-04-17 02:20:36 +04:00
} ;
2009-07-08 22:31:42 +04:00
void isdnhdlc_rcv_init ( struct isdnhdlc_vars * hdlc , u32 features )
2005-04-17 02:20:36 +04:00
{
2009-07-08 22:31:42 +04:00
memset ( hdlc , 0 , sizeof ( struct isdnhdlc_vars ) ) ;
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GET_DATA ;
2009-07-08 22:31:42 +04:00
if ( features & HDLC_56KBIT )
hdlc - > do_adapt56 = 1 ;
if ( features & HDLC_BITREVERSE )
hdlc - > do_bitreverse = 1 ;
2005-04-17 02:20:36 +04:00
}
2009-07-08 21:11:09 +04:00
EXPORT_SYMBOL ( isdnhdlc_out_init ) ;
2005-04-17 02:20:36 +04:00
2009-07-08 22:31:42 +04:00
void isdnhdlc_out_init ( struct isdnhdlc_vars * hdlc , u32 features )
2005-04-17 02:20:36 +04:00
{
2009-07-08 22:31:42 +04:00
memset ( hdlc , 0 , sizeof ( struct isdnhdlc_vars ) ) ;
if ( features & HDLC_DCHANNEL ) {
2005-04-17 02:20:36 +04:00
hdlc - > dchannel = 1 ;
hdlc - > state = HDLC_SEND_FIRST_FLAG ;
} else {
hdlc - > dchannel = 0 ;
hdlc - > state = HDLC_SEND_FAST_FLAG ;
hdlc - > ffvalue = 0x7e ;
}
hdlc - > cbin = 0x7e ;
2009-07-08 22:31:42 +04:00
if ( features & HDLC_56KBIT ) {
2005-04-17 02:20:36 +04:00
hdlc - > do_adapt56 = 1 ;
hdlc - > state = HDLC_SENDFLAG_B0 ;
2009-07-08 22:31:42 +04:00
} else
2005-04-17 02:20:36 +04:00
hdlc - > data_bits = 8 ;
2009-07-08 22:31:42 +04:00
if ( features & HDLC_BITREVERSE )
hdlc - > do_bitreverse = 1 ;
2005-04-17 02:20:36 +04:00
}
2009-07-08 21:11:09 +04:00
EXPORT_SYMBOL ( isdnhdlc_rcv_init ) ;
static int
check_frame ( struct isdnhdlc_vars * hdlc )
{
int status ;
2012-02-20 07:52:38 +04:00
if ( hdlc - > dstpos < 2 ) /* too small - framing error */
2009-07-08 21:11:09 +04:00
status = - HDLC_FRAMING_ERROR ;
else if ( hdlc - > crc ! = 0xf0b8 ) /* crc error */
status = - HDLC_CRC_ERROR ;
else {
/* remove CRC */
hdlc - > dstpos - = 2 ;
/* good frame */
status = hdlc - > dstpos ;
}
return status ;
}
2005-04-17 02:20:36 +04:00
/*
isdnhdlc_decode - decodes HDLC frames from a transparent bit stream .
The source buffer is scanned for valid HDLC frames looking for
flags ( 01111110 ) to indicate the start of a frame . If the start of
the frame is found , the bit stuffing is removed ( 0 after 5 1 ' s ) .
When a new flag is found , the complete frame has been received
and the CRC is checked .
If a valid frame is found , the function returns the frame length
excluding the CRC with the bit HDLC_END_OF_FRAME set .
If the beginning of a valid frame is found , the function returns
the length .
If a framing error is found ( too many 1 s and not a flag ) the function
returns the length with the bit HDLC_FRAMING_ERROR set .
If a CRC error is found the function returns the length with the
bit HDLC_CRC_ERROR set .
If the frame length exceeds the destination buffer size , the function
returns the length with the bit HDLC_LENGTH_ERROR set .
src - source buffer
slen - source buffer length
count - number of bytes removed ( decoded ) from the source buffer
dst _ destination buffer
dsize - destination buffer size
returns - number of decoded bytes in the destination buffer and status
flag .
2012-02-20 07:52:38 +04:00
*/
2009-07-08 21:11:09 +04:00
int isdnhdlc_decode ( struct isdnhdlc_vars * hdlc , const u8 * src , int slen ,
2012-02-20 07:52:38 +04:00
int * count , u8 * dst , int dsize )
2005-04-17 02:20:36 +04:00
{
2009-07-08 21:11:09 +04:00
int status = 0 ;
2005-04-17 02:20:36 +04:00
2009-07-08 21:11:09 +04:00
static const unsigned char fast_flag [ ] = {
0x00 , 0x00 , 0x00 , 0x20 , 0x30 , 0x38 , 0x3c , 0x3e , 0x3f
2005-04-17 02:20:36 +04:00
} ;
2009-07-08 21:11:09 +04:00
static const unsigned char fast_flag_value [ ] = {
0x00 , 0x7e , 0xfc , 0xf9 , 0xf3 , 0xe7 , 0xcf , 0x9f , 0x3f
2005-04-17 02:20:36 +04:00
} ;
2009-07-08 21:11:09 +04:00
static const unsigned char fast_abort [ ] = {
0x00 , 0x00 , 0x80 , 0xc0 , 0xe0 , 0xf0 , 0xf8 , 0xfc , 0xfe , 0xff
2005-04-17 02:20:36 +04:00
} ;
2012-02-20 07:52:38 +04:00
# define handle_fast_flag(h) \
do { \
if ( h - > cbin = = fast_flag [ h - > bit_shift ] ) { \
h - > ffvalue = fast_flag_value [ h - > bit_shift ] ; \
h - > state = HDLC_FAST_FLAG ; \
h - > ffbit_shift = h - > bit_shift ; \
h - > bit_shift = 1 ; \
} else { \
h - > state = HDLC_GET_DATA ; \
h - > data_received = 0 ; \
} \
2009-07-08 21:11:09 +04:00
} while ( 0 )
2012-02-20 07:52:38 +04:00
# define handle_abort(h) \
do { \
h - > shift_reg = fast_abort [ h - > ffbit_shift - 1 ] ; \
h - > hdlc_bits1 = h - > ffbit_shift - 2 ; \
if ( h - > hdlc_bits1 < 0 ) \
h - > hdlc_bits1 = 0 ; \
h - > data_bits = h - > ffbit_shift - 1 ; \
h - > state = HDLC_GET_DATA ; \
h - > data_received = 0 ; \
2009-07-08 21:11:09 +04:00
} while ( 0 )
2005-04-17 02:20:36 +04:00
* count = slen ;
2009-07-08 21:11:09 +04:00
while ( slen > 0 ) {
if ( hdlc - > bit_shift = = 0 ) {
2009-07-08 22:31:42 +04:00
/* the code is for bitreverse streams */
if ( hdlc - > do_bitreverse = = 0 )
hdlc - > cbin = bitrev8 ( * src + + ) ;
else
hdlc - > cbin = * src + + ;
2005-04-17 02:20:36 +04:00
slen - - ;
hdlc - > bit_shift = 8 ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > do_adapt56 )
hdlc - > bit_shift - - ;
2005-04-17 02:20:36 +04:00
}
2009-07-08 21:11:09 +04:00
switch ( hdlc - > state ) {
2005-04-17 02:20:36 +04:00
case STOPPED :
return 0 ;
case HDLC_FAST_IDLE :
2009-07-08 21:11:09 +04:00
if ( hdlc - > cbin = = 0xff ) {
2005-04-17 02:20:36 +04:00
hdlc - > bit_shift = 0 ;
break ;
}
hdlc - > state = HDLC_GET_FLAG_B0 ;
hdlc - > hdlc_bits1 = 0 ;
hdlc - > bit_shift = 8 ;
break ;
case HDLC_GET_FLAG_B0 :
2009-07-08 21:11:09 +04:00
if ( ! ( hdlc - > cbin & 0x80 ) ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GETFLAG_B1A6 ;
hdlc - > hdlc_bits1 = 0 ;
} else {
2009-07-08 21:11:09 +04:00
if ( ( ! hdlc - > do_adapt56 ) & &
( + + hdlc - > hdlc_bits1 > = 8 ) & &
( hdlc - > bit_shift = = 1 ) )
2012-02-20 07:52:38 +04:00
hdlc - > state = HDLC_FAST_IDLE ;
2005-04-17 02:20:36 +04:00
}
2009-07-08 21:11:09 +04:00
hdlc - > cbin < < = 1 ;
hdlc - > bit_shift - - ;
2005-04-17 02:20:36 +04:00
break ;
case HDLC_GETFLAG_B1A6 :
2009-07-08 21:11:09 +04:00
if ( hdlc - > cbin & 0x80 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 + + ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > hdlc_bits1 = = 6 )
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GETFLAG_B7 ;
2009-07-08 21:11:09 +04:00
} else
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 = 0 ;
2009-07-08 21:11:09 +04:00
hdlc - > cbin < < = 1 ;
hdlc - > bit_shift - - ;
2005-04-17 02:20:36 +04:00
break ;
case HDLC_GETFLAG_B7 :
2009-07-08 21:11:09 +04:00
if ( hdlc - > cbin & 0x80 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GET_FLAG_B0 ;
} else {
hdlc - > state = HDLC_GET_DATA ;
hdlc - > crc = 0xffff ;
hdlc - > shift_reg = 0 ;
hdlc - > hdlc_bits1 = 0 ;
hdlc - > data_bits = 0 ;
hdlc - > data_received = 0 ;
}
2009-07-08 21:11:09 +04:00
hdlc - > cbin < < = 1 ;
hdlc - > bit_shift - - ;
2005-04-17 02:20:36 +04:00
break ;
case HDLC_GET_DATA :
2009-07-08 21:11:09 +04:00
if ( hdlc - > cbin & 0x80 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 + + ;
2009-07-08 21:11:09 +04:00
switch ( hdlc - > hdlc_bits1 ) {
2005-04-17 02:20:36 +04:00
case 6 :
break ;
case 7 :
2009-07-08 21:11:09 +04:00
if ( hdlc - > data_received )
/* bad frame */
2005-04-17 02:20:36 +04:00
status = - HDLC_FRAMING_ERROR ;
2009-07-08 21:11:09 +04:00
if ( ! hdlc - > do_adapt56 ) {
if ( hdlc - > cbin = = fast_abort
[ hdlc - > bit_shift + 1 ] ) {
hdlc - > state =
HDLC_FAST_IDLE ;
hdlc - > bit_shift = 1 ;
2005-04-17 02:20:36 +04:00
break ;
}
2009-07-08 21:11:09 +04:00
} else
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GET_FLAG_B0 ;
break ;
default :
2009-07-08 21:11:09 +04:00
hdlc - > shift_reg > > = 1 ;
2005-04-17 02:20:36 +04:00
hdlc - > shift_reg | = 0x80 ;
hdlc - > data_bits + + ;
break ;
}
} else {
2009-07-08 21:11:09 +04:00
switch ( hdlc - > hdlc_bits1 ) {
2005-04-17 02:20:36 +04:00
case 5 :
break ;
case 6 :
2009-07-08 21:11:09 +04:00
if ( hdlc - > data_received )
status = check_frame ( hdlc ) ;
2005-04-17 02:20:36 +04:00
hdlc - > crc = 0xffff ;
hdlc - > shift_reg = 0 ;
hdlc - > data_bits = 0 ;
2009-07-08 21:11:09 +04:00
if ( ! hdlc - > do_adapt56 )
handle_fast_flag ( hdlc ) ;
else {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GET_DATA ;
hdlc - > data_received = 0 ;
}
break ;
default :
2009-07-08 21:11:09 +04:00
hdlc - > shift_reg > > = 1 ;
2005-04-17 02:20:36 +04:00
hdlc - > data_bits + + ;
break ;
}
hdlc - > hdlc_bits1 = 0 ;
}
if ( status ) {
hdlc - > dstpos = 0 ;
* count - = slen ;
hdlc - > cbin < < = 1 ;
hdlc - > bit_shift - - ;
return status ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > data_bits = = 8 ) {
2005-04-17 02:20:36 +04:00
hdlc - > data_bits = 0 ;
hdlc - > data_received = 1 ;
2009-07-08 21:11:09 +04:00
hdlc - > crc = crc_ccitt_byte ( hdlc - > crc ,
2012-02-20 07:52:38 +04:00
hdlc - > shift_reg ) ;
2005-04-17 02:20:36 +04:00
2009-07-08 21:11:09 +04:00
/* good byte received */
if ( hdlc - > dstpos < dsize )
2005-04-17 02:20:36 +04:00
dst [ hdlc - > dstpos + + ] = hdlc - > shift_reg ;
2009-07-08 21:11:09 +04:00
else {
/* frame too long */
2005-04-17 02:20:36 +04:00
status = - HDLC_LENGTH_ERROR ;
hdlc - > dstpos = 0 ;
}
}
hdlc - > cbin < < = 1 ;
hdlc - > bit_shift - - ;
break ;
case HDLC_FAST_FLAG :
2009-07-08 21:11:09 +04:00
if ( hdlc - > cbin = = hdlc - > ffvalue ) {
2005-04-17 02:20:36 +04:00
hdlc - > bit_shift = 0 ;
break ;
} else {
2009-07-08 21:11:09 +04:00
if ( hdlc - > cbin = = 0xff ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_FAST_IDLE ;
2009-07-08 21:11:09 +04:00
hdlc - > bit_shift = 0 ;
} else if ( hdlc - > ffbit_shift = = 8 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_GETFLAG_B7 ;
break ;
2009-07-08 21:11:09 +04:00
} else
handle_abort ( hdlc ) ;
2005-04-17 02:20:36 +04:00
}
break ;
default :
break ;
}
}
* count - = slen ;
return 0 ;
}
2009-07-08 21:11:09 +04:00
EXPORT_SYMBOL ( isdnhdlc_decode ) ;
2005-04-17 02:20:36 +04:00
/*
isdnhdlc_encode - encodes HDLC frames to a transparent bit stream .
The bit stream starts with a beginning flag ( 01111110 ) . After
that each byte is added to the bit stream with bit stuffing added
( 0 after 5 1 ' s ) .
When the last byte has been removed from the source buffer , the
CRC ( 2 bytes is added ) and the frame terminates with the ending flag .
For the dchannel , the idle character ( all 1 ' s ) is also added at the end .
If this function is called with empty source buffer ( slen = 0 ) , flags or
idle character will be generated .
src - source buffer
slen - source buffer length
count - number of bytes removed ( encoded ) from source buffer
dst _ destination buffer
dsize - destination buffer size
returns - number of encoded bytes in the destination buffer
*/
2009-07-08 21:11:09 +04:00
int isdnhdlc_encode ( struct isdnhdlc_vars * hdlc , const u8 * src , u16 slen ,
2012-02-20 07:52:38 +04:00
int * count , u8 * dst , int dsize )
2005-04-17 02:20:36 +04:00
{
static const unsigned char xfast_flag_value [ ] = {
2009-07-08 21:11:09 +04:00
0x7e , 0x3f , 0x9f , 0xcf , 0xe7 , 0xf3 , 0xf9 , 0xfc , 0x7e
2005-04-17 02:20:36 +04:00
} ;
int len = 0 ;
* count = slen ;
2009-07-08 22:58:33 +04:00
/* special handling for one byte frames */
if ( ( slen = = 1 ) & & ( hdlc - > state = = HDLC_SEND_FAST_FLAG ) )
hdlc - > state = HDLC_SENDFLAG_ONE ;
2005-04-17 02:20:36 +04:00
while ( dsize > 0 ) {
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 ) {
if ( slen & & ! hdlc - > do_closing ) {
2005-04-17 02:20:36 +04:00
hdlc - > shift_reg = * src + + ;
slen - - ;
if ( slen = = 0 )
2009-07-08 21:11:09 +04:00
/* closing sequence, CRC + flag(s) */
hdlc - > do_closing = 1 ;
2005-04-17 02:20:36 +04:00
hdlc - > bit_shift = 8 ;
} else {
2009-07-08 21:11:09 +04:00
if ( hdlc - > state = = HDLC_SEND_DATA ) {
if ( hdlc - > data_received ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SEND_CRC1 ;
hdlc - > crc ^ = 0xffff ;
hdlc - > bit_shift = 8 ;
2009-07-08 21:11:09 +04:00
hdlc - > shift_reg =
hdlc - > crc & 0xff ;
} else if ( ! hdlc - > do_adapt56 )
hdlc - > state =
HDLC_SEND_FAST_FLAG ;
else
hdlc - > state =
HDLC_SENDFLAG_B0 ;
2005-04-17 02:20:36 +04:00
}
}
}
2009-07-08 21:11:09 +04:00
switch ( hdlc - > state ) {
2005-04-17 02:20:36 +04:00
case STOPPED :
while ( dsize - - )
* dst + + = 0xff ;
return dsize ;
case HDLC_SEND_FAST_FLAG :
hdlc - > do_closing = 0 ;
2009-07-08 21:11:09 +04:00
if ( slen = = 0 ) {
2009-07-08 22:31:42 +04:00
/* the code is for bitreverse streams */
if ( hdlc - > do_bitreverse = = 0 )
* dst + + = bitrev8 ( hdlc - > ffvalue ) ;
else
* dst + + = hdlc - > ffvalue ;
2005-04-17 02:20:36 +04:00
len + + ;
dsize - - ;
break ;
}
2009-07-08 22:58:33 +04:00
/* fall through */
case HDLC_SENDFLAG_ONE :
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 8 ) {
hdlc - > cbin = hdlc - > ffvalue > >
( 8 - hdlc - > data_bits ) ;
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SEND_DATA ;
hdlc - > crc = 0xffff ;
hdlc - > hdlc_bits1 = 0 ;
hdlc - > data_received = 1 ;
}
break ;
case HDLC_SENDFLAG_B0 :
hdlc - > do_closing = 0 ;
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
hdlc - > hdlc_bits1 = 0 ;
hdlc - > state = HDLC_SENDFLAG_B1A6 ;
break ;
case HDLC_SENDFLAG_B1A6 :
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
hdlc - > cbin + + ;
2009-07-08 21:11:09 +04:00
if ( + + hdlc - > hdlc_bits1 = = 6 )
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SENDFLAG_B7 ;
break ;
case HDLC_SENDFLAG_B7 :
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
2009-07-08 21:11:09 +04:00
if ( slen = = 0 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SENDFLAG_B0 ;
break ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 8 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SEND_DATA ;
hdlc - > crc = 0xffff ;
hdlc - > hdlc_bits1 = 0 ;
hdlc - > data_received = 1 ;
}
break ;
case HDLC_SEND_FIRST_FLAG :
hdlc - > data_received = 1 ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > data_bits = = 8 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SEND_DATA ;
hdlc - > crc = 0xffff ;
hdlc - > hdlc_bits1 = 0 ;
break ;
}
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > shift_reg & 0x01 )
2005-04-17 02:20:36 +04:00
hdlc - > cbin + + ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SEND_DATA ;
hdlc - > crc = 0xffff ;
hdlc - > hdlc_bits1 = 0 ;
}
break ;
case HDLC_SEND_DATA :
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > hdlc_bits1 = = 5 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 = 0 ;
break ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 8 )
hdlc - > crc = crc_ccitt_byte ( hdlc - > crc ,
2012-02-20 07:52:38 +04:00
hdlc - > shift_reg ) ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > shift_reg & 0x01 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 + + ;
hdlc - > cbin + + ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
} else {
hdlc - > hdlc_bits1 = 0 ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
}
break ;
case HDLC_SEND_CRC1 :
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > hdlc_bits1 = = 5 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 = 0 ;
break ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > shift_reg & 0x01 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 + + ;
hdlc - > cbin + + ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
} else {
hdlc - > hdlc_bits1 = 0 ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 ) {
2005-04-17 02:20:36 +04:00
hdlc - > shift_reg = ( hdlc - > crc > > 8 ) ;
hdlc - > state = HDLC_SEND_CRC2 ;
hdlc - > bit_shift = 8 ;
}
break ;
case HDLC_SEND_CRC2 :
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > hdlc_bits1 = = 5 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 = 0 ;
break ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > shift_reg & 0x01 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 + + ;
hdlc - > cbin + + ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
} else {
hdlc - > hdlc_bits1 = 0 ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 ) {
2005-04-17 02:20:36 +04:00
hdlc - > shift_reg = 0x7e ;
hdlc - > state = HDLC_SEND_CLOSING_FLAG ;
hdlc - > bit_shift = 8 ;
}
break ;
case HDLC_SEND_CLOSING_FLAG :
hdlc - > cbin < < = 1 ;
hdlc - > data_bits + + ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > hdlc_bits1 = = 5 ) {
2005-04-17 02:20:36 +04:00
hdlc - > hdlc_bits1 = 0 ;
break ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > shift_reg & 0x01 )
2005-04-17 02:20:36 +04:00
hdlc - > cbin + + ;
hdlc - > shift_reg > > = 1 ;
hdlc - > bit_shift - - ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 ) {
hdlc - > ffvalue =
xfast_flag_value [ hdlc - > data_bits ] ;
if ( hdlc - > dchannel ) {
2005-04-17 02:20:36 +04:00
hdlc - > ffvalue = 0x7e ;
hdlc - > state = HDLC_SEND_IDLE1 ;
hdlc - > bit_shift = 8 - hdlc - > data_bits ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 )
hdlc - > state =
HDLC_SEND_FAST_IDLE ;
2005-04-17 02:20:36 +04:00
} else {
2009-07-08 21:11:09 +04:00
if ( ! hdlc - > do_adapt56 ) {
hdlc - > state =
HDLC_SEND_FAST_FLAG ;
2005-04-17 02:20:36 +04:00
hdlc - > data_received = 0 ;
} else {
hdlc - > state = HDLC_SENDFLAG_B0 ;
hdlc - > data_received = 0 ;
}
2009-07-08 21:11:09 +04:00
/* Finished this frame, send flags */
if ( dsize > 1 )
dsize = 1 ;
2005-04-17 02:20:36 +04:00
}
}
break ;
case HDLC_SEND_IDLE1 :
hdlc - > do_closing = 0 ;
hdlc - > cbin < < = 1 ;
hdlc - > cbin + + ;
hdlc - > data_bits + + ;
hdlc - > bit_shift - - ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 0 ) {
2005-04-17 02:20:36 +04:00
hdlc - > state = HDLC_SEND_FAST_IDLE ;
hdlc - > bit_shift = 0 ;
}
break ;
case HDLC_SEND_FAST_IDLE :
hdlc - > do_closing = 0 ;
hdlc - > cbin = 0xff ;
hdlc - > data_bits = 8 ;
2009-07-08 21:11:09 +04:00
if ( hdlc - > bit_shift = = 8 ) {
2005-04-17 02:20:36 +04:00
hdlc - > cbin = 0x7e ;
hdlc - > state = HDLC_SEND_FIRST_FLAG ;
} else {
2009-07-08 22:31:42 +04:00
/* the code is for bitreverse streams */
if ( hdlc - > do_bitreverse = = 0 )
* dst + + = bitrev8 ( hdlc - > cbin ) ;
else
* dst + + = hdlc - > cbin ;
2009-07-08 21:11:09 +04:00
hdlc - > bit_shift = 0 ;
hdlc - > data_bits = 0 ;
2005-04-17 02:20:36 +04:00
len + + ;
dsize = 0 ;
}
break ;
default :
break ;
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > do_adapt56 ) {
if ( hdlc - > data_bits = = 7 ) {
2005-04-17 02:20:36 +04:00
hdlc - > cbin < < = 1 ;
hdlc - > cbin + + ;
hdlc - > data_bits + + ;
}
}
2009-07-08 21:11:09 +04:00
if ( hdlc - > data_bits = = 8 ) {
2009-07-08 22:31:42 +04:00
/* the code is for bitreverse streams */
if ( hdlc - > do_bitreverse = = 0 )
* dst + + = bitrev8 ( hdlc - > cbin ) ;
else
* dst + + = hdlc - > cbin ;
2005-04-17 02:20:36 +04:00
hdlc - > data_bits = 0 ;
len + + ;
dsize - - ;
}
}
* count - = slen ;
return len ;
}
EXPORT_SYMBOL ( isdnhdlc_encode ) ;