blob: fae8df7ae1365207b3008aac4cceb212931e10f6 [file] [log] [blame] [edit]
/* $Id: tpam_crcpc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
*
* Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding)
*
* Copyright 1998-2000 AUVERTECH Télécom
* Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For all support questions please contact: <support@auvertech.fr>
*
*/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Module Name:
crcpc.c
Abstract:
Modem HDLC coding
Software HDLC coding / decoding
Revision History:
---------------------------------------------------------------------------*/
#include <linux/crc-ccitt.h>
#include "tpam.h"
#define HDLC_CTRL_CHAR_CMPL_MASK 0x20 /* HDLC control character complement mask */
#define HDLC_FLAG 0x7E /* HDLC flag */
#define HDLC_CTRL_ESC 0x7D /* HDLC control escapr character */
#define HDLC_LIKE_FCS_INIT_VAL 0xFFFF /* FCS initial value (0xFFFF for new equipment or 0) */
#define HDLC_FCS_OK 0xF0B8 /* This value is the only valid value of FCS */
#define TRUE 1
#define FALSE 0
static u8 ap_t_ctrl_char_complemented[256]; /* list of characters to complement */
static void ap_hdlc_like_ctrl_char_list (u32 ctrl_char) {
int i;
for (i = 0; i < 256; ++i)
ap_t_ctrl_char_complemented[i] = FALSE;
for (i = 0; i < 32; ++i)
if ((ctrl_char >> i) & 0x0001)
ap_t_ctrl_char_complemented [i] = TRUE;
ap_t_ctrl_char_complemented[HDLC_FLAG] = TRUE;
ap_t_ctrl_char_complemented[HDLC_CTRL_ESC] = TRUE;
}
void init_CRC(void) {
ap_hdlc_like_ctrl_char_list(0xffffffff);
}
void hdlc_encode_modem(u8 *buffer_in, u32 lng_in,
u8 *buffer_out, u32 *lng_out) {
u16 fcs;
register u8 data;
register u8 *p_data_out = buffer_out;
fcs = HDLC_LIKE_FCS_INIT_VAL;
/*
* Insert HDLC flag at the beginning of the frame
*/
*p_data_out++ = HDLC_FLAG;
#define ESCAPE_CHAR(data_out, data) \
if (ap_t_ctrl_char_complemented[data]) { \
*data_out++ = HDLC_CTRL_ESC; \
*data_out++ = data ^ 0x20; \
} \
else \
*data_out++ = data;
while (lng_in--) {
data = *buffer_in++;
/*
* FCS calculation
*/
fcs = crc_ccitt_byte(fcs, data);
ESCAPE_CHAR(p_data_out, data);
}
/*
* Add FCS and closing flag
*/
fcs ^= 0xFFFF; // Complement
data = (u8)(fcs & 0xff); /* LSB */
ESCAPE_CHAR(p_data_out, data);
data = (u8)((fcs >> 8)); /* MSB */
ESCAPE_CHAR(p_data_out, data);
#undef ESCAPE_CHAR
*p_data_out++ = HDLC_FLAG;
*lng_out = (u32)(p_data_out - buffer_out);
}
void hdlc_no_accm_encode(u8 *buffer_in, u32 lng_in,
u8 *buffer_out, u32 *lng_out) {
u16 fcs;
register u8 data;
register u8 *p_data_out = buffer_out;
/*
* Insert HDLC flag at the beginning of the frame
*/
fcs = HDLC_LIKE_FCS_INIT_VAL;
while (lng_in--) {
data = *buffer_in++;
/* calculate FCS */
fcs = crc_ccitt_byte(fcs, data);
*p_data_out++ = data;
}
/*
* Add FCS and closing flag
*/
fcs ^= 0xFFFF; // Complement
data = (u8)(fcs);
*p_data_out++ = data;
data =(u8)((fcs >> 8)); // revense MSB / LSB
*p_data_out++ = data;
*lng_out = (u32)(p_data_out - buffer_out);
}
u32 hdlc_no_accm_decode(u8 *buffer_in, u32 lng_in) {
u16 fcs;
u32 lng = lng_in;
register u8 data;
/*
* Insert HDLC flag at the beginning of the frame
*/
fcs = HDLC_LIKE_FCS_INIT_VAL;
while (lng_in--) {
data = *buffer_in++;
/* calculate FCS */
fcs = crc_ccitt_byte(fcs, data);
}
if (fcs == HDLC_FCS_OK)
return (lng-2);
else
return 0;
}