/*
  Copyright 2004, 2005, 2006 Jean-Baptiste Note

  This file is part of prism54usb.

  prism54usb 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.

  prism54usb 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 prism54usb; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef _HAVE_PROTOCOL_H
#define _HAVE_PROTOCOL_H

#ifdef __linux__
#include <linux/types.h>
#include <linux/if_ether.h>
#endif				/* __linux__ */

#include "islsm_pda.h"

/**** protocol parameters ****/
/* hardware versions */
enum islsm_versions {
	ISLSM_DEVICE_USB_VER1 = 0,
	ISLSM_DEVICE_USB_VER2,
	ISLSM_DEVICE_PCI_VER1,
	ISLSM_DEVICE_SPI_VER1,
};

/* firmware versions */
enum islsm_fw_type {
	ISLSM_FW_LM86 = 0,
	ISLSM_FW_LM87,
	ISLSM_FW_LM20,
	ISLSM_FW_FMAC,
};

#define ISLSM_TX_TIMEOUT		(HZ/10)
#define ISLSM_ACK_TIMEOUT               (HZ*512/1000)

#define ISLSM_ACK_TIMER         0x1

/* softmac management for isl 802.11g devices. For now this softmac
 * relies on the madwifi stack. Plan is to port is to the hostap API.
 * If you would like to do this, please contact me */

/* Control frames are at maximum 0x400 + header space */
#define ISLSM_MAX_FRAME_SIZE	2048
#define ISLSM_MAX_CONTROL       0x400
/* we need 3 bytes more for alignment purposes */
#define ISLSM_ALIGN_SPACE       3
#define ISLSM_RXSPACE           0x3500

/*
   The sm_tx_p structure contains the values used to fill the header of
   a 802.11 packet sent to the device.  We maintain for now four sets of
   such parameters for data, mgmt, beacon and probe packets.
*/

struct sm_tx_p {
	/* flag : are we expecting an ack ? */
	int                     ack_timer;
	/* type of packet */
	uint32_t                id_magic1;
	/* value filled in the first byte of a tx data packet */
	/* maybe this one is only the rts/cts rate */
	uint16_t                req_type;
	u8                      retry1;
	u8                      retry2;
//	uint16_t                flags;
	uint8_t                 rateset[8];
	/* value filled in the rateset parameter */
	uint32_t                magic4;
	uint32_t                magic5;
	/* value filled in the type parameter */
	uint8_t                 frame_type;
};

/*
   The sm_filter_p structure contains the values used to fill the rx_tx
   filter sent to the device.  We maintain for now three sets of such
   parameters for different states of the 802.11 stack: assoc, scan,
   master.
*/

struct sm_filter_p {
	/* these are expected to be timeouts, but no idea really */
	uint16_t                rxtx_timeout1;
	uint16_t                rxtx_timeout2;
};

/*
   The sm_p structure summarizes all unknown or half-guessed values used
   in the driver for all kinds of packets.
 */

struct sm_p {
	/*** rx/tx filter parameters ***/
	/* some rx/tx filter value common to all packets */
	uint16_t                rxhw;
	struct sm_filter_p      assoc;
	struct sm_filter_p      scan;
	struct sm_filter_p      master;

	/*** data tx packets parameters ***/
	struct sm_tx_p          data;
	struct sm_tx_p          mgmt;
	struct sm_tx_p          beacon;
	struct sm_tx_p          probe;
};

/* These should be read from the mgmt frame
   I don't really know where they are located...
*/
#define ISLSM_NR_CHANNELS 14
#define ISLSM_NR_RATES 12	/* from what i can read in the packets */

/* rate information */
/* this rate table is actually present in the firmware header.
   Learn how to exctract it precisely */
#define ISLSM_TX_CTSONLY  0x20	/* set this flag and the device will CTS */
#define ISLSM_TX_RTSCTS   0x10	/* set this flag and the device will RTS */

#define ISLSM_TX_UNK1 0x10	/* i don't know what this means actually */

static uint8_t          islsm_rate_table[12]  __attribute__ ((unused)) =
{ 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c };

/* this seems to be present
   in all kinds of frames
   received on data and mgmt pipes */
struct islsm_rx {
	uint16_t                length;
	uint8_t                 padding[14];
	char                    data[];
} __attribute__ ((packed));

#define SIZE_RX sizeof(struct islsm_rx)

