initial import of qmi_test.c reading out the device IMEI

This commit is contained in:
Harald Welte 2016-11-06 19:23:17 +01:00
commit 272f4318b5
3 changed files with 364 additions and 0 deletions

25
qmi/Makefile Normal file
View File

@ -0,0 +1,25 @@
ANDRO_VEND_QCOM_INC ?= $(HOME)/projects/git/android_vendor_qcom_proprietary
QMI_LIBDIR ?= $(HOME)/projects/kommerz/sysmocom/quectel/EC20/files/usr/lib
CROSS_COMPILE ?= arm-oe-linux-gnueabi-
QMI_CFLAGS := -I$(ANDRO_VEND_QCOM_INC)/qmi/inc -I$(ANDRO_VEND_QCOM_INC)/qmi/services -I$(ANDRO_VEND_QCOM_INC)/qmi/platform -I$(ANDRO_VEND_QCOM_INC)/qmi-framework/inc
QMI_LIBS := -L$(QMI_LIBDIR) -lqmi -lqmiservices -lqmi_cci
CFLAGS := $(QMI_CFLAGS) -Wno-unused-function -Wall
LDFLAGS := $(QMI_LIBS)
CFLAGS += $(EXTRA_CFLAGS)
all: qmi_test
qmi_test: qmi_test.o
$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $^ -o $@
clean:
rm -f *.o qmi_test
push: qmi_test
adb push qmi_test /cache/tmp/

276
qmi/qmi.txt Normal file
View File

@ -0,0 +1,276 @@
= Typicall Client App =
Typical client program would do:
* something like test_get_service_object_v01() to get the service
object
* qmi_client_notifier_init()
* qmi_client_get_service_list() to check if the service is up yet
* qmi_client_init(service_info, service_obj, qmi_client_ind_cb, ind_cb_data, os_params, user_handle)
to initialize the client
* main() loop
* qmi_client_release(client)
* qmi_client_release(notifier)
* qmi_client_init_instance(service_obj, instance_id, ind_cb, ind_cb_data, os_params, timeout, user_handle)
seems to be a convenience wrapper around qmi_client_get_service_list() and qmi_client_init()
== QMI (Qualcomm MSM Interface)
This is the general term for all related messaging between processors
and their software stacks on Qualcomm cellular processors.
== IDL
* int32_t qmi_idl_get_service_id(service_obj, service_id)
get service ID for a given service object
* qmi_idl_message_decode()
Decode from TLV to C structure
* qmi_idl_message_encode()
Encode from C structure to wire format TLV
=== IDL Structures
Individual services are implemented in a data-driven manner by data
structures describing the type of messsages and the message TLV
structure.
In the end, a service describes itself using the master structure
qmi_idl_service_object, consisting of
* library version (0x04)
* idl version
* service ID
* maximum message length
* number of command/response/indication messges in tables
* tables describing messages (qmi_idl_service_message_table_entry)
* tables describing types (qmi_idl_type_table_object)
The data structures describing a given service are generated by an IDL
compiler.
== CSI (Common Service Interface)
Data model (see qmi_csi_common.h for more info):
* each service list has a list of active services
* each service has a table of transports associated with it
* each service also has a list of connected clients
* each client has a pointer to the transport it connected from
* each client also has a list of outstanding transactions
CSI has only a single transport on Linux, using te AF_MSM_IPC type
sockets as a basis.
== SAP (Service Access Proxy)
Intended to export a service off-chip using QMUX daemon.
Encodes/Decodes messages for registering services:
* register_service request/response
* deregister_service request/response
* client_connect indication
* client_disconnect indication
== QMUX (QMI Multiplex)
The related code can either talk directly to the shared-memory devices
on Linux and thus the hardware (see qmi_platform_qmux_io.c).
It can however also establish a connection via a multiplex daemon.
This connection utilizes unix domain STREAM type sockets in
/dev/socket, specifically:
* /dev/socket/qmux_audio/qmux_{client,connect}_socket
* /dev/socket/qmux_bluetooth/qmux_{client,connect}_socket
* /dev/socket/qmux_radio/qmux_{client,connect}_socket
* /dev/socket/qmux_gps/qmux_{client,connect}_socket
* /var/qmux_{client,connect}_socket on non-android devices
== QCCI (QMI Common Client Interface)
The QCCI layer wraps QMI into the respective transport. The
transports supported are:
* IPC router (linux kernel socket family)
* QMUXD (using qmi_qmux_... API, via unix domain sockets)
* UDP packets (base port 10000)
The CCI API is what QMI clients normally would call to initiate a
client connection to a service. The CCI functions would then normally
be wrapped by some service specific code that wraps the IDL
definitions for message encoding/decoding and provides
service-specific API to the client.
== IPC (Inter Process Communications)
Qualcomm implements a socket-based inter process communication on
Linux. It is implemented usinga new address family, AF_MSM_IPC (27).
The socket is used as datagram type socket (SOCK_DGRAM).
The socket address of a related socket consists of:
* the socket family (AF_MSM_IPC)
* a struct msm_ipc_addr, consisting of
** a single address type byte
** a port address (node_id, port_id)
** a port name (service, instance)
== IRSC (IPC Router Security Control)
FIXME
== Shared Memory based Logging
There's a /dev/smem_log which can be opened and read from. It
supports some specific ioctl() to set binary mode.
More information in smem_log.h
== AT command implementation (QMI ATCOP service layer)
This is used by client programs to register AT command call-backs
within the modems AT command interpreter.
The QMI ATCOP service layer seems to be pre-IDL, as it doesn't have
the usual IDL compiler code structure.
=== qmi_atcop_fwd_at_urc_req()
used to send unsolicited response codes to modem
=== qmi_atcop_fwd_at_cmd_resp()
used by clien to send response to an AT command previously forwarded
to the client from the modem
=== qmi_atcop_reg_at_command_fwd_req()
used by client to registre any AT commands that need to be forwarded
to it from the modem
=== qmi_atcop_srvc_init_client()
intialization
=== qmi_atcop_srvc_release_client()
cleanup
== QMI Services (via IDL)
=== Test Service
Part of qmi-framework. IDL descriptions for
* ping req/resp
* test_ind
* data req/resp
* large_data req/resp
* data_ind_reg req/resp
* test_data_ind
* get_service_name req/resp
=== common_v01
* get_supported_msgs req/resp
* get_supported_fields req/resp
=== application_traffic_pairing_v01
=== card_application_toolkit_v02
SIM/USIM toolkint related
=== circuit_switched_video_telephony_v01
=== coexistence_manager_v01
bt/wifi coexistance?
=== control_service_v01
=== data_system_determination_v01
check for availability of wlan/modem/... data bearers and set related
policy
=== device_management_service_v01
* inquiry about device maker/model/version
* MSISDN, ICCID, IMSI, MAC address inquiry
* PIN entry/management
* locking
=== ip_multimedia_subsystem_application_v01
=== ip_multimedia_subsystem_dcm_v01
=== ip_multimedia_subsystem_presence_v01
=== ip_multimedia_subsystem_rtp_v01
=== ip_multimedia_subsystem_settings_v01
=== ip_multimedia_subsystem_video_telephony_v01
=== network_access_service_common_v01
=== network_access_service_v01
* network scan / registration
* network preference
* forbidden networks
* rf band information
* operator name
* rx diversity
=== persistent_device_configuration_v01
=== phonebook_manager_service_v01
=== qmi_adc_service_v01
* ADC conversion/calibration
=== qmi_ims_vt_v01
=== qualcomm_mobile_access_point_msgr_v01
=== qualcomm_mobile_access_point_v01
=== radio_frequency_radiated_performance_enhancement_v01
=== sar_vs_service_v01
=== specific_absorption_rate_v01
=== user_identity_module_remote_v01
APDU forwarding of SIM/USIM to remote location?
Probably more te opposite: A way how a modem can export a CCID device
towards a PC and then map the APDUs in something that the modem can
digest?
=== user_identity_module_v01
SIM/USIM card access
* read/write transparent / record EF
* verify / unblock / change pin
* card power up/down
* authenticate
* raw APDU
* SAP
* logicla channels
* ATR
* multi sim (slot) management
=== voice_service_common_v02
=== voice_service_v02
call control
=== wireless_data_administrative_service_v01
=== wireless_data_service_v01
cellular data
=== wireless_messaging_service_v01
SMS-PP, SMS-CB

