/*
 * USB CDC NCM auxiliary definitions
 */

#ifndef __LINUX_USB_NCM_H
#define __LINUX_USB_NCM_H

#include <linux/types.h>
#include <linux/usb/cdc.h>
#include <asm/unaligned.h>

#define NCM_NTB_MIN_IN_SIZE		2048
#define NCM_NTB_MIN_OUT_SIZE		2048

#define NCM_CONTROL_TIMEOUT		(5 * 1000)

/* bmNetworkCapabilities */

#define NCM_NCAP_ETH_FILTER	(1 << 0)
#define NCM_NCAP_NET_ADDRESS	(1 << 1)
#define NCM_NCAP_ENCAP_COMM	(1 << 2)
#define NCM_NCAP_MAX_DGRAM	(1 << 3)
#define NCM_NCAP_CRC_MODE	(1 << 4)

/*
 * Here are options for NCM Datagram Pointer table (NDP) parser.
 * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
 * in NDP16 offsets and sizes fields are 1 16bit word wide,
 * in NDP32 -- 2 16bit words wide. Also signatures are different.
 * To make the parser code the same, put the differences in the structure,
 * and switch pointers to the structures when the format is changed.
 */

struct ndp_parser_opts {
	u32		nth_sign;
	u32		ndp_sign;
	unsigned	nth_size;
	unsigned	ndp_size;
	unsigned	ndplen_align;
	/* sizes in u16 units */
	unsigned	dgram_item_len; /* index or length */
	unsigned	block_length;
	unsigned	fp_index;
	unsigned	reserved1;
	unsigned	reserved2;
	unsigned	next_fp_index;
};

#define INIT_NDP16_OPTS {					\
		.nth_sign = NCM_NTH16_SIGN,			\
		.ndp_sign = NCM_NDP16_NOCRC_SIGN,		\
		.nth_size = sizeof(struct usb_cdc_ncm_nth16),	\
		.ndp_size = sizeof(struct usb_cdc_ncm_ndp16),	\
		.ndplen_align = 4,				\
		.dgram_item_len = 1,				\
		.block_length = 1,				\
		.fp_index = 1,					\
		.reserved1 = 0,					\
		.reserved2 = 0,					\
		.next_fp_index = 1,				\
	}


#define INIT_NDP32_OPTS {					\
		.nth_sign = NCM_NTH32_SIGN,			\
		.ndp_sign = NCM_NDP32_NOCRC_SIGN,		\
		.nth_size = sizeof(struct usb_cdc_ncm_nth32),	\
		.ndp_size = sizeof(struct usb_cdc_ncm_ndp32),	\
		.ndplen_align = 8,				\
		.dgram_item_len = 2,				\
		.block_length = 2,				\
		.fp_index = 2,					\
		.reserved1 = 1,					\
		.reserved2 = 2,					\
		.next_fp_index = 2,				\
	}

static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
{
	switch (size) {
	case 1:
		put_unaligned_le16((u16)val, *p);
		break;
	case 2:
		put_unaligned_le32((u32)val, *p);

		break;
	default:
		BUG();
	}

	*p += size;
}

static inline unsigned get_ncm(__le16 **p, unsigned size)
{
	unsigned tmp;

	switch (size) {
	case 1:
		tmp = get_unaligned_le16(*p);
		break;
	case 2:
		tmp = get_unaligned_le32(*p);
		break;
	default:
		BUG();
	}

	*p += size;
	return tmp;
}

#endif /* __LINUX_USB_NCM_H */