/* the tx'd packets start with a destination on 32 bits, we'll call that
   their "queue" hereafter */
struct islsm_tx {
	uint32_t                arm_addr;
/* until i sort out what this means... */
/* #define ISLSM_TX_QUEUE_CONFIG     0x00020200 */
/* #define ISLSM_TX_QUEUE_ZERO       0x0002006c */
/* #define ISLSM_TX_QUEUE_ZERO_VER2  0x00020070 */

//#define ISLSM_TX_CONTROL_FILTER_MAGIC6_VER1 0x02480c
//#define ISLSM_TX_CONTROL_FILTER_MAGIC6_VER2 0x024214
//#define ISLSM_TX_CONTROL_FILTER_MAGIC6_PCI  0x024790

/*
The variable part is at the same location in v2 devices
0x00020670
0x00020770
*/
	uint16_t                length;
#define ISLSM_MGMT_FOLLOWUP    0x2
	uint16_t                follower;
	uint8_t                 padding[8];
} __attribute__ ((packed));

#define SIZE_NET2280_H sizeof(struct islsm_tx)

/* newer header, seen in DELL 1450 a/b/g usb dongle -- for lm87
 * firmwares.
 *
 * The hardware encapsulation also has changes for the 3887
 * with these newer firmwares -- the address is put right into the
 * packet, instead of having one packet for itself.
 *
 * All of this is to be checked for PCI and USB + net2280
 */
typedef struct islsm_lm87_hdr {
	/* the following checksum seems computed on the data payload,
	   including any padding that may have been added (ie, raw
	   packet size minus 4 bytes, not the size present in the
	   following fields) */
	u32      checksum;
	char     data[];
} islsm_lm87_hdr_t;

/* custom Intersil CRC routine, used for all packets in very recent
   firmwares (still have to sort out how to distinguish them from the
   ones evoked below). Probably standard CRC32. Yes, connexant has
   better things to do than to make reverse-engeneering difficult. */
static inline u32
islsm_crc(const u32 *data, size_t length) {
	size_t i;
	u32 crc = 0;
	for(i = 0; i < length; i+=4) {
		crc ^= *data++;
		crc = (crc >> 5) ^ (crc << 3);
	}
	return crc;
}

/*
 * This version of the checksum is used for instance in the 2.6.X.X,
 * lm86 series, where it is used to checksum only the data packets.
 * Unfortunately I can't seem to be able to put my hands on such a
 * firmware image...
 */
static inline u32
islsm_crc_data(const u8 *data, size_t length) {
	size_t i;
	u32 crc = 0;
	for(i = 0; i < length; i+=4) {
		crc ^= *data++;
		crc = (crc >> 5) ^ (crc << 3);
	}
	return crc;
}

/*
 * structure accounting for the different queues a prio queue would
 * probably be better. Must be able to link between queue and packet, so
 * that a tx timeout can reclaim a tx'd packet asynchronously (does the
 * 802.11 stack allow this ?)
 */
#define ISLSM_TX_QUEUE_MASK       0xF
#define ISLSM_TX_QUEUE_TX(x) (((x & ISLSM_TX_QUEUE_MASK) << 8) | islsm->smpar.datatx_reg)
#define ISLSM_TX_QUEUE_ID(x) (((x) >> 8) & ISLSM_TX_QUEUE_MASK)
/* this is observed maximum, i really don't know */
#define ISLSM_NR_TX_QUEUES 4

/* pimfor from the main driver. */
/* Guess what : same size, 12 bytes */
/*
typedef struct {
	uint8_t  version;
	uint8_t  operation;
	uint32_t oid;
	uint8_t  device_id;
	uint8_t  flags;
	uint32_t length;
} __attribute__ ((packed))
pimfor_header_t;
*/

