nt9856x/code/driver/source/net/GobiNet/QMI.c
2023-05-17 15:33:39 +08:00

1510 lines
44 KiB
C
Executable File

#ifdef __QUEC_INCLUDE_QMI_C__
/*===========================================================================
FILE:
QMI.c
DESCRIPTION:
Qualcomm QMI driver code
FUNCTIONS:
Generic QMUX functions
ParseQMUX
FillQMUX
Generic QMI functions
GetTLV
ValidQMIMessage
GetQMIMessageID
Fill Buffers with QMI requests
QMICTLGetClientIDReq
QMICTLReleaseClientIDReq
QMICTLReadyReq
QMIWDSSetEventReportReq
QMIWDSGetPKGSRVCStatusReq
QMIDMSGetMEIDReq
QMIWDASetDataFormatReq
QMICTLSetDataFormatReq
QMICTLSyncReq
Parse data from QMI responses
QMICTLGetClientIDResp
QMICTLReleaseClientIDResp
QMIWDSEventResp
QMIDMSGetMEIDResp
QMIWDASetDataFormatResp
QMICTLSyncResp
Copyright (c) 2011, Code Aurora Forum. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Code Aurora Forum nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
===========================================================================*/
//---------------------------------------------------------------------------
// Include Files
//---------------------------------------------------------------------------
#include <asm/unaligned.h>
#include <linux/kernel.h>
#include "Structs.h"
#include "QMI.h"
/*=========================================================================*/
// Get sizes of buffers needed by QMI requests
/*=========================================================================*/
/*===========================================================================
METHOD:
QMUXHeaderSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMUXHeaderSize( void )
{
return sizeof( sQMUX );
}
/*===========================================================================
METHOD:
QMICTLGetClientIDReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMICTLGetClientIDReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMICTLGetClientIDReqSize( void )
{
return sizeof( sQMUX ) + 10;
}
/*===========================================================================
METHOD:
QMICTLReleaseClientIDReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMICTLReleaseClientIDReq
RETURN VALUE:
u16 - size of header
===========================================================================*/
static u16 QMICTLReleaseClientIDReqSize( void )
{
return sizeof( sQMUX ) + 11;
}
/*===========================================================================
METHOD:
QMICTLReadyReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMICTLReadyReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMICTLReadyReqSize( void )
{
return sizeof( sQMUX ) + 6;
}
/*===========================================================================
METHOD:
QMIWDSSetEventReportReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMIWDSSetEventReportReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMIWDSSetEventReportReqSize( void )
{
return sizeof( sQMUX ) + 15;
}
/*===========================================================================
METHOD:
QMIWDSGetPKGSRVCStatusReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMIWDSGetPKGSRVCStatusReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMIWDSGetPKGSRVCStatusReqSize( void )
{
return sizeof( sQMUX ) + 7;
}
/*===========================================================================
METHOD:
QMIDMSGetMEIDReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMIDMSGetMEIDReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMIDMSGetMEIDReqSize( void )
{
return sizeof( sQMUX ) + 7;
}
#ifdef QUECTEL_WWAN_QMAP
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS
{
u8 TLVType;
u16 TLVLength;
u8 QOSSetting;
} __packed;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV
{
u8 TLVType;
u16 TLVLength;
u32 Value;
} __packed;
struct QMIWDS_ENDPOINT_TLV
{
u8 TLVType;
u16 TLVLength;
u32 ep_type;
u32 iface_id;
} __packed;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG
{
u8 CtlFlags; // 0: single QMUX Msg; 1:
u16 TransactionId;
u16 Type;
u16 Length;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS QosDataFormatTlv;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UnderlyingLinkLayerProtocolTlv;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationProtocolTlv;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationProtocolTlv;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxDatagramsTlv;
struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxSizeTlv;
struct QMIWDS_ENDPOINT_TLV epTlv;
//struct QMIWDS_ADMIN_SET_DATA_FORMAT_TLV dl_minimum_padding;
} __packed;
#endif
/*===========================================================================
METHOD:
QMIWDASetDataFormatReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMIWDASetDataFormatReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMIWDASetDataFormatReqSize( int qmap_mode )
{
if (qmap_mode)
return sizeof( sQMUX ) + sizeof(struct QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG);
else
return sizeof( sQMUX ) + 18;
}
/*===========================================================================
METHOD:
QMICTLSyncReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMICTLSyncReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMICTLSyncReqSize( void )
{
return sizeof( sQMUX ) + 6;
}
/*=========================================================================*/
// Generic QMUX functions
/*=========================================================================*/
/*===========================================================================
METHOD:
ParseQMUX (Public Method)
DESCRIPTION:
Remove QMUX headers from a buffer
PARAMETERS
pClientID [ O ] - On success, will point to Client ID
pBuffer [ I ] - Full Message passed in
buffSize [ I ] - Size of pBuffer
RETURN VALUE:
int - Positive for size of QMUX header
Negative errno for error
===========================================================================*/
static int ParseQMUX(
u16 * pClientID,
void * pBuffer,
u16 buffSize )
{
sQMUX * pQMUXHeader;
if (pBuffer == 0 || buffSize < 12)
{
return -ENOMEM;
}
// QMUX Header
pQMUXHeader = (sQMUX *)pBuffer;
if (pQMUXHeader->mTF != 1
|| le16_to_cpu(get_unaligned(&pQMUXHeader->mLength)) != buffSize - 1
|| pQMUXHeader->mCtrlFlag != 0x80 )
{
return -EINVAL;
}
// Client ID
*pClientID = (pQMUXHeader->mQMIClientID << 8) + pQMUXHeader->mQMIService;
return sizeof( sQMUX );
}
/*===========================================================================
METHOD:
FillQMUX (Public Method)
DESCRIPTION:
Fill buffer with QMUX headers
PARAMETERS
clientID [ I ] - Client ID
pBuffer [ O ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer (must be at least 6)
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int FillQMUX(
u16 clientID,
void * pBuffer,
u16 buffSize )
{
sQMUX * pQMUXHeader;
if (pBuffer == 0 || buffSize < sizeof( sQMUX ))
{
return -ENOMEM;
}
// QMUX Header
pQMUXHeader = (sQMUX *)pBuffer;
pQMUXHeader->mTF = 1;
put_unaligned(cpu_to_le16(buffSize - 1), &pQMUXHeader->mLength);
//DBG("pQMUXHeader->mLength = 0x%x, buffSize - 1 = 0x%x\n",pQMUXHeader->mLength, buffSize - 1);
pQMUXHeader->mCtrlFlag = 0;
// Service and Client ID
pQMUXHeader->mQMIService = clientID & 0xff;
pQMUXHeader->mQMIClientID = clientID >> 8;
return 0;
}
/*=========================================================================*/
// Generic QMI functions
/*=========================================================================*/
/*===========================================================================
METHOD:
GetTLV (Public Method)
DESCRIPTION:
Get data buffer of a specified TLV from a QMI message
QMI Message shall NOT include SDU
PARAMETERS
pQMIMessage [ I ] - QMI Message buffer
messageLen [ I ] - Size of QMI Message buffer
type [ I ] - Desired Type
pOutDataBuf [ O ] - Buffer to be filled with TLV
messageLen [ I ] - Size of QMI Message buffer
RETURN VALUE:
u16 - Size of TLV for success
Negative errno for error
===========================================================================*/
static int GetTLV(
void * pQMIMessage,
u16 messageLen,
u8 type,
void * pOutDataBuf,
u16 bufferLen )
{
u16 pos;
u16 tlvSize = 0;
u16 cpyCount;
if (pQMIMessage == 0 || pOutDataBuf == 0)
{
return -ENOMEM;
}
for (pos = 4;
pos + 3 < messageLen;
pos += tlvSize + 3)
{
tlvSize = le16_to_cpu( get_unaligned(((u16 *)(pQMIMessage + pos + 1) )) );
if (*(u8 *)(pQMIMessage + pos) == type)
{
if (bufferLen < tlvSize)
{
return -ENOMEM;
}
for (cpyCount = 0; cpyCount < tlvSize; cpyCount++)
{
*((char*)(pOutDataBuf + cpyCount)) = *((char*)(pQMIMessage + pos + 3 + cpyCount));
}
return tlvSize;
}
}
return -ENOMSG;
}
/*===========================================================================
METHOD:
ValidQMIMessage (Public Method)
DESCRIPTION:
Check mandatory TLV in a QMI message
QMI Message shall NOT include SDU
PARAMETERS
pQMIMessage [ I ] - QMI Message buffer
messageLen [ I ] - Size of QMI Message buffer
RETURN VALUE:
int - 0 for success (no error)
Negative errno for error
Positive for QMI error code
===========================================================================*/
static int ValidQMIMessage(
void * pQMIMessage,
u16 messageLen )
{
char mandTLV[4];
if (GetTLV( pQMIMessage, messageLen, 2, &mandTLV[0], 4 ) == 4)
{
// Found TLV
if (*(u16 *)&mandTLV[0] != 0)
{
return le16_to_cpu( get_unaligned(&mandTLV[2]) );
}
else
{
return 0;
}
}
else
{
return -ENOMSG;
}
}
/*===========================================================================
METHOD:
GetQMIMessageID (Public Method)
DESCRIPTION:
Get the message ID of a QMI message
QMI Message shall NOT include SDU
PARAMETERS
pQMIMessage [ I ] - QMI Message buffer
messageLen [ I ] - Size of QMI Message buffer
RETURN VALUE:
int - Positive for message ID
Negative errno for error
===========================================================================*/
static int GetQMIMessageID(
void * pQMIMessage,
u16 messageLen )
{
if (messageLen < 2)
{
return -ENODATA;
}
else
{
return le16_to_cpu( get_unaligned((u16 *)pQMIMessage) );
}
}
/*=========================================================================*/
// Fill Buffers with QMI requests
/*=========================================================================*/
/*===========================================================================
METHOD:
QMICTLGetClientIDReq (Public Method)
DESCRIPTION:
Fill buffer with QMI CTL Get Client ID Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
serviceType [ I ] - Service type requested
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMICTLGetClientIDReq(
void * pBuffer,
u16 buffSize,
u8 transactionID,
u8 serviceType )
{
if (pBuffer == 0 || buffSize < QMICTLGetClientIDReqSize() )
{
return -ENOMEM;
}
// QMI CTL GET CLIENT ID
// Request
*(u8 *)(pBuffer + sizeof( sQMUX ))= 0x00;
// Transaction ID
*(u8 *)(pBuffer + sizeof( sQMUX ) + 1) = transactionID;
// Message ID
put_unaligned(cpu_to_le16(0x0022), (u16 *)(pBuffer + sizeof( sQMUX ) + 2));
// Size of TLV's
put_unaligned(cpu_to_le16(0x0004), (u16 *)(pBuffer + sizeof( sQMUX ) + 4));
// QMI Service Type
*(u8 *)(pBuffer + sizeof( sQMUX ) + 6) = 0x01;
// Size
put_unaligned(cpu_to_le16(0x0001), (u16 *)(pBuffer + sizeof( sQMUX ) + 7));
// QMI svc type
*(u8 *)(pBuffer + sizeof( sQMUX ) + 9) = serviceType;
// success
return sizeof( sQMUX ) + 10;
}
/*===========================================================================
METHOD:
QMICTLReleaseClientIDReq (Public Method)
DESCRIPTION:
Fill buffer with QMI CTL Release Client ID Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
clientID [ I ] - Service type requested
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMICTLReleaseClientIDReq(
void * pBuffer,
u16 buffSize,
u8 transactionID,
u16 clientID )
{
if (pBuffer == 0 || buffSize < QMICTLReleaseClientIDReqSize() )
{
return -ENOMEM;
}
DBG( "buffSize: 0x%x, transactionID: 0x%x, clientID: 0x%x,\n",
buffSize, transactionID, clientID );
// QMI CTL RELEASE CLIENT ID REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
*(u8 *)(pBuffer + sizeof( sQMUX ) + 1 ) = transactionID;
// Message ID
put_unaligned( cpu_to_le16(0x0023), (u16 *)(pBuffer + sizeof( sQMUX ) + 2) );
// Size of TLV's
put_unaligned( cpu_to_le16(0x0005), (u16 *)(pBuffer + sizeof( sQMUX ) + 4) );
// Release client ID
*(u8 *)(pBuffer + sizeof( sQMUX ) + 6) = 0x01;
// Size
put_unaligned( cpu_to_le16(0x0002), (u16 *)(pBuffer + sizeof( sQMUX ) + 7));
// QMI svs type / Client ID
put_unaligned(cpu_to_le16(clientID), (u16 *)(pBuffer + sizeof( sQMUX ) + 9));
// success
return sizeof( sQMUX ) + 11;
}
/*===========================================================================
METHOD:
QMICTLReadyReq (Public Method)
DESCRIPTION:
Fill buffer with QMI CTL Get Version Info Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMICTLReadyReq(
void * pBuffer,
u16 buffSize,
u8 transactionID )
{
if (pBuffer == 0 || buffSize < QMICTLReadyReqSize() )
{
return -ENOMEM;
}
DBG("buffSize: 0x%x, transactionID: 0x%x\n", buffSize, transactionID);
// QMI CTL GET VERSION INFO REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
*(u8 *)(pBuffer + sizeof( sQMUX ) + 1) = transactionID;
// Message ID
put_unaligned( cpu_to_le16(0x0021), (u16 *)(pBuffer + sizeof( sQMUX ) + 2) );
// Size of TLV's
put_unaligned( cpu_to_le16(0x0000), (u16 *)(pBuffer + sizeof( sQMUX ) + 4) );
// success
return sizeof( sQMUX ) + 6;
}
/*===========================================================================
METHOD:
QMIWDSSetEventReportReq (Public Method)
DESCRIPTION:
Fill buffer with QMI WDS Set Event Report Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMIWDSSetEventReportReq(
void * pBuffer,
u16 buffSize,
u16 transactionID )
{
if (pBuffer == 0 || buffSize < QMIWDSSetEventReportReqSize() )
{
return -ENOMEM;
}
// QMI WDS SET EVENT REPORT REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
put_unaligned( cpu_to_le16(transactionID), (u16 *)(pBuffer + sizeof( sQMUX ) + 1));
// Message ID
put_unaligned( cpu_to_le16(0x0001), (u16 *)(pBuffer + sizeof( sQMUX ) + 3));
// Size of TLV's
put_unaligned(cpu_to_le16(0x0008), (u16 *)(pBuffer + sizeof( sQMUX ) + 5));
// Report channel rate TLV
*(u8 *)(pBuffer + sizeof( sQMUX ) + 7) = 0x11;
// Size
put_unaligned( cpu_to_le16(0x0005), (u16 *)(pBuffer + sizeof( sQMUX ) + 8));
// Stats period
*(u8 *)(pBuffer + sizeof( sQMUX ) + 10) = 0x01;
// Stats mask
put_unaligned( cpu_to_le32(0x000000ff), (u32 *)(pBuffer + sizeof( sQMUX ) + 11) );
// success
return sizeof( sQMUX ) + 15;
}
/*===========================================================================
METHOD:
QMIWDSGetPKGSRVCStatusReq (Public Method)
DESCRIPTION:
Fill buffer with QMI WDS Get PKG SRVC Status Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMIWDSGetPKGSRVCStatusReq(
void * pBuffer,
u16 buffSize,
u16 transactionID )
{
if (pBuffer == 0 || buffSize < QMIWDSGetPKGSRVCStatusReqSize() )
{
return -ENOMEM;
}
// QMI WDS Get PKG SRVC Status REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
put_unaligned(cpu_to_le16(transactionID), (u16 *)(pBuffer + sizeof( sQMUX ) + 1));
// Message ID
put_unaligned(cpu_to_le16(0x0022), (u16 *)(pBuffer + sizeof( sQMUX ) + 3));
// Size of TLV's
put_unaligned(cpu_to_le16(0x0000), (u16 *)(pBuffer + sizeof( sQMUX ) + 5));
// success
return sizeof( sQMUX ) + 7;
}
#if 0
static u16 QMIWDSSetQMUXBindMuxDataPortSize( void )
{
return sizeof( sQMUX ) + 29;
}
static u16 QMIWDSSetQMUXBindMuxDataPortReq(
void * pBuffer,
u16 buffSize,
u8 MuxId,
u16 transactionID )
{
if (pBuffer == 0 || buffSize < QMIWDSSetQMUXBindMuxDataPortSize() )
{
return -ENOMEM;
}
// QMI WDS Set QMUX Bind Mux Data Port REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
put_unaligned(cpu_to_le16(transactionID), (u16 *)(pBuffer + sizeof( sQMUX ) + 1));
// Message ID
put_unaligned(cpu_to_le16(0x00a2), (u16 *)(pBuffer + sizeof( sQMUX ) + 3));
// Size of TLV's
put_unaligned(cpu_to_le16(0x0016), (u16 *)(pBuffer + sizeof( sQMUX ) + 5));
*(u8 *)(pBuffer + sizeof( sQMUX ) + 7) = 0x10;
put_unaligned(cpu_to_le16(0x08), (u16 *)(pBuffer + sizeof( sQMUX ) + 8));
put_unaligned(cpu_to_le32(0x02), (u32 *)(pBuffer + sizeof( sQMUX ) + 10)); // ep_type
put_unaligned(cpu_to_le32(0x04), (u32 *)(pBuffer + sizeof( sQMUX ) + 14)); // iface_id
*(u8 *)(pBuffer + sizeof( sQMUX ) + 18) = 0x11;
put_unaligned(cpu_to_le16(0x01), (u16 *)(pBuffer + sizeof( sQMUX ) + 19));
*(u8 *)(pBuffer + sizeof( sQMUX ) + 21) = MuxId; // MuxId
*(u8 *)(pBuffer + sizeof( sQMUX ) + 22) = 0x13;
put_unaligned(cpu_to_le16(0x04), (u16 *)(pBuffer + sizeof( sQMUX ) + 23));
put_unaligned(cpu_to_le32(0x01), (u32 *)(pBuffer + sizeof( sQMUX ) + 25));
// success
return sizeof( sQMUX ) + 29;
}
#endif
/*===========================================================================
METHOD:
QMIDMSGetMEIDReq (Public Method)
DESCRIPTION:
Fill buffer with QMI DMS Get Serial Numbers Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMIDMSGetMEIDReq(
void * pBuffer,
u16 buffSize,
u16 transactionID )
{
if (pBuffer == 0 || buffSize < QMIDMSGetMEIDReqSize() )
{
return -ENOMEM;
}
// QMI DMS GET SERIAL NUMBERS REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
put_unaligned( cpu_to_le16(transactionID), (u16 *)(pBuffer + sizeof( sQMUX ) + 1) );
// Message ID
put_unaligned( cpu_to_le16(0x0025), (u16 *)(pBuffer + sizeof( sQMUX ) + 3) );
// Size of TLV's
put_unaligned( cpu_to_le16(0x0000), (u16 *)(pBuffer + sizeof( sQMUX ) + 5));
// success
return sizeof( sQMUX ) + 7;
}
/*===========================================================================
METHOD:
QMIWDASetDataFormatReq (Public Method)
DESCRIPTION:
Fill buffer with QMI WDA Set Data Format Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMIWDASetDataFormatReq(
void * pBuffer,
u16 buffSize,
bool bRawIPMode, int qmap_mode, u32 rx_size,
u16 transactionID )
{
if (qmap_mode) {
struct QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG *pMUXMsg = (struct QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG *)(pBuffer + sizeof( sQMUX ));
pMUXMsg->CtlFlags = 0x00;
put_unaligned( cpu_to_le16(transactionID), &pMUXMsg->TransactionId);
put_unaligned( cpu_to_le16(0x0020), &pMUXMsg->Type);
put_unaligned( cpu_to_le16(sizeof( struct QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG) - 7), &pMUXMsg->Length);
//Indicates whether the Quality of Service(QOS) data format is used by the client.
pMUXMsg->QosDataFormatTlv.TLVType = 0x10;
pMUXMsg->QosDataFormatTlv.TLVLength = cpu_to_le16(0x0001);
pMUXMsg->QosDataFormatTlv.QOSSetting = 0; /* no-QOS header */
//Underlying Link Layer Protocol
pMUXMsg->UnderlyingLinkLayerProtocolTlv.TLVType = 0x11;
pMUXMsg->UnderlyingLinkLayerProtocolTlv.TLVLength = cpu_to_le16(4);
pMUXMsg->UnderlyingLinkLayerProtocolTlv.Value = cpu_to_le32(0x02); /* Set Ethernet mode */
//Uplink (UL) data aggregation protocol to be used for uplink data transfer.
pMUXMsg->UplinkDataAggregationProtocolTlv.TLVType = 0x12;
pMUXMsg->UplinkDataAggregationProtocolTlv.TLVLength = cpu_to_le16(4);
pMUXMsg->UplinkDataAggregationProtocolTlv.Value = cpu_to_le32(0x05); //UL QMAP is enabled
//Downlink (DL) data aggregation protocol to be used for downlink data transfer
pMUXMsg->DownlinkDataAggregationProtocolTlv.TLVType = 0x13;
pMUXMsg->DownlinkDataAggregationProtocolTlv.TLVLength = cpu_to_le16(4);
pMUXMsg->DownlinkDataAggregationProtocolTlv.Value = cpu_to_le32(0x05); //UL QMAP is enabled
//Maximum number of datagrams in a single aggregated packet on downlink
pMUXMsg->DownlinkDataAggregationMaxDatagramsTlv.TLVType = 0x15;
pMUXMsg->DownlinkDataAggregationMaxDatagramsTlv.TLVLength = cpu_to_le16(4);
pMUXMsg->DownlinkDataAggregationMaxDatagramsTlv.Value = cpu_to_le32(rx_size/1024);
//Maximum size in bytes of a single aggregated packet allowed on downlink
pMUXMsg->DownlinkDataAggregationMaxSizeTlv.TLVType = 0x16;
pMUXMsg->DownlinkDataAggregationMaxSizeTlv.TLVLength = cpu_to_le16(4);
pMUXMsg->DownlinkDataAggregationMaxSizeTlv.Value = cpu_to_le32(rx_size);
//Peripheral End Point ID
pMUXMsg->epTlv.TLVType = 0x17;
pMUXMsg->epTlv.TLVLength = cpu_to_le16(8);
pMUXMsg->epTlv.ep_type = cpu_to_le32(0x02); // DATA_EP_TYPE_BAM_DMUX
pMUXMsg->epTlv.iface_id = cpu_to_le32(0x04);
#if 0
//Specifies the minimum padding bytes to be added in between aggregated downlink QMAP packets.
pMUXMsg->dl_minimum_padding.TLVType = 0x19;
pMUXMsg->dl_minimum_padding.TLVLength = cpu_to_le16(4);
pMUXMsg->dl_minimum_padding.Value = cpu_to_le32(0);
#endif
}
else {
if (pBuffer == 0 || buffSize < QMIWDASetDataFormatReqSize(qmap_mode) )
{
return -ENOMEM;
}
// QMI WDA SET DATA FORMAT REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
put_unaligned( cpu_to_le16(transactionID), (u16 *)(pBuffer + sizeof( sQMUX ) + 1) );
// Message ID
put_unaligned( cpu_to_le16(0x0020), (u16 *)(pBuffer + sizeof( sQMUX ) + 3) );
// Size of TLV's
put_unaligned( cpu_to_le16(0x000b), (u16 *)(pBuffer + sizeof( sQMUX ) + 5));
/* TLVType QOS Data Format 1 byte */
*(u8 *)(pBuffer + sizeof( sQMUX ) + 7) = 0x10; // type data format
/* TLVLength 2 bytes - see spec */
put_unaligned( cpu_to_le16(0x0001), (u16 *)(pBuffer + sizeof( sQMUX ) + 8));
/* DataFormat: 0-default; 1-QoS hdr present 2 bytes */
#ifdef QOS_MODE
*(u8 *)(pBuffer + sizeof( sQMUX ) + 10) = 1; /* QOS header */
#else
*(u8 *)(pBuffer + sizeof( sQMUX ) + 10) = 0; /* no-QOS header */
#endif
/* TLVType Link-Layer Protocol (Optional) 1 byte */
*(u8 *)(pBuffer + sizeof( sQMUX ) + 11) = 0x11;
/* TLVLength 2 bytes */
put_unaligned( cpu_to_le16(0x0004), (u16 *)(pBuffer + sizeof( sQMUX ) + 12));
/* LinkProt: 0x1 - ETH; 0x2 - rawIP 4 bytes */
if (bRawIPMode) { //#ifdef DATA_MODE_RP
/* Set RawIP mode */
put_unaligned( cpu_to_le32(0x00000002), (u32 *)(pBuffer + sizeof( sQMUX ) + 14));
DBG("Request RawIP Data Format\n");
} else { //#else
/* Set Ethernet mode */
put_unaligned( cpu_to_le32(0x00000001), (u32 *)(pBuffer + sizeof( sQMUX ) + 14));
DBG("Request Ethernet Data Format\n");
} //#endif
}
// success
return QMIWDASetDataFormatReqSize(qmap_mode);
}
#if 0
static int QMIWDASetDataQmapReq(
void * pBuffer,
u16 buffSize,
u16 transactionID )
{
// QMI WDA SET DATA FORMAT REQ
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
put_unaligned( cpu_to_le16(transactionID), (u16 *)(pBuffer + sizeof( sQMUX ) + 1) );
// Message ID
put_unaligned( cpu_to_le16(0x002B), (u16 *)(pBuffer + sizeof( sQMUX ) + 3) );
// Size of TLV's
put_unaligned( cpu_to_le16(0x0004), (u16 *)(pBuffer + sizeof( sQMUX ) + 5));
/* TLVType QMAP In-Band Flow Control 1 byte */
*(u8 *)(pBuffer + sizeof( sQMUX ) + 7) = 0x10;
put_unaligned( cpu_to_le16(0x0001), (u16 *)(pBuffer + sizeof( sQMUX ) + 8));
*(u8 *)(pBuffer + sizeof( sQMUX ) + 10) = 0x01;
// success
return ( sizeof( sQMUX ) + 11);
}
#endif
#if 0
/*===========================================================================
METHOD:
QMICTLSetDataFormatReqSize (Public Method)
DESCRIPTION:
Get size of buffer needed for QMUX + QMICTLSetDataFormatReq
RETURN VALUE:
u16 - size of buffer
===========================================================================*/
static u16 QMICTLSetDataFormatReqSize( void )
{
return sizeof( sQMUX ) + 15;
}
/*===========================================================================
METHOD:
QMICTLSetDataFormatReq (Public Method)
DESCRIPTION:
Fill buffer with QMI CTL Set Data Format Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMICTLSetDataFormatReq(
void * pBuffer,
u16 buffSize,
u8 transactionID )
{
if (pBuffer == 0 || buffSize < QMICTLSetDataFormatReqSize() )
{
return -ENOMEM;
}
/* QMI CTL Set Data Format Request */
/* Request */
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00; // QMICTL_FLAG_REQUEST
/* Transaction ID 1 byte */
*(u8 *)(pBuffer + sizeof( sQMUX ) + 1) = transactionID; /* 1 byte as in spec */
/* QMICTLType 2 bytes */
put_unaligned( cpu_to_le16(0x0026), (u16 *)(pBuffer + sizeof( sQMUX ) + 2));
/* Length 2 bytes of 2 TLVs each - see spec */
put_unaligned( cpu_to_le16(0x0009), (u16 *)(pBuffer + sizeof( sQMUX ) + 4));
/* TLVType Data Format (Mandatory) 1 byte */
*(u8 *)(pBuffer + sizeof( sQMUX ) + 6) = 0x01; // type data format
/* TLVLength 2 bytes - see spec */
put_unaligned( cpu_to_le16(0x0001), (u16 *)(pBuffer + sizeof( sQMUX ) + 7));
/* DataFormat: 0-default; 1-QoS hdr present 2 bytes */
#ifdef QOS_MODE
*(u8 *)(pBuffer + sizeof( sQMUX ) + 9) = 1; /* QOS header */
#else
*(u8 *)(pBuffer + sizeof( sQMUX ) + 9) = 0; /* no-QOS header */
#endif
/* TLVType Link-Layer Protocol (Optional) 1 byte */
*(u8 *)(pBuffer + sizeof( sQMUX ) + 10) = TLV_TYPE_LINK_PROTO;
/* TLVLength 2 bytes */
put_unaligned( cpu_to_le16(0x0002), (u16 *)(pBuffer + sizeof( sQMUX ) + 11));
/* LinkProt: 0x1 - ETH; 0x2 - rawIP 2 bytes */
#ifdef DATA_MODE_RP
/* Set RawIP mode */
put_unaligned( cpu_to_le16(0x0002), (u16 *)(pBuffer + sizeof( sQMUX ) + 13));
DBG("Request RawIP Data Format\n");
#else
/* Set Ethernet mode */
put_unaligned( cpu_to_le16(0x0001), (u16 *)(pBuffer + sizeof( sQMUX ) + 13));
DBG("Request Ethernet Data Format\n");
#endif
/* success */
return sizeof( sQMUX ) + 15;
}
#endif
/*===========================================================================
METHOD:
QMICTLSyncReq (Public Method)
DESCRIPTION:
Fill buffer with QMI CTL Sync Request
PARAMETERS
pBuffer [ 0 ] - Buffer to be filled
buffSize [ I ] - Size of pBuffer
transactionID [ I ] - Transaction ID
RETURN VALUE:
int - Positive for resulting size of pBuffer
Negative errno for error
===========================================================================*/
static int QMICTLSyncReq(
void * pBuffer,
u16 buffSize,
u16 transactionID )
{
if (pBuffer == 0 || buffSize < QMICTLSyncReqSize() )
{
return -ENOMEM;
}
// Request
*(u8 *)(pBuffer + sizeof( sQMUX )) = 0x00;
// Transaction ID
*(u8 *)(pBuffer + sizeof( sQMUX ) + 1) = transactionID;
// Message ID
put_unaligned( cpu_to_le16(0x0027), (u16 *)(pBuffer + sizeof( sQMUX ) + 2) );
// Size of TLV's
put_unaligned( cpu_to_le16(0x0000), (u16 *)(pBuffer + sizeof( sQMUX ) + 4) );
// success
return sizeof( sQMUX ) + 6;
}
/*=========================================================================*/
// Parse data from QMI responses
/*=========================================================================*/
/*===========================================================================
METHOD:
QMICTLGetClientIDResp (Public Method)
DESCRIPTION:
Parse the QMI CTL Get Client ID Resp
PARAMETERS
pBuffer [ I ] - Buffer to be parsed
buffSize [ I ] - Size of pBuffer
pClientID [ 0 ] - Recieved client ID
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int QMICTLGetClientIDResp(
void * pBuffer,
u16 buffSize,
u16 * pClientID )
{
int result;
// Ignore QMUX and SDU
// QMI CTL SDU is 2 bytes, not 3
u8 offset = sizeof( sQMUX ) + 2;
if (pBuffer == 0 || buffSize < offset)
{
return -ENOMEM;
}
pBuffer = pBuffer + offset;
buffSize -= offset;
result = GetQMIMessageID( pBuffer, buffSize );
if (result != 0x22)
{
return -EFAULT;
}
result = ValidQMIMessage( pBuffer, buffSize );
if (result != 0)
{
return -EFAULT;
}
result = GetTLV( pBuffer, buffSize, 0x01, pClientID, 2 );
if (result != 2)
{
return -EFAULT;
}
return 0;
}
/*===========================================================================
METHOD:
QMICTLReleaseClientIDResp (Public Method)
DESCRIPTION:
Verify the QMI CTL Release Client ID Resp is valid
PARAMETERS
pBuffer [ I ] - Buffer to be parsed
buffSize [ I ] - Size of pBuffer
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int QMICTLReleaseClientIDResp(
void * pBuffer,
u16 buffSize )
{
int result;
// Ignore QMUX and SDU
// QMI CTL SDU is 2 bytes, not 3
u8 offset = sizeof( sQMUX ) + 2;
if (pBuffer == 0 || buffSize < offset)
{
return -ENOMEM;
}
pBuffer = pBuffer + offset;
buffSize -= offset;
result = GetQMIMessageID( pBuffer, buffSize );
if (result != 0x23)
{
return -EFAULT;
}
result = ValidQMIMessage( pBuffer, buffSize );
if (result != 0)
{
return -EFAULT;
}
return 0;
}
/*===========================================================================
METHOD:
QMIWDSEventResp (Public Method)
DESCRIPTION:
Parse the QMI WDS Set Event Report Resp/Indication or
QMI WDS Get PKG SRVC Status Resp/Indication
Return parameters will only be updated if value was received
PARAMETERS
pBuffer [ I ] - Buffer to be parsed
buffSize [ I ] - Size of pBuffer
pTXOk [ O ] - Number of transmitted packets without errors
pRXOk [ O ] - Number of recieved packets without errors
pTXErr [ O ] - Number of transmitted packets with framing errors
pRXErr [ O ] - Number of recieved packets with framing errors
pTXOfl [ O ] - Number of transmitted packets dropped due to overflow
pRXOfl [ O ] - Number of recieved packets dropped due to overflow
pTXBytesOk [ O ] - Number of transmitted bytes without errors
pRXBytesOk [ O ] - Number of recieved bytes without errors
pbLinkState [ 0 ] - Is the link active?
pbReconfigure [ 0 ] - Must interface be reconfigured? (reset IP address)
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int QMIWDSEventResp(
void * pBuffer,
u16 buffSize,
u32 * pTXOk,
u32 * pRXOk,
u32 * pTXErr,
u32 * pRXErr,
u32 * pTXOfl,
u32 * pRXOfl,
u64 * pTXBytesOk,
u64 * pRXBytesOk,
bool * pbLinkState,
bool * pbReconfigure )
{
int result;
u8 pktStatusRead[2];
// Ignore QMUX and SDU
u8 offset = sizeof( sQMUX ) + 3;
if (pBuffer == 0
|| buffSize < offset
|| pTXOk == 0
|| pRXOk == 0
|| pTXErr == 0
|| pRXErr == 0
|| pTXOfl == 0
|| pRXOfl == 0
|| pTXBytesOk == 0
|| pRXBytesOk == 0
|| pbLinkState == 0
|| pbReconfigure == 0 )
{
return -ENOMEM;
}
pBuffer = pBuffer + offset;
buffSize -= offset;
// Note: Indications. No Mandatory TLV required
result = GetQMIMessageID( pBuffer, buffSize );
// QMI WDS Set Event Report Resp
if (result == 0x01)
{
// TLV's are not mandatory
GetTLV( pBuffer, buffSize, 0x10, (void*)pTXOk, 4 );
put_unaligned( le32_to_cpu(*pTXOk), pTXOk);
GetTLV( pBuffer, buffSize, 0x11, (void*)pRXOk, 4 );
put_unaligned( le32_to_cpu(*pRXOk), pRXOk);
GetTLV( pBuffer, buffSize, 0x12, (void*)pTXErr, 4 );
put_unaligned( le32_to_cpu(*pTXErr), pTXErr);
GetTLV( pBuffer, buffSize, 0x13, (void*)pRXErr, 4 );
put_unaligned( le32_to_cpu(*pRXErr), pRXErr);
GetTLV( pBuffer, buffSize, 0x14, (void*)pTXOfl, 4 );
put_unaligned( le32_to_cpu(*pTXOfl), pTXOfl);
GetTLV( pBuffer, buffSize, 0x15, (void*)pRXOfl, 4 );
put_unaligned( le32_to_cpu(*pRXOfl), pRXOfl);
GetTLV( pBuffer, buffSize, 0x19, (void*)pTXBytesOk, 8 );
put_unaligned( le64_to_cpu(*pTXBytesOk), pTXBytesOk);
GetTLV( pBuffer, buffSize, 0x1A, (void*)pRXBytesOk, 8 );
put_unaligned( le64_to_cpu(*pRXBytesOk), pRXBytesOk);
}
// QMI WDS Get PKG SRVC Status Resp
else if (result == 0x22)
{
result = GetTLV( pBuffer, buffSize, 0x01, &pktStatusRead[0], 2 );
// 1 or 2 bytes may be received
if (result >= 1)
{
if (pktStatusRead[0] == 0x02)
{
*pbLinkState = true;
}
else
{
*pbLinkState = false;
}
}
if (result == 2)
{
if (pktStatusRead[1] == 0x01)
{
*pbReconfigure = true;
}
else
{
*pbReconfigure = false;
}
}
if (result < 0)
{
return result;
}
}
else
{
return -EFAULT;
}
return 0;
}
/*===========================================================================
METHOD:
QMIDMSGetMEIDResp (Public Method)
DESCRIPTION:
Parse the QMI DMS Get Serial Numbers Resp
PARAMETERS
pBuffer [ I ] - Buffer to be parsed
buffSize [ I ] - Size of pBuffer
pMEID [ O ] - Device MEID
meidSize [ I ] - Size of MEID buffer (at least 14)
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int QMIDMSGetMEIDResp(
void * pBuffer,
u16 buffSize,
char * pMEID,
int meidSize )
{
int result;
// Ignore QMUX and SDU
u8 offset = sizeof( sQMUX ) + 3;
if (pBuffer == 0 || buffSize < offset || meidSize < 14)
{
return -ENOMEM;
}
pBuffer = pBuffer + offset;
buffSize -= offset;
result = GetQMIMessageID( pBuffer, buffSize );
if (result != 0x25)
{
return -EFAULT;
}
result = ValidQMIMessage( pBuffer, buffSize );
if (result != 0)
{
return -EFAULT;
}
result = GetTLV( pBuffer, buffSize, 0x12, (void*)pMEID, 14 );
if (result != 14)
{
return -EFAULT;
}
return 0;
}
/*===========================================================================
METHOD:
QMIWDASetDataFormatResp (Public Method)
DESCRIPTION:
Parse the QMI WDA Set Data Format Response
PARAMETERS
pBuffer [ I ] - Buffer to be parsed
buffSize [ I ] - Size of pBuffer
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int QMIWDASetDataFormatResp(
void * pBuffer,
u16 buffSize, bool bRawIPMode, int *qmap_enabled, int *rx_size, int *tx_size)
{
int result;
u8 pktLinkProtocol[4];
// Ignore QMUX and SDU
// QMI SDU is 3 bytes
u8 offset = sizeof( sQMUX ) + 3;
if (pBuffer == 0 || buffSize < offset)
{
return -ENOMEM;
}
pBuffer = pBuffer + offset;
buffSize -= offset;
result = GetQMIMessageID( pBuffer, buffSize );
if (result != 0x20)
{
return -EFAULT;
}
/* Check response message result TLV */
result = ValidQMIMessage( pBuffer, buffSize );
if (result != 0)
{
DBG("EFAULT: Data Format Mode Bad Response\n");
// return -EFAULT;
return 0;
}
/* Check response message link protocol */
result = GetTLV( pBuffer, buffSize, 0x11,
&pktLinkProtocol[0], 4);
if (result != 4)
{
DBG("EFAULT: Wrong TLV format\n");
return 0;
}
if (bRawIPMode) { ////#ifdef DATA_MODE_RP
if (pktLinkProtocol[0] != 2)
{
DBG("EFAULT: Data Format Cannot be set to RawIP Mode\n");
return pktLinkProtocol[0];
}
DBG("Data Format Set to RawIP\n");
} else { ////#else
if (pktLinkProtocol[0] != 1)
{
DBG("EFAULT: Data Format Cannot be set to Ethernet Mode\n");
return pktLinkProtocol[0];
}
DBG("Data Format Set to Ethernet Mode \n");
} //#endif
GetTLV( pBuffer, buffSize, 0x12, qmap_enabled, 4);
if (le32_to_cpu(*qmap_enabled) == 5)
GetTLV( pBuffer, buffSize, 0x13, qmap_enabled, 4);
GetTLV( pBuffer, buffSize, 0x16, rx_size, 4);
GetTLV( pBuffer, buffSize, 0x18, tx_size, 4);
return pktLinkProtocol[0];
}
/*===========================================================================
METHOD:
QMICTLSyncResp (Public Method)
DESCRIPTION:
Validate the QMI CTL Sync Response
PARAMETERS
pBuffer [ I ] - Buffer to be parsed
buffSize [ I ] - Size of pBuffer
RETURN VALUE:
int - 0 for success
Negative errno for error
===========================================================================*/
static int QMICTLSyncResp(
void *pBuffer,
u16 buffSize )
{
int result;
// Ignore QMUX (2 bytes for QMI CTL) and SDU
u8 offset = sizeof( sQMUX ) + 2;
if (pBuffer == 0 || buffSize < offset)
{
return -ENOMEM;
}
pBuffer = pBuffer + offset;
buffSize -= offset;
result = GetQMIMessageID( pBuffer, buffSize );
if (result != 0x27)
{
return -EFAULT;
}
result = ValidQMIMessage( pBuffer, buffSize );
return result;
}
#endif