63
qmi/qmi_test.c Normal file
View File

@ -0,0 +1,63 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <qmi_client.h>
#include <device_management_service_v01.h>
#include <network_access_service_v01.h>
static int g_qmi_handle = -1;
int main(int argc, char **argv)
{
qmi_client_type clnt, notifier;
qmi_cci_os_signal_type os_params;
qmi_idl_service_object_type dm_service_obj;
qmi_service_info info[10];
uint32_t num_services, num_entries = 0;
int rc;
g_qmi_handle = qmi_init(NULL, NULL);
if (g_qmi_handle < 0) {
fprintf(stderr, "qmi_init() failed: %d\n", g_qmi_handle);
exit(1);
}
dm_service_obj = dms_get_service_object_v01();
if (!dm_service_obj) {
fprintf(stderr, "Cannot get service object\n");
return -1;
}
rc = qmi_client_notifier_init(dm_service_obj, &os_params, &notifier);
/* wait for service and get number of services */
while (1) {
rc = qmi_client_get_service_list(dm_service_obj, NULL, NULL, &num_services);
if (rc == QMI_NO_ERR)
break;
printf("Waiting for service to become available...\n");
QMI_CCI_OS_SIGNAL_WAIT(&os_params, 0);
}
num_entries = num_services;
printf("%u services available\n", num_services);
/* obtain service info */
rc = qmi_client_get_service_list(dm_service_obj, info, &num_entries, &num_services);
printf("qmi_client_get_service_list() returned %d num_entries = %d num_services = %d\n", rc, num_entries, num_services);
rc = qmi_client_init(&info[0], dm_service_obj, NULL, NULL, NULL, &clnt);
printf("qmi_client_init() returned %d\n", rc);
/* FIXME: main */
dms_get_device_serial_numbers_resp_msg_v01 serno_resp;
rc = qmi_client_send_msg_sync(clnt, QMI_DMS_GET_DEVICE_SERIAL_NUMBERS_REQ_V01, NULL, 0, &serno_resp, sizeof(serno_resp), 0);
printf("qmi_client_send_msg_sync() returned %d\n", rc);
printf("IMEI IS %s\n", serno_resp.imei_valid ? serno_resp.imei : "invalid");
/* clean-up */
rc = qmi_client_release(clnt);
rc = qmi_client_release(notifier);
sleep(1);
exit(0);
}