/* the length should be the length of data *after* the header we're in */
struct islsm_id {
/* actually 2*uint8_t, channel + flags */
	uint16_t                magic1;
/* TX magic numbers */
#define ISLSM_TX_MGMT_ID   0x0000
#define ISLSM_TX_BEACON_ID 0x0002
/* TODO: reorganize all this mess */
/* sometimes data packets begin like this */
#define ISLSM_TX_DATA_ID   0x0010
#define ISLSM_TX_PAD_FLAG  0x4000

/* Actually i think all bits in the first byte are meaningless and are
 * copied indiscriminately in the response packet. But looking at data
 * transactions, i'm not so confident... */
#define ISLSM_IC_FLAG_FREE              0x01
#define ISLSM_IC_TYPE_CTRL              0x80

#define ISLSM_ID_CONTROL                0x8000
#define ISLSM_ID_CTRL_FLAG_READ         0x0001

#define ISLSM_TX_CONTROL_NORESPONSE_ID  0x8001
#define ISLSM_ID_EEPROM_READBACK        0x8000
#define ISLSM_ID_FAULT                  0x4d00

#define ISLSM_MGMT_FRAME              (1<<15)
#define ISLSM_DATA_FRAME              (1<<14)
/*
 * Set this bit if you don't want any response on the mgmt pipe. Usually
 * this is OK for settings only echoing their result (rx/tx filter
 * packets, frequency change packets
 */
/* get = 0 / set = 1
   must try get with zeroed buffer (i didn't try this !) !!!  */
#define ISLSM_ID_NO_MGMT_RESPONSE     (1 << 0)
/* this flag is an unknown quantity for me.
   seems usefull only for sending data  */
#define ISLSM_ID_UNKNOWN              (1 << 4)

/* The following magic numbers are coming along with data packets.
   We need to understand better what they mean so we get rid of this
   list */

#define ISLSM_ID_FCS_OK   (1 << 0)
#define ISLSM_ID_MASK     (0xff00)
#define ISLSM_ID_MGMT_PKT               0x0100
#define ISLSM_ID_DATA_PKT               0x0000

/* provide an example capture */
/* seen in non-monitor mode : 0x4c,0x54,0x5c,0x52 */
/* seen in real monitor mode : 0xb0,0xa0,0x84,0x80,0x70,
   0x74,0x60,0x64,0x4c,0x48,0x44,0x40,0x04,0x00 */
#define ISLSM_DATA_PKT_ACK  (1<<7)
	uint16_t                length;
} __attribute__ ((packed));

/* this is from the main driver. Guess what. 20 bytes. */
struct rfmon_header {
	uint16_t                unk0;	/* = 0x0000 */
	uint16_t                length;	/* = 0x1400 */
	uint32_t                clock;	/* 1MHz clock */
	uint8_t                 flags;
	uint8_t                 unk1;
	uint8_t                 rate;
	uint8_t                 unk2;
	uint16_t                freq;
	uint16_t                unk3;
	uint8_t                 rssi;
	uint8_t                 padding[3];
} __attribute__ ((packed));

/* prism2 rx header. We can get some inspiration from the RX_STATUS.
   at least the FCS bit is located in the same place */
struct hfa384x_rx_frame {
	/* HFA384X RX frame descriptor */
	u16 status; /* HFA384X_RX_STATUS_ flags */
	u32 time; /* timestamp, 1 microsecond resolution */
	u8 silence; /* 27 .. 154; seems to be 0 */
	u8 signal; /* 27 .. 154 */
	u8 rate; /* 10, 20, 55, or 110 */
	u8 rxflow;
	u32 reserved;
};

/* packets wrapping a received 802.11 packet */
struct islsm_rx_packet_header {
	/* This first field to be put above */
	struct islsm_id         id;
	uint16_t                freq;	/* frequency, in MHz, le */
	uint8_t                 unknown1;   /* one bit stored @568 */
	uint8_t                 rate;	/* rate, same as specified for rateset on tx  */
	uint8_t                 signal_strength;	/* , in ? Not sure about the meaning of the first byte, really */
	uint8_t                 padding2;
	uint16_t                unknown2;	/* this should not be hard -- noise ? Seems to
						 * be timestamp in master mode */
	uint64_t                timestamp;	/* timestamp, in microsec, le */
} __attribute__ ((packed));

#define SIZE_RX_HEADER sizeof(struct islsm_rx_packet_header)

enum control_frame_types {
	ISLSM_TX_CONTROL_TYPE_FILTER_SET = 0,
	ISLSM_TX_CONTROL_TYPE_CHANNEL_CHANGE,
	ISLSM_TX_CONTROL_TYPE_FREQDONE,
	/* 3, 4, 5, 6 unknown ? */
	ISLSM_TX_CONTROL_TYPE_FREEQUEUE = 7,
	ISLSM_TX_CONTROL_TYPE_TXDONE,
	ISLSM_TX_CONTROL_TYPE_PING,
	ISLSM_TX_CONTROL_TYPE_STAT_READBACK,
	ISLSM_TX_CONTROL_TYPE_BBP,
	ISLSM_TX_CONTROL_TYPE_EEPROM_READBACK,
	ISLSM_TX_CONTROL_TYPE_LED,
};

