162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * isdnhdlc.c -- General purpose ISDN HDLC decoder. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 662306a36Sopenharmony_ci * 2009 Karsten Keil <keil@b1-systems.de> 762306a36Sopenharmony_ci * 2002 Wolfgang Mües <wolfgang@iksw-muees.de> 862306a36Sopenharmony_ci * 2001 Frode Isaksen <fisaksen@bewan.com> 962306a36Sopenharmony_ci * 2001 Kai Germaschewski <kai.germaschewski@gmx.de> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/crc-ccitt.h> 1562306a36Sopenharmony_ci#include <linux/bitrev.h> 1662306a36Sopenharmony_ci#include "isdnhdlc.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/*-------------------------------------------------------------------*/ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciMODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, " 2162306a36Sopenharmony_ci "Frode Isaksen <fisaksen@bewan.com>, " 2262306a36Sopenharmony_ci "Kai Germaschewski <kai.germaschewski@gmx.de>"); 2362306a36Sopenharmony_ciMODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); 2462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/*-------------------------------------------------------------------*/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cienum { 2962306a36Sopenharmony_ci HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, 3062306a36Sopenharmony_ci HDLC_GET_DATA, HDLC_FAST_FLAG 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cienum { 3462306a36Sopenharmony_ci HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, 3562306a36Sopenharmony_ci HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, 3662306a36Sopenharmony_ci HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, 3762306a36Sopenharmony_ci HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); 4362306a36Sopenharmony_ci hdlc->state = HDLC_GET_DATA; 4462306a36Sopenharmony_ci if (features & HDLC_56KBIT) 4562306a36Sopenharmony_ci hdlc->do_adapt56 = 1; 4662306a36Sopenharmony_ci if (features & HDLC_BITREVERSE) 4762306a36Sopenharmony_ci hdlc->do_bitreverse = 1; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_out_init); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); 5462306a36Sopenharmony_ci if (features & HDLC_DCHANNEL) { 5562306a36Sopenharmony_ci hdlc->dchannel = 1; 5662306a36Sopenharmony_ci hdlc->state = HDLC_SEND_FIRST_FLAG; 5762306a36Sopenharmony_ci } else { 5862306a36Sopenharmony_ci hdlc->dchannel = 0; 5962306a36Sopenharmony_ci hdlc->state = HDLC_SEND_FAST_FLAG; 6062306a36Sopenharmony_ci hdlc->ffvalue = 0x7e; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci hdlc->cbin = 0x7e; 6362306a36Sopenharmony_ci if (features & HDLC_56KBIT) { 6462306a36Sopenharmony_ci hdlc->do_adapt56 = 1; 6562306a36Sopenharmony_ci hdlc->state = HDLC_SENDFLAG_B0; 6662306a36Sopenharmony_ci } else 6762306a36Sopenharmony_ci hdlc->data_bits = 8; 6862306a36Sopenharmony_ci if (features & HDLC_BITREVERSE) 6962306a36Sopenharmony_ci hdlc->do_bitreverse = 1; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_rcv_init); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int 7462306a36Sopenharmony_cicheck_frame(struct isdnhdlc_vars *hdlc) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int status; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (hdlc->dstpos < 2) /* too small - framing error */ 7962306a36Sopenharmony_ci status = -HDLC_FRAMING_ERROR; 8062306a36Sopenharmony_ci else if (hdlc->crc != 0xf0b8) /* crc error */ 8162306a36Sopenharmony_ci status = -HDLC_CRC_ERROR; 8262306a36Sopenharmony_ci else { 8362306a36Sopenharmony_ci /* remove CRC */ 8462306a36Sopenharmony_ci hdlc->dstpos -= 2; 8562306a36Sopenharmony_ci /* good frame */ 8662306a36Sopenharmony_ci status = hdlc->dstpos; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci return status; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci The source buffer is scanned for valid HDLC frames looking for 9562306a36Sopenharmony_ci flags (01111110) to indicate the start of a frame. If the start of 9662306a36Sopenharmony_ci the frame is found, the bit stuffing is removed (0 after 5 1's). 9762306a36Sopenharmony_ci When a new flag is found, the complete frame has been received 9862306a36Sopenharmony_ci and the CRC is checked. 9962306a36Sopenharmony_ci If a valid frame is found, the function returns the frame length 10062306a36Sopenharmony_ci excluding the CRC with the bit HDLC_END_OF_FRAME set. 10162306a36Sopenharmony_ci If the beginning of a valid frame is found, the function returns 10262306a36Sopenharmony_ci the length. 10362306a36Sopenharmony_ci If a framing error is found (too many 1s and not a flag) the function 10462306a36Sopenharmony_ci returns the length with the bit HDLC_FRAMING_ERROR set. 10562306a36Sopenharmony_ci If a CRC error is found the function returns the length with the 10662306a36Sopenharmony_ci bit HDLC_CRC_ERROR set. 10762306a36Sopenharmony_ci If the frame length exceeds the destination buffer size, the function 10862306a36Sopenharmony_ci returns the length with the bit HDLC_LENGTH_ERROR set. 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci src - source buffer 11162306a36Sopenharmony_ci slen - source buffer length 11262306a36Sopenharmony_ci count - number of bytes removed (decoded) from the source buffer 11362306a36Sopenharmony_ci dst _ destination buffer 11462306a36Sopenharmony_ci dsize - destination buffer size 11562306a36Sopenharmony_ci returns - number of decoded bytes in the destination buffer and status 11662306a36Sopenharmony_ci flag. 11762306a36Sopenharmony_ci*/ 11862306a36Sopenharmony_ciint isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, 11962306a36Sopenharmony_ci int *count, u8 *dst, int dsize) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci int status = 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci static const unsigned char fast_flag[] = { 12462306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f 12562306a36Sopenharmony_ci }; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci static const unsigned char fast_flag_value[] = { 12862306a36Sopenharmony_ci 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f 12962306a36Sopenharmony_ci }; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci static const unsigned char fast_abort[] = { 13262306a36Sopenharmony_ci 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 13362306a36Sopenharmony_ci }; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define handle_fast_flag(h) \ 13662306a36Sopenharmony_ci do { \ 13762306a36Sopenharmony_ci if (h->cbin == fast_flag[h->bit_shift]) { \ 13862306a36Sopenharmony_ci h->ffvalue = fast_flag_value[h->bit_shift]; \ 13962306a36Sopenharmony_ci h->state = HDLC_FAST_FLAG; \ 14062306a36Sopenharmony_ci h->ffbit_shift = h->bit_shift; \ 14162306a36Sopenharmony_ci h->bit_shift = 1; \ 14262306a36Sopenharmony_ci } else { \ 14362306a36Sopenharmony_ci h->state = HDLC_GET_DATA; \ 14462306a36Sopenharmony_ci h->data_received = 0; \ 14562306a36Sopenharmony_ci } \ 14662306a36Sopenharmony_ci } while (0) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define handle_abort(h) \ 14962306a36Sopenharmony_ci do { \ 15062306a36Sopenharmony_ci h->shift_reg = fast_abort[h->ffbit_shift - 1]; \ 15162306a36Sopenharmony_ci h->hdlc_bits1 = h->ffbit_shift - 2; \ 15262306a36Sopenharmony_ci if (h->hdlc_bits1 < 0) \ 15362306a36Sopenharmony_ci h->hdlc_bits1 = 0; \ 15462306a36Sopenharmony_ci h->data_bits = h->ffbit_shift - 1; \ 15562306a36Sopenharmony_ci h->state = HDLC_GET_DATA; \ 15662306a36Sopenharmony_ci h->data_received = 0; \ 15762306a36Sopenharmony_ci } while (0) 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci *count = slen; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci while (slen > 0) { 16262306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 16362306a36Sopenharmony_ci /* the code is for bitreverse streams */ 16462306a36Sopenharmony_ci if (hdlc->do_bitreverse == 0) 16562306a36Sopenharmony_ci hdlc->cbin = bitrev8(*src++); 16662306a36Sopenharmony_ci else 16762306a36Sopenharmony_ci hdlc->cbin = *src++; 16862306a36Sopenharmony_ci slen--; 16962306a36Sopenharmony_ci hdlc->bit_shift = 8; 17062306a36Sopenharmony_ci if (hdlc->do_adapt56) 17162306a36Sopenharmony_ci hdlc->bit_shift--; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci switch (hdlc->state) { 17562306a36Sopenharmony_ci case STOPPED: 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci case HDLC_FAST_IDLE: 17862306a36Sopenharmony_ci if (hdlc->cbin == 0xff) { 17962306a36Sopenharmony_ci hdlc->bit_shift = 0; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci hdlc->state = HDLC_GET_FLAG_B0; 18362306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 18462306a36Sopenharmony_ci hdlc->bit_shift = 8; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci case HDLC_GET_FLAG_B0: 18762306a36Sopenharmony_ci if (!(hdlc->cbin & 0x80)) { 18862306a36Sopenharmony_ci hdlc->state = HDLC_GETFLAG_B1A6; 18962306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 19062306a36Sopenharmony_ci } else { 19162306a36Sopenharmony_ci if ((!hdlc->do_adapt56) && 19262306a36Sopenharmony_ci (++hdlc->hdlc_bits1 >= 8) && 19362306a36Sopenharmony_ci (hdlc->bit_shift == 1)) 19462306a36Sopenharmony_ci hdlc->state = HDLC_FAST_IDLE; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci hdlc->cbin <<= 1; 19762306a36Sopenharmony_ci hdlc->bit_shift--; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci case HDLC_GETFLAG_B1A6: 20062306a36Sopenharmony_ci if (hdlc->cbin & 0x80) { 20162306a36Sopenharmony_ci hdlc->hdlc_bits1++; 20262306a36Sopenharmony_ci if (hdlc->hdlc_bits1 == 6) 20362306a36Sopenharmony_ci hdlc->state = HDLC_GETFLAG_B7; 20462306a36Sopenharmony_ci } else 20562306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 20662306a36Sopenharmony_ci hdlc->cbin <<= 1; 20762306a36Sopenharmony_ci hdlc->bit_shift--; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case HDLC_GETFLAG_B7: 21062306a36Sopenharmony_ci if (hdlc->cbin & 0x80) { 21162306a36Sopenharmony_ci hdlc->state = HDLC_GET_FLAG_B0; 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci hdlc->state = HDLC_GET_DATA; 21462306a36Sopenharmony_ci hdlc->crc = 0xffff; 21562306a36Sopenharmony_ci hdlc->shift_reg = 0; 21662306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 21762306a36Sopenharmony_ci hdlc->data_bits = 0; 21862306a36Sopenharmony_ci hdlc->data_received = 0; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci hdlc->cbin <<= 1; 22162306a36Sopenharmony_ci hdlc->bit_shift--; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci case HDLC_GET_DATA: 22462306a36Sopenharmony_ci if (hdlc->cbin & 0x80) { 22562306a36Sopenharmony_ci hdlc->hdlc_bits1++; 22662306a36Sopenharmony_ci switch (hdlc->hdlc_bits1) { 22762306a36Sopenharmony_ci case 6: 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci case 7: 23062306a36Sopenharmony_ci if (hdlc->data_received) 23162306a36Sopenharmony_ci /* bad frame */ 23262306a36Sopenharmony_ci status = -HDLC_FRAMING_ERROR; 23362306a36Sopenharmony_ci if (!hdlc->do_adapt56) { 23462306a36Sopenharmony_ci if (hdlc->cbin == fast_abort 23562306a36Sopenharmony_ci [hdlc->bit_shift + 1]) { 23662306a36Sopenharmony_ci hdlc->state = 23762306a36Sopenharmony_ci HDLC_FAST_IDLE; 23862306a36Sopenharmony_ci hdlc->bit_shift = 1; 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci } else 24262306a36Sopenharmony_ci hdlc->state = HDLC_GET_FLAG_B0; 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci default: 24562306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 24662306a36Sopenharmony_ci hdlc->shift_reg |= 0x80; 24762306a36Sopenharmony_ci hdlc->data_bits++; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci } else { 25162306a36Sopenharmony_ci switch (hdlc->hdlc_bits1) { 25262306a36Sopenharmony_ci case 5: 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case 6: 25562306a36Sopenharmony_ci if (hdlc->data_received) 25662306a36Sopenharmony_ci status = check_frame(hdlc); 25762306a36Sopenharmony_ci hdlc->crc = 0xffff; 25862306a36Sopenharmony_ci hdlc->shift_reg = 0; 25962306a36Sopenharmony_ci hdlc->data_bits = 0; 26062306a36Sopenharmony_ci if (!hdlc->do_adapt56) 26162306a36Sopenharmony_ci handle_fast_flag(hdlc); 26262306a36Sopenharmony_ci else { 26362306a36Sopenharmony_ci hdlc->state = HDLC_GET_DATA; 26462306a36Sopenharmony_ci hdlc->data_received = 0; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci default: 26862306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 26962306a36Sopenharmony_ci hdlc->data_bits++; 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci if (status) { 27562306a36Sopenharmony_ci hdlc->dstpos = 0; 27662306a36Sopenharmony_ci *count -= slen; 27762306a36Sopenharmony_ci hdlc->cbin <<= 1; 27862306a36Sopenharmony_ci hdlc->bit_shift--; 27962306a36Sopenharmony_ci return status; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci if (hdlc->data_bits == 8) { 28262306a36Sopenharmony_ci hdlc->data_bits = 0; 28362306a36Sopenharmony_ci hdlc->data_received = 1; 28462306a36Sopenharmony_ci hdlc->crc = crc_ccitt_byte(hdlc->crc, 28562306a36Sopenharmony_ci hdlc->shift_reg); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* good byte received */ 28862306a36Sopenharmony_ci if (hdlc->dstpos < dsize) 28962306a36Sopenharmony_ci dst[hdlc->dstpos++] = hdlc->shift_reg; 29062306a36Sopenharmony_ci else { 29162306a36Sopenharmony_ci /* frame too long */ 29262306a36Sopenharmony_ci status = -HDLC_LENGTH_ERROR; 29362306a36Sopenharmony_ci hdlc->dstpos = 0; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci hdlc->cbin <<= 1; 29762306a36Sopenharmony_ci hdlc->bit_shift--; 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci case HDLC_FAST_FLAG: 30062306a36Sopenharmony_ci if (hdlc->cbin == hdlc->ffvalue) { 30162306a36Sopenharmony_ci hdlc->bit_shift = 0; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci } else { 30462306a36Sopenharmony_ci if (hdlc->cbin == 0xff) { 30562306a36Sopenharmony_ci hdlc->state = HDLC_FAST_IDLE; 30662306a36Sopenharmony_ci hdlc->bit_shift = 0; 30762306a36Sopenharmony_ci } else if (hdlc->ffbit_shift == 8) { 30862306a36Sopenharmony_ci hdlc->state = HDLC_GETFLAG_B7; 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci } else 31162306a36Sopenharmony_ci handle_abort(hdlc); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci default: 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci *count -= slen; 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_decode); 32262306a36Sopenharmony_ci/* 32362306a36Sopenharmony_ci isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci The bit stream starts with a beginning flag (01111110). After 32662306a36Sopenharmony_ci that each byte is added to the bit stream with bit stuffing added 32762306a36Sopenharmony_ci (0 after 5 1's). 32862306a36Sopenharmony_ci When the last byte has been removed from the source buffer, the 32962306a36Sopenharmony_ci CRC (2 bytes is added) and the frame terminates with the ending flag. 33062306a36Sopenharmony_ci For the dchannel, the idle character (all 1's) is also added at the end. 33162306a36Sopenharmony_ci If this function is called with empty source buffer (slen=0), flags or 33262306a36Sopenharmony_ci idle character will be generated. 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci src - source buffer 33562306a36Sopenharmony_ci slen - source buffer length 33662306a36Sopenharmony_ci count - number of bytes removed (encoded) from source buffer 33762306a36Sopenharmony_ci dst _ destination buffer 33862306a36Sopenharmony_ci dsize - destination buffer size 33962306a36Sopenharmony_ci returns - number of encoded bytes in the destination buffer 34062306a36Sopenharmony_ci*/ 34162306a36Sopenharmony_ciint isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, 34262306a36Sopenharmony_ci int *count, u8 *dst, int dsize) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci static const unsigned char xfast_flag_value[] = { 34562306a36Sopenharmony_ci 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e 34662306a36Sopenharmony_ci }; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci int len = 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci *count = slen; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* special handling for one byte frames */ 35362306a36Sopenharmony_ci if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) 35462306a36Sopenharmony_ci hdlc->state = HDLC_SENDFLAG_ONE; 35562306a36Sopenharmony_ci while (dsize > 0) { 35662306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 35762306a36Sopenharmony_ci if (slen && !hdlc->do_closing) { 35862306a36Sopenharmony_ci hdlc->shift_reg = *src++; 35962306a36Sopenharmony_ci slen--; 36062306a36Sopenharmony_ci if (slen == 0) 36162306a36Sopenharmony_ci /* closing sequence, CRC + flag(s) */ 36262306a36Sopenharmony_ci hdlc->do_closing = 1; 36362306a36Sopenharmony_ci hdlc->bit_shift = 8; 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci if (hdlc->state == HDLC_SEND_DATA) { 36662306a36Sopenharmony_ci if (hdlc->data_received) { 36762306a36Sopenharmony_ci hdlc->state = HDLC_SEND_CRC1; 36862306a36Sopenharmony_ci hdlc->crc ^= 0xffff; 36962306a36Sopenharmony_ci hdlc->bit_shift = 8; 37062306a36Sopenharmony_ci hdlc->shift_reg = 37162306a36Sopenharmony_ci hdlc->crc & 0xff; 37262306a36Sopenharmony_ci } else if (!hdlc->do_adapt56) 37362306a36Sopenharmony_ci hdlc->state = 37462306a36Sopenharmony_ci HDLC_SEND_FAST_FLAG; 37562306a36Sopenharmony_ci else 37662306a36Sopenharmony_ci hdlc->state = 37762306a36Sopenharmony_ci HDLC_SENDFLAG_B0; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci switch (hdlc->state) { 38462306a36Sopenharmony_ci case STOPPED: 38562306a36Sopenharmony_ci while (dsize--) 38662306a36Sopenharmony_ci *dst++ = 0xff; 38762306a36Sopenharmony_ci return dsize; 38862306a36Sopenharmony_ci case HDLC_SEND_FAST_FLAG: 38962306a36Sopenharmony_ci hdlc->do_closing = 0; 39062306a36Sopenharmony_ci if (slen == 0) { 39162306a36Sopenharmony_ci /* the code is for bitreverse streams */ 39262306a36Sopenharmony_ci if (hdlc->do_bitreverse == 0) 39362306a36Sopenharmony_ci *dst++ = bitrev8(hdlc->ffvalue); 39462306a36Sopenharmony_ci else 39562306a36Sopenharmony_ci *dst++ = hdlc->ffvalue; 39662306a36Sopenharmony_ci len++; 39762306a36Sopenharmony_ci dsize--; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci fallthrough; 40162306a36Sopenharmony_ci case HDLC_SENDFLAG_ONE: 40262306a36Sopenharmony_ci if (hdlc->bit_shift == 8) { 40362306a36Sopenharmony_ci hdlc->cbin = hdlc->ffvalue >> 40462306a36Sopenharmony_ci (8 - hdlc->data_bits); 40562306a36Sopenharmony_ci hdlc->state = HDLC_SEND_DATA; 40662306a36Sopenharmony_ci hdlc->crc = 0xffff; 40762306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 40862306a36Sopenharmony_ci hdlc->data_received = 1; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case HDLC_SENDFLAG_B0: 41262306a36Sopenharmony_ci hdlc->do_closing = 0; 41362306a36Sopenharmony_ci hdlc->cbin <<= 1; 41462306a36Sopenharmony_ci hdlc->data_bits++; 41562306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 41662306a36Sopenharmony_ci hdlc->state = HDLC_SENDFLAG_B1A6; 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci case HDLC_SENDFLAG_B1A6: 41962306a36Sopenharmony_ci hdlc->cbin <<= 1; 42062306a36Sopenharmony_ci hdlc->data_bits++; 42162306a36Sopenharmony_ci hdlc->cbin++; 42262306a36Sopenharmony_ci if (++hdlc->hdlc_bits1 == 6) 42362306a36Sopenharmony_ci hdlc->state = HDLC_SENDFLAG_B7; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case HDLC_SENDFLAG_B7: 42662306a36Sopenharmony_ci hdlc->cbin <<= 1; 42762306a36Sopenharmony_ci hdlc->data_bits++; 42862306a36Sopenharmony_ci if (slen == 0) { 42962306a36Sopenharmony_ci hdlc->state = HDLC_SENDFLAG_B0; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci if (hdlc->bit_shift == 8) { 43362306a36Sopenharmony_ci hdlc->state = HDLC_SEND_DATA; 43462306a36Sopenharmony_ci hdlc->crc = 0xffff; 43562306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 43662306a36Sopenharmony_ci hdlc->data_received = 1; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci case HDLC_SEND_FIRST_FLAG: 44062306a36Sopenharmony_ci hdlc->data_received = 1; 44162306a36Sopenharmony_ci if (hdlc->data_bits == 8) { 44262306a36Sopenharmony_ci hdlc->state = HDLC_SEND_DATA; 44362306a36Sopenharmony_ci hdlc->crc = 0xffff; 44462306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci hdlc->cbin <<= 1; 44862306a36Sopenharmony_ci hdlc->data_bits++; 44962306a36Sopenharmony_ci if (hdlc->shift_reg & 0x01) 45062306a36Sopenharmony_ci hdlc->cbin++; 45162306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 45262306a36Sopenharmony_ci hdlc->bit_shift--; 45362306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 45462306a36Sopenharmony_ci hdlc->state = HDLC_SEND_DATA; 45562306a36Sopenharmony_ci hdlc->crc = 0xffff; 45662306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case HDLC_SEND_DATA: 46062306a36Sopenharmony_ci hdlc->cbin <<= 1; 46162306a36Sopenharmony_ci hdlc->data_bits++; 46262306a36Sopenharmony_ci if (hdlc->hdlc_bits1 == 5) { 46362306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 46462306a36Sopenharmony_ci break; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci if (hdlc->bit_shift == 8) 46762306a36Sopenharmony_ci hdlc->crc = crc_ccitt_byte(hdlc->crc, 46862306a36Sopenharmony_ci hdlc->shift_reg); 46962306a36Sopenharmony_ci if (hdlc->shift_reg & 0x01) { 47062306a36Sopenharmony_ci hdlc->hdlc_bits1++; 47162306a36Sopenharmony_ci hdlc->cbin++; 47262306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 47362306a36Sopenharmony_ci hdlc->bit_shift--; 47462306a36Sopenharmony_ci } else { 47562306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 47662306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 47762306a36Sopenharmony_ci hdlc->bit_shift--; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci case HDLC_SEND_CRC1: 48162306a36Sopenharmony_ci hdlc->cbin <<= 1; 48262306a36Sopenharmony_ci hdlc->data_bits++; 48362306a36Sopenharmony_ci if (hdlc->hdlc_bits1 == 5) { 48462306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci if (hdlc->shift_reg & 0x01) { 48862306a36Sopenharmony_ci hdlc->hdlc_bits1++; 48962306a36Sopenharmony_ci hdlc->cbin++; 49062306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 49162306a36Sopenharmony_ci hdlc->bit_shift--; 49262306a36Sopenharmony_ci } else { 49362306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 49462306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 49562306a36Sopenharmony_ci hdlc->bit_shift--; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 49862306a36Sopenharmony_ci hdlc->shift_reg = (hdlc->crc >> 8); 49962306a36Sopenharmony_ci hdlc->state = HDLC_SEND_CRC2; 50062306a36Sopenharmony_ci hdlc->bit_shift = 8; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case HDLC_SEND_CRC2: 50462306a36Sopenharmony_ci hdlc->cbin <<= 1; 50562306a36Sopenharmony_ci hdlc->data_bits++; 50662306a36Sopenharmony_ci if (hdlc->hdlc_bits1 == 5) { 50762306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci if (hdlc->shift_reg & 0x01) { 51162306a36Sopenharmony_ci hdlc->hdlc_bits1++; 51262306a36Sopenharmony_ci hdlc->cbin++; 51362306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 51462306a36Sopenharmony_ci hdlc->bit_shift--; 51562306a36Sopenharmony_ci } else { 51662306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 51762306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 51862306a36Sopenharmony_ci hdlc->bit_shift--; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 52162306a36Sopenharmony_ci hdlc->shift_reg = 0x7e; 52262306a36Sopenharmony_ci hdlc->state = HDLC_SEND_CLOSING_FLAG; 52362306a36Sopenharmony_ci hdlc->bit_shift = 8; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci case HDLC_SEND_CLOSING_FLAG: 52762306a36Sopenharmony_ci hdlc->cbin <<= 1; 52862306a36Sopenharmony_ci hdlc->data_bits++; 52962306a36Sopenharmony_ci if (hdlc->hdlc_bits1 == 5) { 53062306a36Sopenharmony_ci hdlc->hdlc_bits1 = 0; 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci if (hdlc->shift_reg & 0x01) 53462306a36Sopenharmony_ci hdlc->cbin++; 53562306a36Sopenharmony_ci hdlc->shift_reg >>= 1; 53662306a36Sopenharmony_ci hdlc->bit_shift--; 53762306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 53862306a36Sopenharmony_ci hdlc->ffvalue = 53962306a36Sopenharmony_ci xfast_flag_value[hdlc->data_bits]; 54062306a36Sopenharmony_ci if (hdlc->dchannel) { 54162306a36Sopenharmony_ci hdlc->ffvalue = 0x7e; 54262306a36Sopenharmony_ci hdlc->state = HDLC_SEND_IDLE1; 54362306a36Sopenharmony_ci hdlc->bit_shift = 8-hdlc->data_bits; 54462306a36Sopenharmony_ci if (hdlc->bit_shift == 0) 54562306a36Sopenharmony_ci hdlc->state = 54662306a36Sopenharmony_ci HDLC_SEND_FAST_IDLE; 54762306a36Sopenharmony_ci } else { 54862306a36Sopenharmony_ci if (!hdlc->do_adapt56) { 54962306a36Sopenharmony_ci hdlc->state = 55062306a36Sopenharmony_ci HDLC_SEND_FAST_FLAG; 55162306a36Sopenharmony_ci hdlc->data_received = 0; 55262306a36Sopenharmony_ci } else { 55362306a36Sopenharmony_ci hdlc->state = HDLC_SENDFLAG_B0; 55462306a36Sopenharmony_ci hdlc->data_received = 0; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci /* Finished this frame, send flags */ 55762306a36Sopenharmony_ci if (dsize > 1) 55862306a36Sopenharmony_ci dsize = 1; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci case HDLC_SEND_IDLE1: 56362306a36Sopenharmony_ci hdlc->do_closing = 0; 56462306a36Sopenharmony_ci hdlc->cbin <<= 1; 56562306a36Sopenharmony_ci hdlc->cbin++; 56662306a36Sopenharmony_ci hdlc->data_bits++; 56762306a36Sopenharmony_ci hdlc->bit_shift--; 56862306a36Sopenharmony_ci if (hdlc->bit_shift == 0) { 56962306a36Sopenharmony_ci hdlc->state = HDLC_SEND_FAST_IDLE; 57062306a36Sopenharmony_ci hdlc->bit_shift = 0; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci case HDLC_SEND_FAST_IDLE: 57462306a36Sopenharmony_ci hdlc->do_closing = 0; 57562306a36Sopenharmony_ci hdlc->cbin = 0xff; 57662306a36Sopenharmony_ci hdlc->data_bits = 8; 57762306a36Sopenharmony_ci if (hdlc->bit_shift == 8) { 57862306a36Sopenharmony_ci hdlc->cbin = 0x7e; 57962306a36Sopenharmony_ci hdlc->state = HDLC_SEND_FIRST_FLAG; 58062306a36Sopenharmony_ci } else { 58162306a36Sopenharmony_ci /* the code is for bitreverse streams */ 58262306a36Sopenharmony_ci if (hdlc->do_bitreverse == 0) 58362306a36Sopenharmony_ci *dst++ = bitrev8(hdlc->cbin); 58462306a36Sopenharmony_ci else 58562306a36Sopenharmony_ci *dst++ = hdlc->cbin; 58662306a36Sopenharmony_ci hdlc->bit_shift = 0; 58762306a36Sopenharmony_ci hdlc->data_bits = 0; 58862306a36Sopenharmony_ci len++; 58962306a36Sopenharmony_ci dsize = 0; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci default: 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci if (hdlc->do_adapt56) { 59662306a36Sopenharmony_ci if (hdlc->data_bits == 7) { 59762306a36Sopenharmony_ci hdlc->cbin <<= 1; 59862306a36Sopenharmony_ci hdlc->cbin++; 59962306a36Sopenharmony_ci hdlc->data_bits++; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci if (hdlc->data_bits == 8) { 60362306a36Sopenharmony_ci /* the code is for bitreverse streams */ 60462306a36Sopenharmony_ci if (hdlc->do_bitreverse == 0) 60562306a36Sopenharmony_ci *dst++ = bitrev8(hdlc->cbin); 60662306a36Sopenharmony_ci else 60762306a36Sopenharmony_ci *dst++ = hdlc->cbin; 60862306a36Sopenharmony_ci hdlc->data_bits = 0; 60962306a36Sopenharmony_ci len++; 61062306a36Sopenharmony_ci dsize--; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci *count -= slen; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return len; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ciEXPORT_SYMBOL(isdnhdlc_encode); 618