467 lines
16 KiB
C
467 lines
16 KiB
C
/*
|
|
* Broadcom Dongle Host Driver (DHD), Linux-specific network interface.
|
|
* Basically selected code segments from usb-cdc.c and usb-rndis.c
|
|
*
|
|
* Copyright (C) 2023, Broadcom.
|
|
*
|
|
* Unless you and Broadcom execute a separate written software license
|
|
* agreement governing use of this software, this software is licensed to you
|
|
* under the terms of the GNU General Public License version 2 (the "GPL"),
|
|
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
|
|
* following added to such license:
|
|
*
|
|
* As a special exception, the copyright holders of this software give you
|
|
* permission to link this software with independent modules, and to copy and
|
|
* distribute the resulting executable under terms of your choice, provided that
|
|
* you also meet, for each linked independent module, the terms and conditions of
|
|
* the license of that module. An independent module is a module which is not
|
|
* derived from this software. The special exception does not apply to any
|
|
* modifications of the software.
|
|
*
|
|
*
|
|
* <<Broadcom-WL-IPTag/Open:>>
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#ifndef __DHD_CSI_H__
|
|
#define __DHD_CSI_H__
|
|
|
|
/* definition for structure and API between APPP and driver */
|
|
|
|
/* **** SYNA CSI header interface with driver **** */
|
|
|
|
enum syna_csi_data_mode_type {
|
|
SYNA_CSI_DATA_MODE_NONE = 0,
|
|
/* upper layer will fetch data by sysfs */
|
|
SYNA_CSI_DATA_MODE_SYSFS,
|
|
/* upper layer will fetch data by UDP socket */
|
|
SYNA_CSI_DATA_MODE_UDP_SOCKET,
|
|
SYNA_CSI_DATA_MODE_LAST
|
|
};
|
|
|
|
enum syna_csi_format_type {
|
|
SYNA_CSI_FORMAT_UNKNOWN = 0,
|
|
SYNA_CSI_FORMAT_Q8, /* (9,9,5) Q8 floating point
|
|
* BCM4358/4359
|
|
*/
|
|
SYNA_CSI_FORMAT_Q13, /* (14,14) Q13 fixed point
|
|
* BCM4339/43455/43456/43458
|
|
*/
|
|
SYNA_CSI_FORMAT_Q11, /* (12,12,6) Q11 floating point
|
|
* BCM4360/4366
|
|
*/
|
|
SYNA_CSI_FORMAT_LAST
|
|
};
|
|
/* (9,9,5) Q8 floating point data format */
|
|
#define _Q8_REAL_MA(t) (0x000ff &((t)>>14))
|
|
#define _Q8_REAL_SI(t) (0x00001 &((t)>>22))
|
|
#define _Q8_IMAGE_MA(t) (0x000ff &((t)>> 5))
|
|
#define _Q8_IMAGE_SI(t) (0x00001 &((t)>>13))
|
|
#define SYNA_CSI_DATA_Q8_REAL(t) \
|
|
(((0 < _Q8_REAL_SI(t)) \
|
|
? (-1) \
|
|
: (1)) \
|
|
* ((int32)_Q8_REAL_MA(t)) \
|
|
)
|
|
#define SYNA_CSI_DATA_Q8_IMAGE(t) \
|
|
(((0 < _Q8_IMAGE_SI(t)) \
|
|
? (-1) \
|
|
: (1)) \
|
|
* ((int32)_Q8_IMAGE_MA(t)) \
|
|
)
|
|
#define SYNA_CSI_DATA_Q8_EXP(t) \
|
|
(((int8)(0xf8 \
|
|
& ((t) << 3))) \
|
|
>> 3 \
|
|
)
|
|
/* (14,14) Q13 fixed point data format */
|
|
#define SYNA_CSI_DATA_Q13_REAL(t) \
|
|
(((int32)(0xfff30000 \
|
|
& ((t) << 4))) \
|
|
>> (14 + 4) \
|
|
)
|
|
#define SYNA_CSI_DATA_Q13_IMAGE(t) \
|
|
(((int32)(0xfff30000 \
|
|
& ((t) << 18))) \
|
|
>> (0 + 18) \
|
|
)
|
|
/* (12,12,6) Q11 floating point */
|
|
#define _Q11_REAL_MA(t) (0x007ff &((t)>>18))
|
|
#define _Q11_REAL_SI(t) (0x00001 &((t)>>29))
|
|
#define _Q11_IMAGE_MA(t) (0x007ff &((t)>> 6))
|
|
#define _Q11_IMAGE_SI(t) (0x00001 &((t)>>17))
|
|
#define SYNA_CSI_DATA_Q11_REAL(t) \
|
|
(((0 < _Q11_REAL_SI(t)) \
|
|
? (-1) \
|
|
: (1)) \
|
|
* ((int32)_Q11_REAL_MA(t)) \
|
|
)
|
|
#define SYNA_CSI_DATA_Q11_IMAGE(t) \
|
|
(((0 < _Q11_IMAGE_SI(t)) \
|
|
? (-1) \
|
|
: (1)) \
|
|
* ((int32)_Q11_IMAGE_MA(t)) \
|
|
)
|
|
#define SYNA_CSI_DATA_Q11_EXP(t) \
|
|
(((int8)(0xfc \
|
|
& ((t) << 2))) \
|
|
>> 2 \
|
|
)
|
|
|
|
enum syna_csi_error_status {
|
|
SYNA_CSI_ERROR_NONE,
|
|
SYNA_CSI_ERROR_GENERIC, /* generic error */
|
|
SYNA_CSI_ERROR_NO_ACK, /* peer doesn't ACK */
|
|
SYNA_CSI_ERROR_READ, /* read data error */
|
|
SYNA_CSI_ERROR_PS, /* peer device under powersaving */
|
|
SYNA_CSI_ERROR_LAST
|
|
};
|
|
|
|
enum syna_csi_flag {
|
|
/* bit 0 ~ bit 15 are for error information */
|
|
SYNA_CSI_FLAG_ERROR_MASK = 0x0FFFF,
|
|
SYNA_CSI_FLAG_ERROR_CHECKSUM = (1 << 0),
|
|
SYNA_CSI_FLAG_ERROR_GENERIC = (1 << SYNA_CSI_ERROR_GENERIC),
|
|
SYNA_CSI_FLAG_ERROR_NO_ACK = (1 << SYNA_CSI_ERROR_NO_ACK),
|
|
SYNA_CSI_FLAG_ERROR_READ = (1 << SYNA_CSI_ERROR_READ),
|
|
SYNA_CSI_FLAG_ERROR_PS = (1 << SYNA_CSI_ERROR_PS),
|
|
|
|
/* subcarrier real position along FFT index: (total N=2*M subcarries)
|
|
* -M, -(M-1), -(M-2), -(M-3),...,-1, 0, 1, 2,...M-1, M
|
|
*
|
|
* Data Output order with positive part first(*default*):
|
|
* 0, 1, 2,...M-1, M, -M, -(M-1), -(M-2), -(M-3),...,-1,
|
|
*
|
|
* Data Output order with negative part first:
|
|
* -M, -(M-1), -(M-2), -(M-3),...,-1, 0, 1, 2,...M-1, M
|
|
*/
|
|
SYNA_CSI_FLAG_FFT_NEGATIVE_FIRST = (1 << 16),
|
|
SYNA_CSI_FLAG_LAST
|
|
};
|
|
|
|
enum syna_csi_band_type {
|
|
SYNA_CSI_BAND_UNKNOWN = 0,
|
|
SYNA_CSI_BAND_2G,
|
|
SYNA_CSI_BAND_5G,
|
|
SYNA_CSI_BAND_6G,
|
|
SYNA_CSI_BAND_LAST
|
|
};
|
|
|
|
enum syna_csi_bandwidth_type {
|
|
SYNA_CSI_BW_UNKNOWN = 0x000,
|
|
SYNA_CSI_BW_5MHz = 0x001,
|
|
SYNA_CSI_BW_10MHz = 0x002,
|
|
SYNA_CSI_BW_20MHz = 0x004,
|
|
SYNA_CSI_BW_40MHz = 0x008,
|
|
SYNA_CSI_BW_80MHz = 0x010,
|
|
SYNA_CSI_BW_160MHz = 0x020,
|
|
SYNA_CSI_BW_320MHz = 0x040,
|
|
SYNA_CSI_BW_LAST
|
|
};
|
|
|
|
/* 'SYNA' -> 'A'53, 'N'59, 'Y'4e, 'S'41 */
|
|
#define CONST_SYNA_CSI_MAGIC_FLAG 0x414E5953
|
|
|
|
/* CSI API common header structure (8 bytes alignment for 64bit system) */
|
|
/* below is version 1 'syna_csi_header' */
|
|
#define CONST_SYNA_CSI_COMMON_HEADER_VERSION 0x01
|
|
struct syna_csi_header {
|
|
/* byte 0 ~ 3 */
|
|
uint32 magic_flag; /* flag for protecting and detecting header */
|
|
|
|
/* byte 4 ~ 7 */
|
|
uint8 version; /* header version of this structure */
|
|
uint8 format_type; /* data format type of current CSI packet,
|
|
* enumerated in 'syna_csi_format_type'
|
|
*/
|
|
uint8 fc; /* packet frame control type of current
|
|
* CSI data for further checking if it
|
|
* is correct expected result
|
|
*/
|
|
uint8 flags; /* flag may use for extra emendation
|
|
* which enumerated as 'syna_csi_flag'
|
|
*/
|
|
|
|
/* byte 8 ~ 19 */
|
|
uint8 client_ea[6]; /* client MAC address */
|
|
uint8 bsscfg_ea[6]; /* BSSCFG address of current interface */
|
|
|
|
/* byte 20 ~ 23 */
|
|
uint8 band; /* enumerated in 'syna_csi_band_type' */
|
|
uint8 bandwidth; /* enumerated in 'syna_csi_bandwidth_type' */
|
|
uint16 channel; /* channel number of corresponding band */
|
|
|
|
/* byte 24 ~ 31 */
|
|
uint64 report_tsf; /* current CSI DATA RX timestamp */
|
|
|
|
/* byte 32 ~ 35 */
|
|
uint8 num_txstream; /* peer side TX spatial steams */
|
|
uint8 num_rxchain; /* number of RX side chain/antenna */
|
|
uint16 num_subcarrier; /* Number of subcarrier */
|
|
|
|
/* byte 36 ~ 39 */
|
|
int8 rssi; /* average RSSI, and goto check the
|
|
* 'rssi_ant' if this 'rssi' is zero
|
|
*/
|
|
int8 noise; /* average noise */
|
|
int16 global_id; /* CSI frame global ID */
|
|
|
|
/* byte 40 ~ 47 */
|
|
int8 rssi_ant[8]; /* RSSI of each RX chain/antenna
|
|
* (Depends on solution, and some
|
|
* chipsets may only provide 'rssi'
|
|
* rather than 'rssi_ant')
|
|
*/
|
|
|
|
/* byte 48 ~ 55 */
|
|
uint64 padding_future; /* reserved */
|
|
|
|
/* byte 56 ~ 63 */
|
|
uint16 data_length; /* the bytes of 'data[]' */
|
|
uint16 remain_length; /* remain length of not received data */
|
|
uint16 copied_length; /* the length has been copied to user */
|
|
uint16 checksum; /* 'data[]' checksum, 0 - not used */
|
|
|
|
/* byte 64 ~ End */
|
|
uint32 data[0]; /* variable length according to the
|
|
* 'data_length', but the minimal
|
|
* valid data length will be
|
|
* decided by the 'num_txchains'
|
|
* 'num_rxchain' 'num_subcarrier'.
|
|
* For example, the index quantity
|
|
* of 'uint32' in the 11N 80MHz can
|
|
* be got via:
|
|
* 256 SubCarriers * 2 TXStream * 2 RXChain
|
|
* Note: 'data_length' is bytes quantity,
|
|
* and the 'data[]' array index range should
|
|
* be 0 ~ (data_length/4 - 1)
|
|
*/
|
|
};
|
|
|
|
#define SYNA_CSI_PKT_TOTAL_LEN(ptr) \
|
|
(sizeof(struct syna_csi_header) \
|
|
+ ((struct syna_csi_header *)(ptr))->data_length \
|
|
)
|
|
|
|
/* definition for structure and functions between driver and FW */
|
|
|
|
/* Maxinum csi file dump size */
|
|
#define MAX_CSI_FILESZ (32 * 1024)
|
|
/* Maxinum subcarrier number */
|
|
#define MAXIMUM_CFR_DATA 2048
|
|
#define CSI_DUMP_PATH "/sys/bcm-dhd/csi"
|
|
#define MAX_EVENT_SIZE 1400
|
|
/* maximun csi number stored at dhd */
|
|
#define MAX_CSI_NUM 16
|
|
#define MAX_CSI_BUF_NUM 1024
|
|
|
|
/* CSI VERSION */
|
|
#define CSI_VERSION_V0 0 /* V0 */
|
|
#define CSI_VERSION_V1 1 /* V1 */
|
|
#define CSI_VERSION_V2 2 /* V2 */
|
|
|
|
struct dhd_cfr_header_v0 {
|
|
uint8 status:4; /* bit3-0 */
|
|
uint8 version:4; /* bit7-4 */
|
|
/* Peer MAC address */
|
|
uint8 peer_macaddr[6];
|
|
/* Number of Space Time Streams */
|
|
uint8 sts;
|
|
/* Number of RX chain */
|
|
uint8 num_rx;
|
|
/* Number of subcarrier */
|
|
uint16 num_carrier;
|
|
/* Length of the CSI dump */
|
|
uint32 cfr_dump_length;
|
|
/* remain unsend CSI data length */
|
|
uint32 remain_length;
|
|
/* RSSI */
|
|
int8 rssi;
|
|
uint32 data[0];
|
|
} __attribute__ ((packed));
|
|
|
|
struct dhd_cfr_header_v1 {
|
|
uint8 status:4; /* bit3-0 */
|
|
uint8 version:4; /* bit7-4 */
|
|
/* Peer MAC address */
|
|
uint8 peer_macaddr[6];
|
|
/* Number of Space Time Streams */
|
|
uint8 sts;
|
|
/* Number of RX chain */
|
|
uint8 num_rx;
|
|
/* Number of subcarrier */
|
|
uint16 num_carrier;
|
|
/* Length of the CSI dump */
|
|
uint32 cfr_dump_length;
|
|
/* remain unsend CSI data length */
|
|
uint32 remain_length;
|
|
/* RSSI */
|
|
int8 rssi;
|
|
|
|
/* Chip id. 1 for BCM43456/8 */
|
|
uint8 chip_id;
|
|
/* Frame control field */
|
|
uint8 fc;
|
|
/* Time stamp when CFR capture is taken,
|
|
* in microseconds since the epoch
|
|
*/
|
|
uint64 cfr_timestamp;
|
|
|
|
uint32 data[0];
|
|
} __attribute__ ((packed));
|
|
|
|
struct dhd_cfr_header_v2 { /* 8 bytes aligment for x64 */
|
|
/* byte 0 ~ 7 */
|
|
uint8 status_compat:4; /* bit3-0, current CSI data status: 0->good */
|
|
uint8 version_compat:4; /* bit7-4, duplicate but compatible part */
|
|
uint8 padding_magic;
|
|
uint16 magic_flag; /* flag for protecting and detecting header */
|
|
|
|
uint8 version; /* header version of this structure */
|
|
uint8 format_type; /* data format type of current CSI packet,
|
|
* enumerated in 'syna_csi_format_type'
|
|
*/
|
|
uint8 fc; /* packet frame control type of current
|
|
* CSI data for further checking if it
|
|
* is correct expected result
|
|
*/
|
|
uint8 flags; /* flag may use for extra emendation
|
|
* which enumerated as 'syna_csi_flag'
|
|
*/
|
|
|
|
/* byte 8 ~ 19 */
|
|
uint8 client_ea[6]; /* client MAC address */
|
|
uint8 bsscfg_ea[6]; /* BSSCFG address of current interface */
|
|
|
|
/* byte 20 ~ 23 */
|
|
uint8 band; /* enumerated in 'syna_csi_band_type' */
|
|
uint8 bandwidth; /* enumerated in 'syna_csi_bandwidth_type' */
|
|
uint16 channel; /* channel number of corresponding band */
|
|
|
|
/* byte 24 ~ 31 */
|
|
uint64 report_tsf; /* current CSI DATA RX timestamp */
|
|
|
|
/* byte 32 ~ 35 */
|
|
uint8 num_txstream; /* peer side TX spatial steams */
|
|
uint8 num_rxchain; /* number of RX side chain/antenna */
|
|
uint16 num_subcarrier; /* Number of subcarrier */
|
|
|
|
/* byte 36 ~ 39 */
|
|
int8 rssi; /* average RSSI, and goto check the
|
|
* 'rssi_ant' if this 'rssi' is zero
|
|
*/
|
|
int8 noise; /* average noise */
|
|
int16 global_id; /* CSI frame global ID */
|
|
|
|
/* byte 40 ~ 47 */
|
|
int8 rssi_ant[8]; /* RSSI of each RX chain/antenna
|
|
* (Depends on solution, and some
|
|
* chipsets may only provide 'rssi'
|
|
* rather than 'rssi_ant')
|
|
*/
|
|
|
|
/* byte 48 ~ 55 */
|
|
uint64 padding_future; /* reserved */
|
|
|
|
/* byte 56 ~ 63 */
|
|
uint16 data_length; /* the data length of 'data[]' */
|
|
uint16 remain_length; /* the remain unsent length of 'data[]' */
|
|
uint16 padding_length; /* reserved */
|
|
uint16 checksum; /* 'data[]' checksum, 0 - not used */
|
|
|
|
/* byte 64 ~ End */
|
|
uint32 data[0]; /* variable according to 'data_length', but
|
|
* the minial valid data length will be
|
|
* decided by 'num_txchains', 'num_rxchain'
|
|
* 'num_subcarrier'. For example, the
|
|
* quantity of uint32(4 bytes) in the
|
|
* 11N 80MHz can be got via:
|
|
* 256 SubCarriers * 2 TXStream * 2 RXChain
|
|
*/
|
|
};
|
|
|
|
union dhd_cfr_header {
|
|
struct dhd_cfr_header_v0 header_v0;
|
|
struct dhd_cfr_header_v1 header_v1;
|
|
struct dhd_cfr_header_v2 header_v2;
|
|
};
|
|
#define CSI_CFR_TOTAL_LENGTH(data_len) \
|
|
(sizeof(union dhd_cfr_header) + data_len)
|
|
|
|
/* BW80 2x2 => 4bytes*256subcarries*2txstream*2rxchain */
|
|
#define CONST_CSI_MAXIMUM_DATA_BYTES (CSI_CFR_TOTAL_LENGTH(256 *2 *2 *4))
|
|
|
|
struct csi_cfr_node {
|
|
struct list_head list;
|
|
void *pNode; /* recording current node pointer
|
|
* especially for UDP data manner
|
|
*/
|
|
uint32 total_size;
|
|
|
|
struct syna_csi_header entry;
|
|
};
|
|
|
|
#define SYNA_CSI_CFR_NODE_LEN sizeof(struct csi_cfr_node)
|
|
|
|
#define SYNA_CSI_CFR_NODE_TOTAL_LEN(ptr, data_length) \
|
|
(\
|
|
SYNA_CSI_CFR_NODE_LEN + data_length \
|
|
)
|
|
|
|
#define SYNA_CSI_CFR_NODE_FREE_LEN(ptr) \
|
|
(\
|
|
((struct csi_cfr_node *)(ptr))->total_size \
|
|
- SYNA_CSI_CFR_NODE_LEN \
|
|
)
|
|
|
|
extern int dhd_csi_config(dhd_pub_t *dhdp, char *buf, uint length, bool is_set);
|
|
|
|
/* Function: change the upper layer fetching data manner
|
|
* Input: uint is_set indicate it's set or get action
|
|
* uint type the expected fetch type(ignore when get)
|
|
* uint param extra param when set(UDP socket port)
|
|
* Output: < 0 error encounter
|
|
* == 0 successful
|
|
* > 0 corresponding 'fetch type' when get
|
|
*/
|
|
extern int dhd_csi_data_fetch_type_access(uint is_set, uint type, uint param);
|
|
|
|
/* Function: parse the CSI event and convert to 'dhd_csi_header' format,
|
|
* and queue the item into the common 'csi_cfr_queue'
|
|
* Input: dhd_pub_t *dhdp context for operation
|
|
* char *buf buffer for storing csi data
|
|
* uint count total bytes available in 'buf'
|
|
* Output: < 0 error encounter
|
|
* == 0 successful but no csi data in queue
|
|
* > 0 bytes write into 'buf'
|
|
*/
|
|
extern int dhd_csi_retrieve_queue_data(dhd_pub_t *dhdp, char *buf, uint count);
|
|
|
|
/* Function: parse the CSI event and convert to 'dhd_csi_header' format,
|
|
* and queue the item into the common 'csi_cfr_queue'
|
|
* Input: dhd_pub_t *dhdp context for operation
|
|
* wl_event_msg_t *event wl event message header
|
|
* void *event_data extra event data
|
|
* Output: < 0 error encounter
|
|
* == 0 successful
|
|
*/
|
|
extern int dhd_csi_event_handler(dhd_pub_t *dhdp,
|
|
const wl_event_msg_t *event, void *event_data);
|
|
|
|
/* Function: Initialize the CSI module
|
|
* Input: dhd_pub_t *dhdp context for operation
|
|
* Output: < 0 error encounter
|
|
* == 0 successful
|
|
*/
|
|
extern int dhd_csi_init(dhd_pub_t *dhdp);
|
|
|
|
/* Function: Deinitialize the CSI module
|
|
* Input: dhd_pub_t *dhdp context for operation
|
|
* Output: < 0 error encounter
|
|
* == 0 successful
|
|
*/
|
|
extern int dhd_csi_deinit(dhd_pub_t *dhdp);
|
|
|
|
#endif /* __DHD_CSI_H__ */
|