/* the above islsm_tx and islsm_rx headers often wrap this kind of packets */
struct islsm_tx_control {
	struct islsm_id         id;
	/* req_d precision : The device doesn't like them to be
	 * mangled. Be sure that they are _unique in the device_ ! it's
	 * used internally too, so sending two packets with the same
	 * req_id will confuse the device. Beware ! */
	/* small addition : in the driver, as a control packet is
	 * reserved, most control frames, using the bottom
	 * lmac address have this set to 0 */
	uint32_t                req_id;
	/* actually this is 2 16-bit fields */
	uint16_t                type;
	/* types of data frames -- I still don't know what they mean */
/* This flag is for writes */
#define ISLSM_TX_CONTROL_TYPE_DATANOACK	       0x0
/* This flag is for reads */
#define ISLSM_TX_CONTROL_TYPE_DATAACK	       0x1
/* This flag is for control frames */
#define ISLSM_TX_CONTROL_TYPE_TXVER2           0x8000

/*
  Firmware has an auto-retry mechanism. Each of these bytes is a retry
  counter. When a TX fails (for various reasons, and at various
  points), its tx retry counter is increased and compared to the values
  below (there are two reasons for TX fails, each yielding an increase
  in two different counters). When the retry count exceeds the maximum
  allowed, the packet is dismissed.
  The retry count is used as an offset into the rate table which follows
  (field rateset of struct islsm_tx_control_allocdata below). Thus, the
  retry mechanism allows to lower the rate of the retry, which is
  supposed to be nice (lower rate = greater chance of successful TX).
*/
/*
  FIXME: this should move this to the structure below. Would cut on data
  passed to islsm_make_prism_header_skb, and be more logical. Maybe.
*/
	u8                      retry1;
	u8                      retry2;
#define ISLSM_TX_CONTROL_FLAGS_ACK              0x0707
#define ISLSM_TX_CONTROL_FLAGS_NOACK	       0x0101
	char                    data[];
} __attribute__ ((packed));

#define SIZE_TX_CONTROL sizeof(struct islsm_tx_control)

/*
 * Frequency setting packet
 */

#define ISLSM_POINTS_PER_CURVE 8

struct fw_out_levels {
	uint8_t                 val_barker;
	uint8_t                 val_bpsk;
	uint8_t                 val_qpsk;
	uint8_t                 val_16qam;
	uint8_t                 val_64qam;
} __attribute__ ((packed));

struct fw_cal_data_sample {
	struct wlan_pda_pa_curve_data_sample_rev1_s sample;
	/* zero-padded */
	uint8_t                 padding;
} __attribute__ ((packed));

struct islsm_tx_control_channel {
	/* This is a bitfield */
	uint16_t                magic1;
	/* this is a timing -- maybe CIFS, beacon interval, dwell time ? */
	uint16_t                magic2;
/* Setting when passive-scanning */
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC1_SCAN          0x2
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC2_SCAN          0x78
// OR with default scan values when reaching channel 14
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC1_SCAN_WRAP     0x8

/* Setting when active-scanning.
 * Such a frequency change packet triggers
 * the emission of the packet in slot ISLSM_FRAME_PROBE
 */
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC1_EMIT_TXSLOT    0x6
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC2_EMIT_TXSLOT    0x28

/* TX mode. When in this mode, subsequent TX packets with mode
 * ISLSM_FRAME_DATA, ISLSM_FRAME_MGMT, ISLSM_FRAME_BEACON are directly
 * emitted. A correct tx/rx filter is needed for BEACON type.
 */
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC1_TX            0x1
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC2_TX              0

/* This mode is used in ad-hoc mode, when you want to emit a packet
 * (null data in dabe's log) while still scanning. Is this possible ?
 * See for instance Dabe's log.
 */
#define ISLSM_TX_CONTROL_CHANNEL_MAGIC1_SET2          0x3
	uint8_t                 padding1[20];
	/* These are the IQ autocalibration parameters, whatever
	   this means */
	struct wlan_pda_iq_autocal_s freq;
	/* number of points on the PA calibration curves */
	uint8_t                 pa_points_per_curve;
	/* PA levels for the various modulations */
	struct fw_out_levels    output_pwr_levels;
	/* The curve data, for interpolation to the above PA level */
	/* FIXME : move to dynamic number of elements */
	struct fw_cal_data_sample curve_data[ISLSM_POINTS_PER_CURVE];
	uint32_t                padding;	/* filled with 0 in old firmware, repeat of output_power_limit
						 * from the PDA in newer devices */
} __attribute__ ((packed));

