Merge tag 'isdn-removal' of https://git.kernel.org/pub/scm/linux/kernel/git/arnd...
authorDavid S. Miller <davem@davemloft.net>
Mon, 3 Jun 2019 00:48:58 +0000 (17:48 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Jun 2019 00:48:58 +0000 (17:48 -0700)
Arnd Bergmann says:

====================
isdn: deprecate non-mISDN drivers

When isdn4linux came up in the context of another patch series, I
remembered that we had discussed removing it a while ago.

It turns out that the suggestion from Karsten Keil wa to remove I4L
in 2018 after the last public ISDN networks are shut down. This has
happened now (with a very small number of exceptions), so I guess it's
time to try again.

We currently have three ISDN stacks in the kernel: the original
isdn4linux (with the hisax driver), the newer CAPI (with four drivers),
and finally the mISDN stack (supporting roughly the same hardware as
hisax).

As far as I can tell, anyone using ISDN with mainline kernel drivers in
the past few years uses mISDN, and this is typically used for voice-only
PBX installations that don't require a public network.

The older stacks support additional features for data networks, but those
typically make no sense any more if there is no network to connect to.

My proposal for this time is to kill off isdn4linux entirely, as it seems
to have been unusable for quite a while. This code has been abandoned
for many years and it does cause problems for treewide maintenance as
it tends to do everything that we try to stop doing.
Birger Harzenetter mentioned that is is still using i4l in order to
make use of the 'divert' feature that is not part of mISDN, but has
otherwise moved on to mISDN for normal operation, like apparently
everyone else.

CAPI in turn is not quite as obsolete, but two of the drivers (avm
and hysdn) don't seem to be used at all, while another one (gigaset)
will stop being maintained as Paul Bolle is no longer able to
test it after the network gets shut down in September.
All three are now moved into drivers/staging to let others speak
up in case there are remaining users.
This leaves Bluetooth CMTP as the only remaining user of CAPI, but
Marcel Holtmann wishes to keep maintaining it.

For the discussion on version 1, see [2]
Unfortunately, Karsten Keil as the maintainer has not participated in
the discussion.

      Arnd

[1] https://patchwork.kernel.org/patch/8484861/#17900371
[2] https://listserv.isdn4linux.de/pipermail/isdn4linux/2019-April/thread.html
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
MAINTAINERS
drivers/isdn/hardware/mISDN/isdnhdlc.c
drivers/isdn/hardware/mISDN/isdnhdlc.h

diff --cc MAINTAINERS
Simple merge
index 0000000,3a8b562..9fea16e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,630 +1,617 @@@
 - *
 - * 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.
++// SPDX-License-Identifier: GPL-2.0-or-later
+ /*
+  * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
+  *
+  * Copyright (C)
+  *    2009    Karsten Keil            <keil@b1-systems.de>
+  *    2002    Wolfgang Mües          <wolfgang@iksw-muees.de>
+  *    2001    Frode Isaksen           <fisaksen@bewan.com>
+  *      2001  Kai Germaschewski       <kai.germaschewski@gmx.de>
+  */
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/crc-ccitt.h>
+ #include <linux/bitrev.h>
+ #include "isdnhdlc.h"
+ /*-------------------------------------------------------------------*/
+ MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
+             "Frode Isaksen <fisaksen@bewan.com>, "
+             "Kai Germaschewski <kai.germaschewski@gmx.de>");
+ 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, HDLC_SENDFLAG_ONE
+ };
+ void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
+ {
+       memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
+       hdlc->state = HDLC_GET_DATA;
+       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, u32 features)
+ {
+       memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
+       if (features & HDLC_DCHANNEL) {
+               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;
+       if (features & HDLC_56KBIT) {
+               hdlc->do_adapt56 = 1;
+               hdlc->state = HDLC_SENDFLAG_B0;
+       } else
+               hdlc->data_bits = 8;
+       if (features & HDLC_BITREVERSE)
+               hdlc->do_bitreverse = 1;
+ }
+ 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.
+   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 u8 *src, int slen,
+                   int *count, u8 *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
+       };
+ #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) {
+                       /* 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)
+                               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) &&
+                                   (++hdlc->hdlc_bits1 >= 8) &&
+                                   (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)
+                                               status = check_frame(hdlc);
+                                       hdlc->crc = 0xffff;
+                                       hdlc->shift_reg = 0;
+                                       hdlc->data_bits = 0;
+                                       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->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
+                                       handle_abort(hdlc);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       *count -= slen;
+       return 0;
+ }
+ EXPORT_SYMBOL(isdnhdlc_decode);
+ /*
+   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 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
+       };
+       int len = 0;
+       *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) {
+                               hdlc->shift_reg = *src++;
+                               slen--;
+                               if (slen == 0)
+                                       /* closing sequence, CRC + flag(s) */
+                                       hdlc->do_closing = 1;
+                               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) {
+                               /* the code is for bitreverse streams */
+                               if (hdlc->do_bitreverse == 0)
+                                       *dst++ = bitrev8(hdlc->ffvalue);
+                               else
+                                       *dst++ = hdlc->ffvalue;
+                               len++;
+                               dsize--;
+                               break;
+                       }
+                       /* fall through */
+               case HDLC_SENDFLAG_ONE:
+                       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 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 {
+                               /* 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++;
+                               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) {
+                       /* 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--;
+               }
+       }
+       *count -= slen;
+       return len;
+ }
+ EXPORT_SYMBOL(isdnhdlc_encode);
index 0000000,9652137..fe2c127
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,82 +1,69 @@@
 - *
 - * 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.
++/* SPDX-License-Identifier: GPL-2.0-or-later */
+ /*
+  * hdlc.h  --  General purpose ISDN HDLC decoder.
+  *
+  * Implementation of a HDLC decoder/encoder in software.
+  * Necessary because some ISDN devices don't have HDLC
+  * controllers.
+  *
+  * Copyright (C)
+  *    2009    Karsten Keil            <keil@b1-systems.de>
+  *    2002    Wolfgang Mües          <wolfgang@iksw-muees.de>
+  *    2001    Frode Isaksen           <fisaksen@bewan.com>
+  *    2001    Kai Germaschewski       <kai.germaschewski@gmx.de>
+  */
+ #ifndef __ISDNHDLC_H__
+ #define __ISDNHDLC_H__
+ struct isdnhdlc_vars {
+       int bit_shift;
+       int hdlc_bits1;
+       int data_bits;
+       int ffbit_shift;        /* encoding only */
+       int state;
+       int dstpos;
+       u16 crc;
+       u8 cbin;
+       u8 shift_reg;
+       u8 ffvalue;
+       /* 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;
+       /* 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
+   the frame length, 0 if no complete frame was decoded,
+   or a negative error number
+ */
+ #define HDLC_FRAMING_ERROR     1
+ #define HDLC_CRC_ERROR         2
+ #define HDLC_LENGTH_ERROR      3
+ 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, u32 features);
+ extern int    isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src,
+                       u16 slen, int *count, u8 *dst, int dsize);
+ #endif /* __ISDNHDLC_H__ */