From cb3824bade2549d7ad059d5802da43312540fdee Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 14:21:12 +0200 Subject: ISDN: Make isdnhdlc usable for other ISDN drivers isdnhdlc is useful for other ISDN drivers as well. Move the include file to a central location and the source to the central isdn location. Signed-off-by: Karsten Keil --- drivers/isdn/i4l/isdnhdlc.c | 603 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 603 insertions(+) create mode 100644 drivers/isdn/i4l/isdnhdlc.c (limited to 'drivers/isdn/i4l/isdnhdlc.c') diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c new file mode 100644 index 00000000000..44ec7418496 --- /dev/null +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -0,0 +1,603 @@ +/* + * isdnhdlc.c -- General purpose ISDN HDLC decoder. + * + *Copyright (C) 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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. + * + * 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. + * + * 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 02139, USA. + */ + +#include +#include +#include +#include + +/*-------------------------------------------------------------------*/ + +MODULE_AUTHOR("Wolfgang Mües , " + "Frode Isaksen , " + "Kai Germaschewski "); +MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); +MODULE_LICENSE("GPL"); + +/*-------------------------------------------------------------------*/ + +enum { + HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, + HDLC_GET_DATA,HDLC_FAST_FLAG +}; + +enum { + 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, + HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED +}; + +void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->state = HDLC_GET_DATA; + hdlc->do_adapt56 = do_adapt56; + hdlc->dchannel = 0; + hdlc->crc = 0; + hdlc->cbin = 0; + hdlc->shift_reg = 0; + hdlc->ffvalue = 0; + hdlc->dstpos = 0; +} + +void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->do_closing = 0; + hdlc->ffvalue = 0; + if (is_d_channel) { + 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; + hdlc->bit_shift = 0; + if(do_adapt56){ + hdlc->do_adapt56 = 1; + hdlc->data_bits = 0; + hdlc->state = HDLC_SENDFLAG_B0; + } else { + hdlc->do_adapt56 = 0; + hdlc->data_bits = 8; + } + hdlc->shift_reg = 0; +} + +/* + 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 1s 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. + */ +int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, + int slen, int *count, unsigned char *dst, int dsize) +{ + int status=0; + + static const unsigned char fast_flag[]={ + 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + }; + + static const unsigned char fast_flag_value[]={ + 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + }; + + static const unsigned char fast_abort[]={ + 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + }; + + *count = slen; + + while(slen > 0){ + if(hdlc->bit_shift==0){ + hdlc->cbin = *src++; + slen--; + hdlc->bit_shift = 8; + if(hdlc->do_adapt56){ + hdlc->bit_shift --; + } + } + + switch(hdlc->state){ + case STOPPED: + return 0; + case HDLC_FAST_IDLE: + if(hdlc->cbin == 0xff){ + 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: + if(!(hdlc->cbin & 0x80)) { + hdlc->state = HDLC_GETFLAG_B1A6; + hdlc->hdlc_bits1 = 0; + } else { + if(!hdlc->do_adapt56){ + if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + hdlc->state = HDLC_FAST_IDLE; + } + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B1A6: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + if(hdlc->hdlc_bits1==6){ + hdlc->state = HDLC_GETFLAG_B7; + } + } else { + hdlc->hdlc_bits1 = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B7: + if(hdlc->cbin & 0x80) { + 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; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GET_DATA: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + switch(hdlc->hdlc_bits1){ + case 6: + break; + case 7: + if(hdlc->data_received) { + // bad frame + status = -HDLC_FRAMING_ERROR; + } + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=1; + break; + } + } else { + hdlc->state = HDLC_GET_FLAG_B0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->shift_reg |= 0x80; + hdlc->data_bits++; + break; + } + } else { + switch(hdlc->hdlc_bits1){ + case 5: + break; + case 6: + if(hdlc->data_received){ + if (hdlc->dstpos < 2) { + 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; + } + } + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->data_bits = 0; + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ + hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; + hdlc->state = HDLC_FAST_FLAG; + hdlc->ffbit_shift = hdlc->bit_shift; + hdlc->bit_shift = 1; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->data_bits++; + break; + } + hdlc->hdlc_bits1 = 0; + } + if (status) { + hdlc->dstpos = 0; + *count -= slen; + hdlc->cbin <<= 1; + hdlc->bit_shift--; + return status; + } + if(hdlc->data_bits==8){ + hdlc->data_bits = 0; + hdlc->data_received = 1; + hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + + // good byte received + if (hdlc->dstpos < dsize) { + dst[hdlc->dstpos++] = hdlc->shift_reg; + } else { + // frame too long + status = -HDLC_LENGTH_ERROR; + hdlc->dstpos = 0; + } + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_FAST_FLAG: + if(hdlc->cbin==hdlc->ffvalue){ + hdlc->bit_shift = 0; + break; + } else { + if(hdlc->cbin == 0xff){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=0; + } else if(hdlc->ffbit_shift==8){ + hdlc->state = HDLC_GETFLAG_B7; + break; + } else { + hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; + hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; + if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; + hdlc->data_bits = hdlc->ffbit_shift-1; + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } + break; + default: + break; + } + } + *count -= slen; + return 0; +} + +/* + 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 +*/ +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, + unsigned short slen, int *count, + unsigned char *dst, int dsize) +{ + static const unsigned char xfast_flag_value[] = { + 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + }; + + int len = 0; + + *count = slen; + + while (dsize > 0) { + if(hdlc->bit_shift==0){ + if(slen && !hdlc->do_closing){ + hdlc->shift_reg = *src++; + slen--; + if (slen == 0) + hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + hdlc->bit_shift = 8; + } else { + if(hdlc->state == HDLC_SEND_DATA){ + if(hdlc->data_received){ + hdlc->state = HDLC_SEND_CRC1; + hdlc->crc ^= 0xffff; + hdlc->bit_shift = 8; + hdlc->shift_reg = hdlc->crc & 0xff; + } else if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + } + } + + } + } + + switch(hdlc->state){ + case STOPPED: + while (dsize--) + *dst++ = 0xff; + + return dsize; + case HDLC_SEND_FAST_FLAG: + hdlc->do_closing = 0; + if(slen == 0){ + *dst++ = hdlc->ffvalue; + len++; + dsize--; + break; + } + if(hdlc->bit_shift==8){ + hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + 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++; + if(++hdlc->hdlc_bits1 == 6) + hdlc->state = HDLC_SENDFLAG_B7; + break; + case HDLC_SENDFLAG_B7: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(slen == 0){ + hdlc->state = HDLC_SENDFLAG_B0; + break; + } + if(hdlc->bit_shift==8){ + 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; + if(hdlc->data_bits==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + break; + } + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->shift_reg & 0x01) + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + } + break; + case HDLC_SEND_DATA: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->bit_shift==8){ + hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + } + if(hdlc->shift_reg & 0x01){ + 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++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + 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++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + 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++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->cbin++; + } + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; + if(hdlc->dchannel){ + hdlc->ffvalue = 0x7e; + hdlc->state = HDLC_SEND_IDLE1; + hdlc->bit_shift = 8-hdlc->data_bits; + if(hdlc->bit_shift==0) + hdlc->state = HDLC_SEND_FAST_IDLE; + } else { + if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->data_received = 0; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + hdlc->data_received = 0; + } + // Finished with this frame, send flags + if (dsize > 1) dsize = 1; + } + } + break; + case HDLC_SEND_IDLE1: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + 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; + if(hdlc->bit_shift == 8){ + hdlc->cbin = 0x7e; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + *dst++ = hdlc->cbin; + hdlc->bit_shift = hdlc->data_bits = 0; + len++; + dsize = 0; + } + break; + default: + break; + } + if(hdlc->do_adapt56){ + if(hdlc->data_bits==7){ + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + } + } + if(hdlc->data_bits==8){ + *dst++ = hdlc->cbin; + hdlc->data_bits = 0; + len++; + dsize--; + } + } + *count -= slen; + + return len; +} + +EXPORT_SYMBOL(isdnhdlc_rcv_init); +EXPORT_SYMBOL(isdnhdlc_decode); +EXPORT_SYMBOL(isdnhdlc_out_init); +EXPORT_SYMBOL(isdnhdlc_encode); -- cgit v1.2.3-70-g09d2 From 6bd4bcd3cd8affc09eaee7efbc037f65f4a71501 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 19:11:09 +0200 Subject: ISDN: Clean up isdnhdlc code Clean up isdnhdlc to meet current code standard. Remove hint to already removed bit reversal table. Signed-off-by: Karsten Keil --- drivers/isdn/i4l/isdnhdlc.c | 366 +++++++++++++++++++++++--------------------- include/linux/isdn/hdlc.h | 68 ++++---- 2 files changed, 231 insertions(+), 203 deletions(-) (limited to 'drivers/isdn/i4l/isdnhdlc.c') diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index 44ec7418496..b80e55ab891 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -1,23 +1,24 @@ /* * isdnhdlc.c -- General purpose ISDN HDLC decoder. * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski + * Copyright (C) + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski * - * 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. + * 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. * - * 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. + * 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. * - * 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 02139, USA. + * 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 02139, USA. */ #include @@ -36,20 +37,20 @@ MODULE_LICENSE("GPL"); /*-------------------------------------------------------------------*/ enum { - HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, - HDLC_GET_DATA,HDLC_FAST_FLAG + HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, + HDLC_GET_DATA, HDLC_FAST_FLAG }; enum { - 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, - HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED + 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, + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED }; -void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56) { - hdlc->bit_shift = 0; + hdlc->bit_shift = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->ffbit_shift = 0; @@ -63,10 +64,12 @@ void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) hdlc->ffvalue = 0; hdlc->dstpos = 0; } +EXPORT_SYMBOL(isdnhdlc_out_init); -void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, + int do_adapt56) { - hdlc->bit_shift = 0; + hdlc->bit_shift = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->ffbit_shift = 0; @@ -83,7 +86,7 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada } hdlc->cbin = 0x7e; hdlc->bit_shift = 0; - if(do_adapt56){ + if (do_adapt56) { hdlc->do_adapt56 = 1; hdlc->data_bits = 0; hdlc->state = HDLC_SENDFLAG_B0; @@ -93,6 +96,25 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada } hdlc->shift_reg = 0; } +EXPORT_SYMBOL(isdnhdlc_rcv_init); + +static int +check_frame(struct isdnhdlc_vars *hdlc) +{ + int status; + + if (hdlc->dstpos < 2) /* too small - framing error */ + 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; +} /* isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. @@ -121,40 +143,63 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada returns - number of decoded bytes in the destination buffer and status flag. */ -int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, - int slen, int *count, unsigned char *dst, int dsize) +int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, + int *count, u8 *dst, int dsize) { - int status=0; + int status = 0; - static const unsigned char fast_flag[]={ - 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + static const unsigned char fast_flag[] = { + 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f }; - static const unsigned char fast_flag_value[]={ - 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + static const unsigned char fast_flag_value[] = { + 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f }; - static const unsigned char fast_abort[]={ - 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + static const unsigned char fast_abort[] = { + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; +#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;\ + } \ + } while (0) + +#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;\ + } while (0) + *count = slen; - while(slen > 0){ - if(hdlc->bit_shift==0){ + while (slen > 0) { + if (hdlc->bit_shift == 0) { hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; - if(hdlc->do_adapt56){ - hdlc->bit_shift --; - } + if (hdlc->do_adapt56) + hdlc->bit_shift--; } - switch(hdlc->state){ + switch (hdlc->state) { case STOPPED: return 0; case HDLC_FAST_IDLE: - if(hdlc->cbin == 0xff){ + if (hdlc->cbin == 0xff) { hdlc->bit_shift = 0; break; } @@ -163,32 +208,30 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift = 8; break; case HDLC_GET_FLAG_B0: - if(!(hdlc->cbin & 0x80)) { + if (!(hdlc->cbin & 0x80)) { hdlc->state = HDLC_GETFLAG_B1A6; hdlc->hdlc_bits1 = 0; } else { - if(!hdlc->do_adapt56){ - if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + if ((!hdlc->do_adapt56) && + (++hdlc->hdlc_bits1 >= 8) && + (hdlc->bit_shift == 1)) hdlc->state = HDLC_FAST_IDLE; - } } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GETFLAG_B1A6: - if(hdlc->cbin & 0x80){ + if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; - if(hdlc->hdlc_bits1==6){ + if (hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_GETFLAG_B7; - } - } else { + } else hdlc->hdlc_bits1 = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GETFLAG_B7: - if(hdlc->cbin & 0x80) { + if (hdlc->cbin & 0x80) { hdlc->state = HDLC_GET_FLAG_B0; } else { hdlc->state = HDLC_GET_DATA; @@ -198,74 +241,55 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->data_bits = 0; hdlc->data_received = 0; } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GET_DATA: - if(hdlc->cbin & 0x80){ + if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; - switch(hdlc->hdlc_bits1){ + switch (hdlc->hdlc_bits1) { case 6: break; case 7: - if(hdlc->data_received) { - // bad frame + if (hdlc->data_received) + /* bad frame */ status = -HDLC_FRAMING_ERROR; - } - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=1; + if (!hdlc->do_adapt56) { + if (hdlc->cbin == fast_abort + [hdlc->bit_shift + 1]) { + hdlc->state = + HDLC_FAST_IDLE; + hdlc->bit_shift = 1; break; } - } else { + } else hdlc->state = HDLC_GET_FLAG_B0; - } break; default: - hdlc->shift_reg>>=1; + hdlc->shift_reg >>= 1; hdlc->shift_reg |= 0x80; hdlc->data_bits++; break; } } else { - switch(hdlc->hdlc_bits1){ + switch (hdlc->hdlc_bits1) { case 5: break; case 6: - if(hdlc->data_received){ - if (hdlc->dstpos < 2) { - 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; - } - } + if (hdlc->data_received) + status = check_frame(hdlc); hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->data_bits = 0; - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ - hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; - hdlc->state = HDLC_FAST_FLAG; - hdlc->ffbit_shift = hdlc->bit_shift; - hdlc->bit_shift = 1; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } else { + if (!hdlc->do_adapt56) + handle_fast_flag(hdlc); + else { hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } break; default: - hdlc->shift_reg>>=1; + hdlc->shift_reg >>= 1; hdlc->data_bits++; break; } @@ -278,16 +302,17 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift--; return status; } - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { hdlc->data_bits = 0; hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); - // good byte received - if (hdlc->dstpos < dsize) { + /* good byte received */ + if (hdlc->dstpos < dsize) dst[hdlc->dstpos++] = hdlc->shift_reg; - } else { - // frame too long + else { + /* frame too long */ status = -HDLC_LENGTH_ERROR; hdlc->dstpos = 0; } @@ -296,24 +321,18 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift--; break; case HDLC_FAST_FLAG: - if(hdlc->cbin==hdlc->ffvalue){ + if (hdlc->cbin == hdlc->ffvalue) { hdlc->bit_shift = 0; break; } else { - if(hdlc->cbin == 0xff){ + if (hdlc->cbin == 0xff) { hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=0; - } else if(hdlc->ffbit_shift==8){ + hdlc->bit_shift = 0; + } else if (hdlc->ffbit_shift == 8) { hdlc->state = HDLC_GETFLAG_B7; break; - } else { - hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; - hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; - if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; - hdlc->data_bits = hdlc->ffbit_shift-1; - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } + } else + handle_abort(hdlc); } break; default: @@ -323,7 +342,7 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, *count -= slen; return 0; } - +EXPORT_SYMBOL(isdnhdlc_decode); /* isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. @@ -343,12 +362,11 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, dsize - destination buffer size returns - number of encoded bytes in the destination buffer */ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, - unsigned short slen, int *count, - unsigned char *dst, int dsize) +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, + int *count, u8 *dst, int dsize) { static const unsigned char xfast_flag_value[] = { - 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e }; int len = 0; @@ -356,31 +374,34 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, *count = slen; while (dsize > 0) { - if(hdlc->bit_shift==0){ - if(slen && !hdlc->do_closing){ + if (hdlc->bit_shift == 0) { + if (slen && !hdlc->do_closing) { hdlc->shift_reg = *src++; slen--; if (slen == 0) - hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + /* closing sequence, CRC + flag(s) */ + hdlc->do_closing = 1; hdlc->bit_shift = 8; } else { - if(hdlc->state == HDLC_SEND_DATA){ - if(hdlc->data_received){ + if (hdlc->state == HDLC_SEND_DATA) { + if (hdlc->data_received) { hdlc->state = HDLC_SEND_CRC1; hdlc->crc ^= 0xffff; hdlc->bit_shift = 8; - hdlc->shift_reg = hdlc->crc & 0xff; - } else if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - } + hdlc->shift_reg = + hdlc->crc & 0xff; + } else if (!hdlc->do_adapt56) + hdlc->state = + HDLC_SEND_FAST_FLAG; + else + hdlc->state = + HDLC_SENDFLAG_B0; } } } - switch(hdlc->state){ + switch (hdlc->state) { case STOPPED: while (dsize--) *dst++ = 0xff; @@ -388,14 +409,15 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, return dsize; case HDLC_SEND_FAST_FLAG: hdlc->do_closing = 0; - if(slen == 0){ + if (slen == 0) { *dst++ = hdlc->ffvalue; len++; dsize--; break; } - if(hdlc->bit_shift==8){ - hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + if (hdlc->bit_shift == 8) { + hdlc->cbin = hdlc->ffvalue >> + (8 - hdlc->data_bits); hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -413,17 +435,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->cbin <<= 1; hdlc->data_bits++; hdlc->cbin++; - if(++hdlc->hdlc_bits1 == 6) + if (++hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_SENDFLAG_B7; break; case HDLC_SENDFLAG_B7: hdlc->cbin <<= 1; hdlc->data_bits++; - if(slen == 0){ + if (slen == 0) { hdlc->state = HDLC_SENDFLAG_B0; break; } - if(hdlc->bit_shift==8){ + if (hdlc->bit_shift == 8) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -432,7 +454,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, break; case HDLC_SEND_FIRST_FLAG: hdlc->data_received = 1; - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -440,11 +462,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, } hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->shift_reg & 0x01) + if (hdlc->shift_reg & 0x01) hdlc->cbin++; hdlc->shift_reg >>= 1; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -453,14 +475,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_DATA: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->bit_shift==8){ - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - } - if(hdlc->shift_reg & 0x01){ + if (hdlc->bit_shift == 8) + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -474,11 +496,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CRC1: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -488,7 +510,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->shift_reg >>= 1; hdlc->bit_shift--; } - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->shift_reg = (hdlc->crc >> 8); hdlc->state = HDLC_SEND_CRC2; hdlc->bit_shift = 8; @@ -497,11 +519,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CRC2: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -511,7 +533,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->shift_reg >>= 1; hdlc->bit_shift--; } - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->shift_reg = 0x7e; hdlc->state = HDLC_SEND_CLOSING_FLAG; hdlc->bit_shift = 8; @@ -520,33 +542,36 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CLOSING_FLAG: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) hdlc->cbin++; - } hdlc->shift_reg >>= 1; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; - if(hdlc->dchannel){ + if (hdlc->bit_shift == 0) { + hdlc->ffvalue = + xfast_flag_value[hdlc->data_bits]; + if (hdlc->dchannel) { hdlc->ffvalue = 0x7e; hdlc->state = HDLC_SEND_IDLE1; hdlc->bit_shift = 8-hdlc->data_bits; - if(hdlc->bit_shift==0) - hdlc->state = HDLC_SEND_FAST_IDLE; + if (hdlc->bit_shift == 0) + hdlc->state = + HDLC_SEND_FAST_IDLE; } else { - if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; + if (!hdlc->do_adapt56) { + hdlc->state = + HDLC_SEND_FAST_FLAG; hdlc->data_received = 0; } else { hdlc->state = HDLC_SENDFLAG_B0; hdlc->data_received = 0; } - // Finished with this frame, send flags - if (dsize > 1) dsize = 1; + /* Finished this frame, send flags */ + if (dsize > 1) + dsize = 1; } } break; @@ -556,7 +581,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->cbin++; hdlc->data_bits++; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->state = HDLC_SEND_FAST_IDLE; hdlc->bit_shift = 0; } @@ -565,12 +590,13 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->do_closing = 0; hdlc->cbin = 0xff; hdlc->data_bits = 8; - if(hdlc->bit_shift == 8){ + if (hdlc->bit_shift == 8) { hdlc->cbin = 0x7e; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { *dst++ = hdlc->cbin; - hdlc->bit_shift = hdlc->data_bits = 0; + hdlc->bit_shift = 0; + hdlc->data_bits = 0; len++; dsize = 0; } @@ -578,14 +604,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, default: break; } - if(hdlc->do_adapt56){ - if(hdlc->data_bits==7){ + if (hdlc->do_adapt56) { + if (hdlc->data_bits == 7) { hdlc->cbin <<= 1; hdlc->cbin++; hdlc->data_bits++; } } - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { *dst++ = hdlc->cbin; hdlc->data_bits = 0; len++; @@ -596,8 +622,4 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, return len; } - -EXPORT_SYMBOL(isdnhdlc_rcv_init); -EXPORT_SYMBOL(isdnhdlc_decode); -EXPORT_SYMBOL(isdnhdlc_out_init); EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h index cf0a95a2401..8f3540c7f69 100644 --- a/include/linux/isdn/hdlc.h +++ b/include/linux/isdn/hdlc.h @@ -1,27 +1,28 @@ /* - * isdnhdlc.h -- General purpose ISDN HDLC decoder. + * hdlc.h -- General purpose ISDN HDLC decoder. * * Implementation of a HDLC decoder/encoder in software. * Neccessary because some ISDN devices don't have HDLC - * controllers. Also included: a bit reversal table. + * controllers. * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski + * Copyright (C) + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski * - * 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. + * 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. * - * 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. + * 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. * - * 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 02139, USA. + * 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 02139, USA. */ #ifndef __ISDNHDLC_H__ @@ -31,20 +32,24 @@ struct isdnhdlc_vars { int bit_shift; int hdlc_bits1; int data_bits; - int ffbit_shift; // encoding only + int ffbit_shift; /* encoding only */ int state; int dstpos; - unsigned short crc; + u16 crc; - unsigned char cbin; - unsigned char shift_reg; - unsigned char ffvalue; + u8 cbin; + u8 shift_reg; + u8 ffvalue; - unsigned int data_received:1; // set if transferring data - unsigned int dchannel:1; // set if D channel (send idle instead of flags) - unsigned int do_adapt56:1; // set if 56K adaptation - unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag + /* set if transferring data */ + u32 data_received:1; + /* set if D channel (send idle instead of flags) */ + u32 dchannel:1; + /* set if 56K adaptation */ + u32 do_adapt56:1; + /* set if in closing phase (need to send CRC + flag) */ + u32 do_closing:1; }; @@ -57,14 +62,15 @@ struct isdnhdlc_vars { #define HDLC_CRC_ERROR 2 #define HDLC_LENGTH_ERROR 3 -extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); +extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56); -extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, - unsigned char *dst, int dsize); +extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, + int slen, int *count, u8 *dst, int dsize); -extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); +extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, + int do_adapt56); -extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, - unsigned char *dst,int dsize); +extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, + u16 slen, int *count, u8 *dst, int dsize); #endif /* __ISDNHDLC_H__ */ -- cgit v1.2.3-70-g09d2 From c38fc3bc2ecddd4f5278131603e6964cbed071b2 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 20:31:42 +0200 Subject: ISDN: Add support for none reverse bitstreams to isdnhdc The original isdnhdlc code was developed for devices which had reversed bitorder in the byte stream. Adding code to handle normal bitstreams as well. Signed-off-by: Karsten Keil --- drivers/isdn/hisax/st5481_b.c | 5 ++- drivers/isdn/hisax/st5481_d.c | 2 +- drivers/isdn/hisax/st5481_usb.c | 11 ++++--- drivers/isdn/i4l/isdnhdlc.c | 70 ++++++++++++++++++++--------------------- include/linux/isdn/hdlc.h | 12 +++++-- 5 files changed, 56 insertions(+), 44 deletions(-) (limited to 'drivers/isdn/i4l/isdnhdlc.c') diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 0074b600a0e..95b1cdd9795 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -218,7 +218,10 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode) if (bcs->mode != L1_MODE_NULL) { // Open the B channel if (bcs->mode != L1_MODE_TRANS) { - isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K); + u32 features = HDLC_BITREVERSE; + if (bcs->mode == L1_MODE_HDLC_56K) + features |= HDLC_56KBIT; + isdnhdlc_out_init(&b_out->hdlc_state, features); } st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL); diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 077991c1cd0..39e8e49cfd2 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -417,7 +417,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg) DBG(2,"len=%d",skb->len); - isdnhdlc_out_init(&d_out->hdlc_state, 1, 0); + isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE); if (test_and_set_bit(buf_nr, &d_out->busy)) { WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 2b3a055059e..10d41c5d73e 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -637,10 +637,13 @@ void st5481_in_mode(struct st5481_in *in, int mode) usb_unlink_urb(in->urb[1]); if (in->mode != L1_MODE_NULL) { - if (in->mode != L1_MODE_TRANS) - isdnhdlc_rcv_init(&in->hdlc_state, - in->mode == L1_MODE_HDLC_56K); - + if (in->mode != L1_MODE_TRANS) { + u32 features = HDLC_BITREVERSE; + + if (in->mode == L1_MODE_HDLC_56K) + features |= HDLC_56KBIT; + isdnhdlc_rcv_init(&in->hdlc_state, features); + } st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); st5481_usb_device_ctrl_msg(in->adapter, in->counter, in->packet_size, diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index b80e55ab891..df345ce73f4 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -2,6 +2,7 @@ * isdnhdlc.c -- General purpose ISDN HDLC decoder. * * Copyright (C) + * 2009 Karsten Keil * 2002 Wolfgang Mües * 2001 Frode Isaksen * 2001 Kai Germaschewski @@ -25,6 +26,7 @@ #include #include #include +#include /*-------------------------------------------------------------------*/ @@ -48,35 +50,21 @@ enum { HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED }; -void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56) +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) { - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); hdlc->state = HDLC_GET_DATA; - hdlc->do_adapt56 = do_adapt56; - hdlc->dchannel = 0; - hdlc->crc = 0; - hdlc->cbin = 0; - hdlc->shift_reg = 0; - hdlc->ffvalue = 0; - hdlc->dstpos = 0; + if (features & HDLC_56KBIT) + hdlc->do_adapt56 = 1; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; } EXPORT_SYMBOL(isdnhdlc_out_init); -void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, - int do_adapt56) +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) { - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->do_closing = 0; - hdlc->ffvalue = 0; - if (is_d_channel) { + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); + if (features & HDLC_DCHANNEL) { hdlc->dchannel = 1; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { @@ -85,16 +73,13 @@ void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, hdlc->ffvalue = 0x7e; } hdlc->cbin = 0x7e; - hdlc->bit_shift = 0; - if (do_adapt56) { + if (features & HDLC_56KBIT) { hdlc->do_adapt56 = 1; - hdlc->data_bits = 0; hdlc->state = HDLC_SENDFLAG_B0; - } else { - hdlc->do_adapt56 = 0; + } else hdlc->data_bits = 8; - } - hdlc->shift_reg = 0; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; } EXPORT_SYMBOL(isdnhdlc_rcv_init); @@ -188,7 +173,11 @@ int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, while (slen > 0) { if (hdlc->bit_shift == 0) { - hdlc->cbin = *src++; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + hdlc->cbin = bitrev8(*src++); + else + hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; if (hdlc->do_adapt56) @@ -405,12 +394,15 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, case STOPPED: while (dsize--) *dst++ = 0xff; - return dsize; case HDLC_SEND_FAST_FLAG: hdlc->do_closing = 0; if (slen == 0) { - *dst++ = hdlc->ffvalue; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->ffvalue); + else + *dst++ = hdlc->ffvalue; len++; dsize--; break; @@ -594,7 +586,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, hdlc->cbin = 0x7e; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { - *dst++ = hdlc->cbin; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; hdlc->bit_shift = 0; hdlc->data_bits = 0; len++; @@ -612,7 +608,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, } } if (hdlc->data_bits == 8) { - *dst++ = hdlc->cbin; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; hdlc->data_bits = 0; len++; dsize--; diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h index 8f3540c7f69..4b3ecc40889 100644 --- a/include/linux/isdn/hdlc.h +++ b/include/linux/isdn/hdlc.h @@ -6,6 +6,7 @@ * controllers. * * Copyright (C) + * 2009 Karsten Keil * 2002 Wolfgang Mües * 2001 Frode Isaksen * 2001 Kai Germaschewski @@ -50,8 +51,14 @@ struct isdnhdlc_vars { u32 do_adapt56:1; /* set if in closing phase (need to send CRC + flag) */ u32 do_closing:1; + /* set if data is bitreverse */ + u32 do_bitreverse:1; }; +/* Feature Flags */ +#define HDLC_56KBIT 0x01 +#define HDLC_DCHANNEL 0x02 +#define HDLC_BITREVERSE 0x04 /* The return value from isdnhdlc_decode is @@ -62,13 +69,12 @@ struct isdnhdlc_vars { #define HDLC_CRC_ERROR 2 #define HDLC_LENGTH_ERROR 3 -extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56); +extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features); extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, int *count, u8 *dst, int dsize); -extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, - int do_adapt56); +extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features); extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, int *count, u8 *dst, int dsize); -- cgit v1.2.3-70-g09d2 From f3fad223ed69f406f33c9619c256858d5a5fc5c7 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 20:58:33 +0200 Subject: ISDN: Fix isdnhdlc for one byte hdlc packets Normally HDLC packets contain more as one byte (e.g a X25/X75 header). But if you use plain HDLC framing, the current code do not encode 1 byte payloads, this patch fix that. Signed-off-by: Karsten Keil --- drivers/isdn/i4l/isdnhdlc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/isdn/i4l/isdnhdlc.c') diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index df345ce73f4..c989aa35dc2 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -47,7 +47,7 @@ enum { 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, - HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE }; void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) @@ -362,6 +362,9 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, *count = slen; + /* special handling for one byte frames */ + if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) + hdlc->state = HDLC_SENDFLAG_ONE; while (dsize > 0) { if (hdlc->bit_shift == 0) { if (slen && !hdlc->do_closing) { @@ -407,6 +410,8 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, dsize--; break; } + /* fall through */ + case HDLC_SENDFLAG_ONE: if (hdlc->bit_shift == 8) { hdlc->cbin = hdlc->ffvalue >> (8 - hdlc->data_bits); -- cgit v1.2.3-70-g09d2