#define SIZE_TX_CONTROL_CHANNEL sizeof(struct islsm_tx_control_channel)
#define FULL_TX_CONTROL_CHANNEL SIZE_TX_CONTROL + SIZE_TX_CONTROL_CHANNEL

struct islsm_tx_control_channel_ver2 {
	struct islsm_tx_control_channel basic_packet;
	uint32_t                padding;
} __attribute__ ((packed));

#define SIZE_TX_CONTROL_CHANNEL_VER2 sizeof(struct islsm_tx_control_channel_ver2)
#define FULL_TX_CONTROL_CHANNEL_VER2 SIZE_TX_CONTROL + SIZE_TX_CONTROL_CHANNEL_VER2

/*
 * packet which sets the rx/tx filter
 */
struct islsm_tx_control_filter {
	/* This is a bitfield rather than a unique filter type. We
	   should understand in the firmware what is the effect of each
	   one of these */
	uint16_t                filter_type;
#define ISLSM_TX_CONTROL_FILTER_NOTYPE    0
#define ISLSM_TX_CONTROL_FILTER_STA       (1<<0)
#define ISLSM_TX_CONTROL_FILTER_ADHOC     (1<<1)
#define ISLSM_TX_CONTROL_FILTER_HOSTAP    (1<<2)
/* Actually 1 << 4 and 1 << 3 should be equivalent. To check. */
#define ISLSM_TX_CONTROL_FILTER_MONITOR   (1<<4)
#define ISLSM_TX_CONTROL_FILTER_RESET     (1<<5)
	uint8_t                 destination[ETH_ALEN];
	uint8_t                 source[ETH_ALEN];
	/* this byte configure the antenna. I'm not sure about the
	   meaning of the second bit, but it allows toggling the antenna
	   diversity at some point in the firmware code. */
#define ISLSM_ANTENNA_DIVERSITY           (1<<0)
#define ISLSM_ANTENNA_VARIATION           (1<<1)
	uint8_t                 antenna;
	/* this byte has no effect on the 2.4.X.X firmware, and is used
	   at some points as an increment for 2.5.X.X firmwares. The
	   firmware (MANU abort) if this is set above 3. */
	uint8_t                 debug;
#define ISLSM_TX_CONTROL_FILTER_MAGIC2_FORM1 ISLSM_ANTENNA_VARIATION
//#define ISLSM_TX_CONTROL_FILTER_MAGIC2_FORM2 (ISLSM_ANTENNA_VARIATION
//| ISLSM_ANTENNA_DIVERSITY)
#define ISLSM_TX_CONTROL_FILTER_MAGIC2_FORM2 ISLSM_ANTENNA_VARIATION
#define ISLSM_TX_CONTROL_FILTER_MAGIC2_FORM3 0
#define ISLSM_TX_CONTROL_FILTER_MAGIC2_STA   ISLSM_ANTENNA_VARIATION
#define ISLSM_TX_CONTROL_FILTER_MAGIC2_MONITOR 0x0000
	/* still to be understood. This field is or'd to 0x150, and used
	   as a size for a memset(0). Still no clue as to the real
	   meaning. */
	uint32_t                magic3;
#define ISLSM_TX_CONTROL_FILTER_MAGIC3_FORM1   0
#define ISLSM_TX_CONTROL_FILTER_MAGIC3_STA     0x15f
#define ISLSM_TX_CONTROL_FILTER_MAGIC3_MONITOR 0x0
	/* array of rates. Only problem, I don't know what rate they
	   control. Certainly rx rates ? */
	uint8_t                 rates[8];
	/* leave about 0x3500 bytes from the top of the
	   device's frame space */
	uint32_t                rx_addr;
	/* this is maximal (raw 802.11) rx packet size. Frames longer
	 * than this are discarded by the firmware, and a counter in the
	   stats increased accordingly */
	uint16_t                mru;
#define ISLSM_TX_CONTROL_FILTER_MAGIC7_VER1 0x0610
#define ISLSM_TX_CONTROL_FILTER_MAGIC7_VER2 0x0620
#define ISLSM_TX_CONTROL_FILTER_MAGIC7_PCI  0x0620
	/* Those two fields are still to be understood. There are
	   certain hints in the firmware though. Somebody should take
	   on this */
	/* This field is used in a table as an index. The table is
	 * located at 0xA0000800 in the 2.4.3.4 firmware. Index 4 in
	 * table is really fun. Maybe what's needed for Pete ? */
	uint16_t                rxhw;
	/* again see in firmware */
	uint16_t                magic8;
#define ISLSM_TX_CONTROL_FILTER_MAGIC8_STA   0x1f4
	uint16_t                magic9;
/* this is a time i think. Find out what it controls */
#define ISLSM_TX_CONTROL_FILTER_MAGIC9_FORM1 0xf642
#define ISLSM_TX_CONTROL_FILTER_MAGIC9_PCI   0xf642
	/* pfui ! */
} __attribute__ ((packed));

#define SIZE_TX_CONTROL_FILTER sizeof(struct islsm_tx_control_filter)
#define FULL_TX_CONTROL_FILTER SIZE_TX_CONTROL + SIZE_TX_CONTROL_FILTER

/*
 * packet which controls the leds
 */
struct islsm_tx_control_led {
/* The workings of the mode is not really clear. Basically,
   a value of 1 will set the activity led to blink on packet rx,
   all other values will go out of this mode */
	uint16_t                mode;
#define LED_MODE_SET       2
#define LED_MODE_RXBLINK   1
#define LED_MODE_OFF       0

/* the leds will be under control of led_setting_temporary
   for temporary_setting_duration time, in msec, then they
   are set according to led_setting_permanent.
   This is for both leds.
   For instance, if you want the activity led to blink while the
   power led is still on, be sure to set it to LED_ACTIVITY | LED_POWER
   otherwise the power led will be off during the blink */
	uint16_t                led_setting_temporary;
	uint16_t                led_setting_permanent;
#define LED_NONE     0
#define LED_POWER    1
#define LED_ACTIVITY 2

	/* duration of the temporary settings, in ms */
	uint16_t                temporary_setting_duration;
} __attribute__ ((packed));

#define SIZE_TX_CONTROL_LED sizeof(struct islsm_tx_control_led)
#define FULL_TX_CONTROL_LED SIZE_TX_CONTROL + SIZE_TX_CONTROL_LED

/*
 * packet which is sent to free a
 * queue where a frame has been alloc'd
 */

struct islsm_tx_control_freequeue {
	uint32_t                queue;
} __attribute__ ((packed));

#define SIZE_TX_CONTROL_FREEQUEUE sizeof(struct islsm_tx_control_freequeue)
#define FULL_TX_CONTROL_FREEQUEUE SIZE_TX_CONTROL + SIZE_TX_CONTROL_FREEQUEUE

/*
 * Data sending packet
 */

struct islsm_wepkey {
	uint8_t                 key_present;
#define ISLSM_WEPKEY_PRESENT 0x1
	uint8_t                 key_length;
	uint8_t                 key[16];
} __attribute__ ((packed));

struct islsm_tx_control_allocdata {
	/* index [0-c] into the ratetable ORd with a
	   bitmask 40 / 20 / 10, still to be understood */
	uint8_t                 rateset[8];
	/* maybe offload type */
	uint16_t                padding;
	struct islsm_wepkey     wepkey;
	uint32_t                frame_type;
	/* packets are queued in-firmware. This frametype is an
	 * index into the queue array. In short, the queue it ends up
	 * in. Additionally, the queue sets a specific TX callback, so
	 * it does affect the way the packet is sent in an unspecified
	 * way as-of-yet */
#define ISLSM_FRAME_DATA		 0x4
/* frame type that will be emitted at once. difference with above ? */
#define ISLSM_FRAME_MGMT            	 0x2
/* frame type that will be emitted once upon a certain frequency change
   (see code). Queue will be freed by a free queue request or by an
   allocation of a frame of the same type */
#define ISLSM_FRAME_PROBE                0x1
/* frame type that will be emitted at regular intervals upon loading of
   the right rx/tx filter. Queue will be freed by a free queue or by an
   allocation of a frame of the same type. */
#define ISLSM_FRAME_BEACON               0x0
	uint32_t                padding2;
	uint32_t                magic4;
	uint32_t                magic5;
/* 02 7f 23 with 00 40 magic seems okay for id purposes */
/* 02 is for some kind of mode ? */
#define ISLSM_TX_FRAME_MAGIC4_MGMT	0x7f020000	/* 0x7f000000, other
							 * form with 00 40 as
							 * magic, and 0x23
							 * below (dabe's device) */
#define ISLSM_TX_FRAME_MAGIC5_MGMT	0x23	/* 0x33, other form with 10
						 * 40 as magic, and 7f02 above */
#define ISLSM_TX_FRAME_MAGIC4_PROBE	0x0
#define ISLSM_TX_FRAME_MAGIC5_PROBE	0x0
	/* 4 is the max padding seen */
	uint8_t                 frame_align[];
} __attribute__ ((packed));

#define SIZE_TX_CONTROL_ALLOCDATA sizeof(struct islsm_tx_control_allocdata)
#define FULL_TX_CONTROL_ALLOCDATA SIZE_TX_CONTROL + SIZE_TX_CONTROL_ALLOCDATA
#define TX_MAX_PADDING (4 - 1)

#define ISLSM_SIZE_STATS 0x24

/*
 * eeprom readback packet
 */
struct islsm_control_eeprom_lm86 {
	uint16_t                offset;
	uint16_t                len;
	char                    data[];
} __attribute__ ((packed));

/* same, for lm87 */
/* I think the maximum framesize is 0x400 -- this includes
   the frame plus crc for lm87 */
#define ISLSM_EEPROM_SIZE       0x2000
#define SIZE_CONTROL_EEPROM     sizeof(struct islsm_control_eeprom_lm86)

struct islsm_control_eeprom_lm87 {
	u32                     address;
	u16                     len;
	/* always 0xf */
	u16                     unknown;
	/* magic is LOCK */
#define ISLSM_LOCK 0x4c4f434b
	u32                     magic;
	char                    data[];
} __attribute__ ((packed));

union islsm_control_eeprom {
	struct islsm_control_eeprom_lm86 lm86;
	struct islsm_control_eeprom_lm87 lm87;
};

/*
 * Packet for accessing the BBP. Whether it's a read or write depends on
 * the id of the packet.
 */
struct islsm_control_bbp {
	/* actually this is treated as a half */
	u32                     reg;
	u32                     val;
};

#define SIZE_TX_CONTROL_BBP sizeof(struct islsm_control_bbp)
#define FULL_CONTROL_BBP SIZE_TX_CONTROL + SIZE_TX_CONTROL_BBP

/*
 * packet reporting successfull frequency setting
 */
struct islsm_control_freqchange {
	uint16_t                padding;
	uint16_t                frequency;
} __attribute__ ((packed));

/*
 * packet sent when a data packet is freed
 */
struct islsm_control_queueemptied {
	uint16_t                status;
/* i'll have to make sure of this */
#define PKT_STATUS_OK        0x100
#define PKT_STATUS_NOTACKED  0x1
	uint16_t                ack_strength;
	/* the device takes care of the sequence control field
	   in the packet. Here is what it filled it with */
	uint16_t                sequence;
	/* this is, i think another field filled in by the device.
	   duration / ID field, maybe ? Seems to be field 0x22-0x23
	   repeated */
	uint16_t                unknown;
} __attribute__ ((packed));

/*
 * packet received, statistics
 */

struct islsm_control_stats {
	uint32_t                rx_pkt_fcsok;
	uint32_t                rx_pkt_fcsbad;
	/* incremented when rxdma from bbp aborted */
	uint32_t                rx_pkt_abort;
	/* incremented for various errors, mainly
	   if size is too small or exceeds the MRU */
	uint32_t                rx_pkt_size_error;
	/* the rest is tx stats */
	uint32_t                stat4;
	uint32_t                stat5;
	uint32_t                timestamp;	/* in microseconds, see rx packet */
	uint32_t                stat6;
	/* signal strength, BBP register 6CD. Only lower byte (masked
	 * with 0xff at firmware level. maybe the lower byte actually
	 * encodes noise ? */
	uint32_t                rssi;
} __attribute__ ((packed));

#endif				/* _HAVE_PROTOCOL_H */
