All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Add SAP driver for ST-Ericsson U8500 platform
@ 2011-07-04 11:02 Szymon Janc
  2011-07-04 12:20 ` Anderson Lizardo
  0 siblings, 1 reply; 4+ messages in thread
From: Szymon Janc @ 2011-07-04 11:02 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: par-gunnar.p.hjalmdahl, ulrik.lauren, Szymon Janc

---
 Makefile.am     |    4 +-
 sap/sap-u8500.c |  717 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 719 insertions(+), 2 deletions(-)
 create mode 100644 sap/sap-u8500.c

diff --git a/Makefile.am b/Makefile.am
index 15216cd..68da65d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -161,7 +161,7 @@ builtin_nodist += sap/sap.c
 
 noinst_LIBRARIES = sap/libsap.a
 
-sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c
+sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c
 endif
 
 if INPUTPLUGIN
@@ -285,7 +285,7 @@ EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
 			input/input.conf serial/serial.conf \
 			audio/audio.conf audio/telephony-dummy.c \
 			audio/telephony-maemo5.c audio/telephony-ofono.c \
-			audio/telephony-maemo6.c sap/sap-dummy.c
+			audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c
 
 
 if ALSA
diff --git a/sap/sap-u8500.c b/sap/sap-u8500.c
new file mode 100644
index 0000000..f6026d9
--- /dev/null
+++ b/sap/sap-u8500.c
@@ -0,0 +1,717 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  SAP Driver for ST-Ericsson U8500 platform
+ *
+ *  Copyright (C) 2010-2011 ST-Ericsson SA
+ *
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for
+ *  ST-Ericsson.
+ *
+ *  This program 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; version 2 of the License.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "log.h"
+#include "sap.h"
+
+#define STE_SIMD_SOCK  "/dev/socket/catd_a"
+#define STE_CLIENT_TAG 0x0000
+
+#ifdef STE_SAP_DEBUG
+#define DBG_VERBOSE(fmt, arg...) DBG(fmt, arg)
+#else
+#define DBG_VERBOSE(fmt...)
+#endif
+
+#define sap_error(fmt, arg...) do { \
+	error("STE U8500 SAP: " fmt, ## arg); \
+	} while (0)
+
+#define sap_info(fmt, arg...) do { \
+	info("STE U8500 SAP: " fmt, ## arg); \
+	} while (0)
+
+struct ste_message {
+	uint16_t len;
+	uint16_t id;
+	uint32_t client_tag;
+	uint8_t payload[0];
+} __attribute__((packed));
+
+#define STE_MSG_PAYLOAD_SIZE(msg) (msg->len - sizeof(*msg) + sizeof(msg->len))
+
+enum ste_protocol {
+	STE_START_SAP_REQ	= 0x2D01,
+	STE_START_SAP_RSP	= 0x2E01,
+	STE_END_SAP_REQ		= 0x2D02,
+	STE_END_SAP_RSP		= 0x2E02,
+	STE_POWER_OFF_REQ	= 0x2D03,
+	STE_POWER_OFF_RSP	= 0x2E03,
+	STE_POWER_ON_REQ	= 0x2D04,
+	STE_POWER_ON_RSP	= 0x2E04,
+	STE_RESET_REQ		= 0x2D05,
+	STE_RESET_RSP		= 0x2E05,
+	STE_SEND_APDU_REQ	= 0x2D06,
+	STE_SEND_APDU_RSP	= 0x2E06,
+	STE_GET_ATR_REQ		= 0x2D07,
+	STE_GET_ATR_RSP		= 0x2E07,
+	STE_GET_STATUS_REQ	= 0x2D08,
+	STE_GET_STATUS_RSP	= 0x2E08,
+	STE_STATUS_IND		= 0x2F02
+};
+
+enum ste_msg {
+	STE_SEND_APDU_MSG,
+	STE_GET_ATR_MSG,
+	STE_POWER_OFF_MSG,
+	STE_POWER_ON_MSG,
+	STE_RESET_MSG,
+	STE_GET_STATUS_MSG,
+	STE_MSG_MAX,
+};
+
+enum ste_status {
+	STE_STATUS_OK		= 0x00000000,
+	STE_STATUS_FAILURE	= 0x00000001,
+};
+
+enum ste_card_status {
+	STE_CARD_STATUS_UNKNOWN		= 0x00,
+	STE_CARD_STATUS_ACTIVE		= 0x01,
+	STE_CARD_STATUS_NOT_ACTIVE	= 0x02,
+	STE_CARD_STATUS_MISSING		= 0x03,
+	STE_CARD_STATUS_INVALID		= 0x04,
+	STE_CARD_STATUS_DISCONNECTED	= 0x05,
+};
+
+/* Card reader status bits as described in GSM 11.14, Section 12.33
+ * Bits 0-2 are for card reader identity and always zeros. */
+#define ICC_READER_REMOVABLE	(1 << 3)
+#define ICC_READER_PRESENT	(1 << 4)
+#define ICC_READER_ID1		(1 << 5)
+#define ICC_READER_CARD_PRESENT	(1 << 6)
+#define ICC_READER_CARD_POWERED	(1 << 7)
+
+enum ste_state {
+	STE_DISABLED,		/* Reader not present or removed */
+	STE_POWERED_OFF,	/* Card in the reader but powered off */
+	STE_NO_CARD,		/* No card in the reader */
+	STE_ENABLED,		/* Card in the reader and powered on */
+	STE_STATE_MAX
+};
+
+struct ste_u8500 {
+	GIOChannel *io;
+	enum ste_state state;
+	void *sap_data;
+};
+
+typedef int(*recv_state_change_cb)(void *sap, uint8_t result);
+typedef int(*recv_pdu_cb)(void *sap, uint8_t result, uint8_t *data,
+								uint16_t len);
+
+static struct ste_u8500 u8500;
+
+static const uint8_t sim2sap_result[STE_MSG_MAX][STE_STATE_MAX] = {
+	/* SAP results for SEND APDU message */
+	{SAP_RESULT_ERROR_NOT_ACCESSIBLE,	/* for STE_DISABLED state */
+	 SAP_RESULT_ERROR_POWERED_OFF,		/* for STE_POWERED_OFF state */
+	 SAP_RESULT_ERROR_CARD_REMOVED,		/* for STE_NO_CARD state */
+	 SAP_RESULT_ERROR_NO_REASON},		/* for STE_ENABLED state */
+	 /* SAP results for GET_ATR message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_POWERED_OFF,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_NO_REASON},
+	 /* SAP results POWER OFF message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_POWERED_OFF,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_NO_REASON},
+	 /* SAP results POWER ON message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NOT_ACCESSIBLE,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_POWERED_ON},
+	 /* SAP results SIM RESET message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_POWERED_OFF,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_NOT_ACCESSIBLE},
+	 /* SAP results GET STATUS message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NO_REASON}
+	};
+
+static uint8_t get_sap_result(enum ste_msg msg, uint32_t status)
+{
+	if (!u8500.io)
+		return SAP_RESULT_ERROR_NO_REASON;
+
+	switch (status) {
+	case STE_STATUS_OK:
+		return SAP_RESULT_OK;
+
+	case STE_STATUS_FAILURE:
+		return sim2sap_result[msg][u8500.state];
+
+	default:
+		DBG("Can't convert a result (status %u)", status);
+		return SAP_RESULT_ERROR_NO_REASON;
+	}
+}
+
+static int get_sap_reader_status(uint32_t card_status, uint8_t *icc_status)
+{
+	/* Card reader is present, not removable and not ID-1 size. */
+	*icc_status = ICC_READER_PRESENT;
+
+	switch (card_status) {
+	case STE_CARD_STATUS_ACTIVE:
+		*icc_status |= ICC_READER_CARD_POWERED;
+
+	case STE_CARD_STATUS_NOT_ACTIVE:
+	case STE_CARD_STATUS_INVALID:
+		*icc_status |= ICC_READER_CARD_PRESENT;
+
+	case STE_CARD_STATUS_MISSING:
+	case STE_CARD_STATUS_DISCONNECTED:
+		return 0;
+
+	default:
+		DBG("Can't convert reader status %u", card_status);
+
+	case STE_CARD_STATUS_UNKNOWN:
+		return -1;
+	}
+}
+
+static uint8_t get_sap_status_change(uint32_t card_status)
+{
+	if (!u8500.io)
+		return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+	switch (card_status) {
+	case STE_CARD_STATUS_UNKNOWN:
+		return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+	case STE_CARD_STATUS_ACTIVE:
+		u8500.state = STE_ENABLED;
+		return SAP_STATUS_CHANGE_CARD_RESET;
+
+	case STE_CARD_STATUS_NOT_ACTIVE:
+		u8500.state = STE_DISABLED;
+		return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+	case STE_CARD_STATUS_MISSING:
+		u8500.state = STE_DISABLED;
+		return SAP_STATUS_CHANGE_CARD_REMOVED;
+
+	case STE_CARD_STATUS_INVALID:
+		u8500.state = STE_DISABLED;
+		return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+	default:
+		DBG("Can't convert status change %u", card_status);
+		return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+	}
+}
+
+static int send_message(GIOChannel *io, void *buf, size_t size)
+{
+	gsize written;
+	GError *gerr = NULL;
+	GIOStatus gstatus;
+
+	DBG_VERBOSE("io %p, size %zu", io, size);
+
+	gstatus = g_io_channel_write_chars(io, buf, size, &written, &gerr);
+	if (gstatus != G_IO_STATUS_NORMAL) {
+		if (gerr)
+			g_error_free(gerr);
+		return -EIO;
+	}
+
+	return written;
+}
+
+static int send_request(GIOChannel *io, uint16_t id,
+						struct sap_parameter *param)
+{
+	int ret;
+	struct ste_message *msg;
+	size_t size = sizeof(*msg);
+
+	DBG_VERBOSE("io %p", io);
+
+	if (param)
+		size += param->len;
+
+	msg = g_try_malloc0(size);
+	if (!msg) {
+		sap_error("sending request failed: %s", strerror(ENOMEM));
+		return -ENOMEM;
+	}
+
+	msg->len = size - sizeof(msg->len);
+	msg->id = id;
+	msg->client_tag = STE_CLIENT_TAG;
+
+	if (param)
+		memcpy(msg->payload, param->val, param->len);
+
+	ret = send_message(io, msg, size);
+	if (ret < 0) {
+		sap_error("sending request failed: %s", strerror(-ret));
+	} else if (ret != (int) size) {
+		sap_error("sending request failed: %d out of %zu bytes sent",
+								ret, size);
+		ret = -EIO;
+	}
+
+	g_free(msg);
+
+	return ret;
+}
+
+static void recv_status(uint32_t status)
+{
+	sap_status_ind(u8500.sap_data, get_sap_status_change(status));
+}
+
+static void recv_card_status(uint32_t status, uint8_t *param)
+{
+	uint32_t *card_status;
+	uint8_t result;
+	uint8_t iccrs;
+
+	if (status != STE_STATUS_OK)
+		return;
+
+	card_status = (uint32_t *)param;
+
+	if (get_sap_reader_status(*card_status, &iccrs) < 0)
+		result = SAP_RESULT_ERROR_NO_REASON;
+	else
+		result = get_sap_result(STE_GET_STATUS_MSG, status);
+
+	sap_transfer_card_reader_status_rsp(u8500.sap_data, result, iccrs);
+}
+
+static void recv_state_change(uint32_t ste_msg, uint32_t status,
+			uint32_t new_state, recv_state_change_cb callback)
+{
+	if (status != STE_STATUS_OK)
+		return;
+
+	u8500.state = new_state;
+
+	if (callback)
+		callback(u8500.sap_data, get_sap_result(ste_msg, status));
+}
+
+static void recv_pdu(uint32_t ste_msg, struct ste_message *msg, uint32_t status,
+					uint8_t *param, recv_pdu_cb callback)
+{
+	uint8_t *data = NULL;
+	uint8_t result;
+	int size = 0;
+
+	if (status == STE_STATUS_OK) {
+		data = param;
+		size = STE_MSG_PAYLOAD_SIZE(msg) - sizeof(status);
+	}
+
+	result = get_sap_result(ste_msg, status);
+
+	if (callback)
+		callback(u8500.sap_data, result, data, size);
+}
+
+static void simd_close(void)
+{
+	DBG("io %p", u8500.io);
+
+	if (u8500.io) {
+		g_io_channel_shutdown(u8500.io, TRUE, NULL);
+		g_io_channel_unref(u8500.io);
+	}
+
+	u8500.state = STE_DISABLED;
+	u8500.io = NULL;
+	u8500.sap_data = NULL;
+}
+
+static void recv_response(struct ste_message *msg)
+{
+	uint32_t status;
+	uint8_t *param;
+
+	DBG_VERBOSE("msg_id 0x%x", msg->id);
+
+	if (msg->id == STE_END_SAP_RSP) {
+		sap_disconnect_rsp(u8500.sap_data);
+		simd_close();
+		return;
+	}
+
+	param = msg->payload;
+	status = *(uint32_t *)param;
+	param += sizeof(status);
+
+	DBG_VERBOSE("status 0x%x", status);
+
+	switch (msg->id) {
+	case STE_START_SAP_RSP:
+		if (status == STE_STATUS_OK) {
+			sap_connect_rsp(u8500.sap_data, SAP_STATUS_OK, 0);
+		} else {
+			sap_connect_rsp(u8500.sap_data,
+					SAP_STATUS_CONNECTION_FAILED, 0);
+			simd_close();
+		}
+		break;
+
+	case STE_SEND_APDU_RSP:
+		recv_pdu(STE_SEND_APDU_MSG, msg, status, param,
+							sap_transfer_apdu_rsp);
+		break;
+
+	case STE_GET_ATR_RSP:
+		recv_pdu(STE_GET_ATR_MSG, msg, status, param,
+							sap_transfer_atr_rsp);
+		break;
+
+	case STE_POWER_OFF_RSP:
+		recv_state_change(STE_POWER_OFF_MSG, status, STE_POWERED_OFF,
+							sap_power_sim_off_rsp);
+		break;
+
+	case STE_POWER_ON_RSP:
+		recv_state_change(STE_POWER_ON_MSG, status, STE_ENABLED,
+							sap_power_sim_on_rsp);
+		break;
+
+	case STE_RESET_RSP:
+		recv_state_change(STE_RESET_MSG, status, STE_ENABLED,
+							sap_reset_sim_rsp);
+		break;
+
+	case STE_GET_STATUS_RSP:
+		recv_card_status(status, param);
+		break;
+
+	case STE_STATUS_IND:
+		recv_status(status);
+		break;
+
+	default:
+		sap_error("unsupported message received (id 0x%x)", msg->id);
+	}
+}
+
+static int recv_message(void *buf, size_t size)
+{
+	uint8_t *iter = buf;
+	struct ste_message *msg = buf;
+
+	do {
+		DBG_VERBOSE("size %zu msg->len %u.", size, msg->len);
+
+		if (size < sizeof(*msg)) {
+			sap_error("invalid message received (%zu bytes)", size);
+			return -EBADMSG;
+		}
+
+		/* Message must be complete. */
+		if (size < (msg->len + sizeof(msg->len))) {
+			sap_error("incomplete message received (%zu bytes)",
+									size);
+			return -EBADMSG;
+		}
+
+		recv_response(msg);
+
+		/* Reduce total buffer size by just handled frame size. */
+		size -= msg->len + sizeof(msg->len);
+
+		/* Move msg pointer to the next message if any. */
+		iter += msg->len + sizeof(msg->len);
+		msg = (struct ste_message *)iter;
+	} while (size > 0);
+
+	return 0;
+}
+
+static gboolean simd_data_cb(GIOChannel *io, GIOCondition cond, gpointer data)
+{
+	GError *gerr = NULL;
+	char buf[SAP_BUF_SIZE];
+	gsize bytes_read;
+	GIOStatus gstatus;
+
+	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+		DBG("Error condition on sim socket (0x%x)", cond);
+		return FALSE;
+	}
+
+	gstatus = g_io_channel_read_chars(io, buf, sizeof(buf), &bytes_read,
+									&gerr);
+	if (gstatus != G_IO_STATUS_NORMAL) {
+		if (gerr)
+			g_error_free(gerr);
+
+		sap_error("error while reading from channel (%d)", gstatus);
+		return TRUE;
+	}
+
+	if (recv_message(buf, bytes_read) < 0)
+		sap_error("error while parsing STE Sim message");
+
+	return TRUE;
+}
+
+static void simd_watch(int sock, void *sap_data)
+{
+	GIOChannel *io;
+
+	DBG("sock %d, sap_data %p ", sock, sap_data);
+
+	io = g_io_channel_unix_new(sock);
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+	g_io_channel_set_encoding(io, NULL, NULL);
+	g_io_channel_set_buffered(io, FALSE);
+
+	u8500.io = io;
+	u8500.sap_data = sap_data;
+	u8500.state = STE_DISABLED;
+
+	g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			simd_data_cb, NULL, NULL);
+}
+
+static int simd_connect(void *sap_data)
+{
+	struct sockaddr_un addr;
+	int sock;
+	int err;
+
+	/* Already connected to simd */
+	if (u8500.io)
+		return -EALREADY;
+
+	sock = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		err = errno;
+		sap_error("creating socket failed: %s", strerror(err));
+		return -err;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	memcpy(addr.sun_path, STE_SIMD_SOCK, sizeof(STE_SIMD_SOCK) - 1);
+
+	if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = errno;
+		sap_error("connect to the socket failed: %s", strerror(err));
+		goto failed;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) > 0) {
+		err = errno;
+		sap_error("setting up socket failed: %s", strerror(err));
+		goto failed;
+	}
+
+	simd_watch(sock, sap_data);
+
+	return 0;
+
+failed:
+	close(sock);
+	return -err;
+}
+
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+	DBG("sap_device %p maxmsgsize %u", sap_device, maxmsgsize);
+
+	sap_info("connect request");
+
+	if (simd_connect(sap_device) < 0) {
+		sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_START_SAP_REQ, NULL) < 0) {
+		sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+								SAP_BUF_SIZE);
+		simd_close();
+	}
+}
+
+void sap_disconnect_req(void *sap_device, uint8_t linkloss)
+{
+	DBG("sap_device %p linkloss %u", sap_device, linkloss);
+
+	sap_info("disconnect request %s", linkloss ? "by link loss" : "");
+
+	if (u8500.state == STE_DISABLED) {
+		sap_disconnect_rsp(sap_device);
+		simd_close();
+		return;
+	}
+
+	if (linkloss) {
+		simd_close();
+		return;
+	}
+
+	if (send_request(u8500.io, STE_END_SAP_REQ, NULL) < 0) {
+		sap_disconnect_rsp(sap_device);
+		return;
+	}
+}
+
+void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
+{
+	uint8_t result;
+
+	DBG_VERBOSE("sap_device %p param %p", sap_device, param);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_SEND_APDU_MSG, STE_STATUS_FAILURE);
+		sap_transfer_apdu_rsp(sap_device, result, NULL, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_SEND_APDU_REQ, param) < 0)
+		sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_NO_DATA,
+								NULL, 0);
+}
+
+void sap_transfer_atr_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_GET_ATR_MSG, STE_STATUS_FAILURE);
+		sap_transfer_atr_rsp(sap_device, result, NULL, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_GET_ATR_REQ, NULL) < 0)
+		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_DATA, NULL,
+									0);
+}
+
+void sap_power_sim_off_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_POWER_OFF_MSG, STE_STATUS_FAILURE);
+		sap_power_sim_off_rsp(sap_device, result);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_POWER_OFF_REQ, NULL) < 0)
+		sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_power_sim_on_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_POWERED_OFF) {
+		result = get_sap_result(STE_POWER_ON_MSG, STE_STATUS_FAILURE);
+		sap_power_sim_on_rsp(sap_device, result);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_POWER_ON_REQ, NULL) < 0)
+		sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_reset_sim_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_RESET_MSG, STE_STATUS_FAILURE);
+		sap_reset_sim_rsp(sap_device, result);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_RESET_REQ, NULL) < 0)
+		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_transfer_card_reader_status_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state == STE_DISABLED) {
+		result = get_sap_result(STE_GET_STATUS_MSG, STE_STATUS_FAILURE);
+		sap_transfer_card_reader_status_rsp(sap_device, result, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_GET_STATUS_REQ, NULL) < 0)
+		sap_transfer_card_reader_status_rsp(sap_device,
+						SAP_RESULT_ERROR_NO_DATA, 0);
+}
+
+void sap_set_transport_protocol_req(void *sap_device,
+						struct sap_parameter *param)
+{
+	DBG("sap_device %p", sap_device);
+
+	sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
+}
+
+int sap_init(void)
+{
+	u8500.state = STE_DISABLED;
+	info("STE U8500 SAP driver initialized");
+	return 0;
+}
+
+void sap_exit(void)
+{
+}
-- 
on behalf of ST-Ericsson


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add SAP driver for ST-Ericsson U8500 platform
  2011-07-04 11:02 [PATCH] Add SAP driver for ST-Ericsson U8500 platform Szymon Janc
@ 2011-07-04 12:20 ` Anderson Lizardo
  2011-07-05 10:03   ` [PATCH v2] " Szymon Janc
  0 siblings, 1 reply; 4+ messages in thread
From: Anderson Lizardo @ 2011-07-04 12:20 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth, par-gunnar.p.hjalmdahl, ulrik.lauren

Hi Szymon,

On Mon, Jul 4, 2011 at 7:02 AM, Szymon Janc <szymon.janc@tieto.com> wrote:
> +       gstatus = g_io_channel_read_chars(io, buf, sizeof(buf), &bytes_read,
> +                                                                       &gerr);
> +       if (gstatus != G_IO_STATUS_NORMAL) {
> +               if (gerr)
> +                       g_error_free(gerr);
> +
> +               sap_error("error while reading from channel (%d)", gstatus);
> +               return TRUE;
> +       }

You can pass NULL to the last argument of g_io_channel_read_chars() if
you are not using the gerr (as in the case above).

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2] Add SAP driver for ST-Ericsson U8500 platform
  2011-07-04 12:20 ` Anderson Lizardo
@ 2011-07-05 10:03   ` Szymon Janc
  2011-07-13  8:53     ` Johan Hedberg
  0 siblings, 1 reply; 4+ messages in thread
From: Szymon Janc @ 2011-07-05 10:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: par-gunnar.p.hjalmdahl, ulrik.lauren, Szymon Janc

---
 Makefile.am     |    4 +-
 sap/sap-u8500.c |  708 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 710 insertions(+), 2 deletions(-)
 create mode 100644 sap/sap-u8500.c

diff --git a/Makefile.am b/Makefile.am
index 15216cd..68da65d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -161,7 +161,7 @@ builtin_nodist += sap/sap.c
 
 noinst_LIBRARIES = sap/libsap.a
 
-sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c
+sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c
 endif
 
 if INPUTPLUGIN
@@ -285,7 +285,7 @@ EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
 			input/input.conf serial/serial.conf \
 			audio/audio.conf audio/telephony-dummy.c \
 			audio/telephony-maemo5.c audio/telephony-ofono.c \
-			audio/telephony-maemo6.c sap/sap-dummy.c
+			audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c
 
 
 if ALSA
diff --git a/sap/sap-u8500.c b/sap/sap-u8500.c
new file mode 100644
index 0000000..65c65af
--- /dev/null
+++ b/sap/sap-u8500.c
@@ -0,0 +1,708 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  SAP Driver for ST-Ericsson U8500 platform
+ *
+ *  Copyright (C) 2010-2011 ST-Ericsson SA
+ *
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for
+ *  ST-Ericsson.
+ *
+ *  This program 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; version 2 of the License.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "log.h"
+#include "sap.h"
+
+#define STE_SIMD_SOCK  "/dev/socket/catd_a"
+#define STE_CLIENT_TAG 0x0000
+
+#ifdef STE_SAP_DEBUG
+#define DBG_VERBOSE(fmt, arg...) DBG(fmt, arg)
+#else
+#define DBG_VERBOSE(fmt...)
+#endif
+
+#define sap_error(fmt, arg...) do { \
+	error("STE U8500 SAP: " fmt, ## arg); \
+	} while (0)
+
+#define sap_info(fmt, arg...) do { \
+	info("STE U8500 SAP: " fmt, ## arg); \
+	} while (0)
+
+struct ste_message {
+	uint16_t len;
+	uint16_t id;
+	uint32_t client_tag;
+	uint8_t payload[0];
+} __attribute__((packed));
+
+#define STE_MSG_PAYLOAD_SIZE(msg) (msg->len - sizeof(*msg) + sizeof(msg->len))
+
+enum ste_protocol {
+	STE_START_SAP_REQ	= 0x2D01,
+	STE_START_SAP_RSP	= 0x2E01,
+	STE_END_SAP_REQ		= 0x2D02,
+	STE_END_SAP_RSP		= 0x2E02,
+	STE_POWER_OFF_REQ	= 0x2D03,
+	STE_POWER_OFF_RSP	= 0x2E03,
+	STE_POWER_ON_REQ	= 0x2D04,
+	STE_POWER_ON_RSP	= 0x2E04,
+	STE_RESET_REQ		= 0x2D05,
+	STE_RESET_RSP		= 0x2E05,
+	STE_SEND_APDU_REQ	= 0x2D06,
+	STE_SEND_APDU_RSP	= 0x2E06,
+	STE_GET_ATR_REQ		= 0x2D07,
+	STE_GET_ATR_RSP		= 0x2E07,
+	STE_GET_STATUS_REQ	= 0x2D08,
+	STE_GET_STATUS_RSP	= 0x2E08,
+	STE_STATUS_IND		= 0x2F02
+};
+
+enum ste_msg {
+	STE_SEND_APDU_MSG,
+	STE_GET_ATR_MSG,
+	STE_POWER_OFF_MSG,
+	STE_POWER_ON_MSG,
+	STE_RESET_MSG,
+	STE_GET_STATUS_MSG,
+	STE_MSG_MAX,
+};
+
+enum ste_status {
+	STE_STATUS_OK		= 0x00000000,
+	STE_STATUS_FAILURE	= 0x00000001,
+};
+
+enum ste_card_status {
+	STE_CARD_STATUS_UNKNOWN		= 0x00,
+	STE_CARD_STATUS_ACTIVE		= 0x01,
+	STE_CARD_STATUS_NOT_ACTIVE	= 0x02,
+	STE_CARD_STATUS_MISSING		= 0x03,
+	STE_CARD_STATUS_INVALID		= 0x04,
+	STE_CARD_STATUS_DISCONNECTED	= 0x05,
+};
+
+/* Card reader status bits as described in GSM 11.14, Section 12.33
+ * Bits 0-2 are for card reader identity and always zeros. */
+#define ICC_READER_REMOVABLE	(1 << 3)
+#define ICC_READER_PRESENT	(1 << 4)
+#define ICC_READER_ID1		(1 << 5)
+#define ICC_READER_CARD_PRESENT	(1 << 6)
+#define ICC_READER_CARD_POWERED	(1 << 7)
+
+enum ste_state {
+	STE_DISABLED,		/* Reader not present or removed */
+	STE_POWERED_OFF,	/* Card in the reader but powered off */
+	STE_NO_CARD,		/* No card in the reader */
+	STE_ENABLED,		/* Card in the reader and powered on */
+	STE_STATE_MAX
+};
+
+struct ste_u8500 {
+	GIOChannel *io;
+	enum ste_state state;
+	void *sap_data;
+};
+
+typedef int(*recv_state_change_cb)(void *sap, uint8_t result);
+typedef int(*recv_pdu_cb)(void *sap, uint8_t result, uint8_t *data,
+								uint16_t len);
+
+static struct ste_u8500 u8500;
+
+static const uint8_t sim2sap_result[STE_MSG_MAX][STE_STATE_MAX] = {
+	/* SAP results for SEND APDU message */
+	{SAP_RESULT_ERROR_NOT_ACCESSIBLE,	/* for STE_DISABLED state */
+	 SAP_RESULT_ERROR_POWERED_OFF,		/* for STE_POWERED_OFF state */
+	 SAP_RESULT_ERROR_CARD_REMOVED,		/* for STE_NO_CARD state */
+	 SAP_RESULT_ERROR_NO_REASON},		/* for STE_ENABLED state */
+	 /* SAP results for GET_ATR message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_POWERED_OFF,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_NO_REASON},
+	 /* SAP results POWER OFF message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_POWERED_OFF,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_NO_REASON},
+	 /* SAP results POWER ON message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NOT_ACCESSIBLE,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_POWERED_ON},
+	 /* SAP results SIM RESET message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_POWERED_OFF,
+	 SAP_RESULT_ERROR_CARD_REMOVED,
+	 SAP_RESULT_ERROR_NOT_ACCESSIBLE},
+	 /* SAP results GET STATUS message */
+	{SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NO_REASON,
+	 SAP_RESULT_ERROR_NO_REASON}
+	};
+
+static uint8_t get_sap_result(enum ste_msg msg, uint32_t status)
+{
+	if (!u8500.io)
+		return SAP_RESULT_ERROR_NO_REASON;
+
+	switch (status) {
+	case STE_STATUS_OK:
+		return SAP_RESULT_OK;
+
+	case STE_STATUS_FAILURE:
+		return sim2sap_result[msg][u8500.state];
+
+	default:
+		DBG("Can't convert a result (status %u)", status);
+		return SAP_RESULT_ERROR_NO_REASON;
+	}
+}
+
+static int get_sap_reader_status(uint32_t card_status, uint8_t *icc_status)
+{
+	/* Card reader is present, not removable and not ID-1 size. */
+	*icc_status = ICC_READER_PRESENT;
+
+	switch (card_status) {
+	case STE_CARD_STATUS_ACTIVE:
+		*icc_status |= ICC_READER_CARD_POWERED;
+
+	case STE_CARD_STATUS_NOT_ACTIVE:
+	case STE_CARD_STATUS_INVALID:
+		*icc_status |= ICC_READER_CARD_PRESENT;
+
+	case STE_CARD_STATUS_MISSING:
+	case STE_CARD_STATUS_DISCONNECTED:
+		return 0;
+
+	default:
+		DBG("Can't convert reader status %u", card_status);
+
+	case STE_CARD_STATUS_UNKNOWN:
+		return -1;
+	}
+}
+
+static uint8_t get_sap_status_change(uint32_t card_status)
+{
+	if (!u8500.io)
+		return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+	switch (card_status) {
+	case STE_CARD_STATUS_UNKNOWN:
+		return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+	case STE_CARD_STATUS_ACTIVE:
+		u8500.state = STE_ENABLED;
+		return SAP_STATUS_CHANGE_CARD_RESET;
+
+	case STE_CARD_STATUS_NOT_ACTIVE:
+		u8500.state = STE_DISABLED;
+		return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+	case STE_CARD_STATUS_MISSING:
+		u8500.state = STE_DISABLED;
+		return SAP_STATUS_CHANGE_CARD_REMOVED;
+
+	case STE_CARD_STATUS_INVALID:
+		u8500.state = STE_DISABLED;
+		return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+	default:
+		DBG("Can't convert status change %u", card_status);
+		return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+	}
+}
+
+static int send_message(GIOChannel *io, void *buf, size_t size)
+{
+	gsize written;
+
+	DBG_VERBOSE("io %p, size %zu", io, size);
+
+	if (g_io_channel_write_chars(io, buf, size, &written, NULL) !=
+							G_IO_STATUS_NORMAL)
+		return -EIO;
+
+	return written;
+}
+
+static int send_request(GIOChannel *io, uint16_t id,
+						struct sap_parameter *param)
+{
+	int ret;
+	struct ste_message *msg;
+	size_t size = sizeof(*msg);
+
+	DBG_VERBOSE("io %p", io);
+
+	if (param)
+		size += param->len;
+
+	msg = g_try_malloc0(size);
+	if (!msg) {
+		sap_error("sending request failed: %s", strerror(ENOMEM));
+		return -ENOMEM;
+	}
+
+	msg->len = size - sizeof(msg->len);
+	msg->id = id;
+	msg->client_tag = STE_CLIENT_TAG;
+
+	if (param)
+		memcpy(msg->payload, param->val, param->len);
+
+	ret = send_message(io, msg, size);
+	if (ret < 0) {
+		sap_error("sending request failed: %s", strerror(-ret));
+	} else if (ret != (int) size) {
+		sap_error("sending request failed: %d out of %zu bytes sent",
+								ret, size);
+		ret = -EIO;
+	}
+
+	g_free(msg);
+
+	return ret;
+}
+
+static void recv_status(uint32_t status)
+{
+	sap_status_ind(u8500.sap_data, get_sap_status_change(status));
+}
+
+static void recv_card_status(uint32_t status, uint8_t *param)
+{
+	uint32_t *card_status;
+	uint8_t result;
+	uint8_t iccrs;
+
+	if (status != STE_STATUS_OK)
+		return;
+
+	card_status = (uint32_t *)param;
+
+	if (get_sap_reader_status(*card_status, &iccrs) < 0)
+		result = SAP_RESULT_ERROR_NO_REASON;
+	else
+		result = get_sap_result(STE_GET_STATUS_MSG, status);
+
+	sap_transfer_card_reader_status_rsp(u8500.sap_data, result, iccrs);
+}
+
+static void recv_state_change(uint32_t ste_msg, uint32_t status,
+			uint32_t new_state, recv_state_change_cb callback)
+{
+	if (status != STE_STATUS_OK)
+		return;
+
+	u8500.state = new_state;
+
+	if (callback)
+		callback(u8500.sap_data, get_sap_result(ste_msg, status));
+}
+
+static void recv_pdu(uint32_t ste_msg, struct ste_message *msg, uint32_t status,
+					uint8_t *param, recv_pdu_cb callback)
+{
+	uint8_t *data = NULL;
+	uint8_t result;
+	int size = 0;
+
+	if (status == STE_STATUS_OK) {
+		data = param;
+		size = STE_MSG_PAYLOAD_SIZE(msg) - sizeof(status);
+	}
+
+	result = get_sap_result(ste_msg, status);
+
+	if (callback)
+		callback(u8500.sap_data, result, data, size);
+}
+
+static void simd_close(void)
+{
+	DBG("io %p", u8500.io);
+
+	if (u8500.io) {
+		g_io_channel_shutdown(u8500.io, TRUE, NULL);
+		g_io_channel_unref(u8500.io);
+	}
+
+	u8500.state = STE_DISABLED;
+	u8500.io = NULL;
+	u8500.sap_data = NULL;
+}
+
+static void recv_response(struct ste_message *msg)
+{
+	uint32_t status;
+	uint8_t *param;
+
+	DBG_VERBOSE("msg_id 0x%x", msg->id);
+
+	if (msg->id == STE_END_SAP_RSP) {
+		sap_disconnect_rsp(u8500.sap_data);
+		simd_close();
+		return;
+	}
+
+	param = msg->payload;
+	status = *(uint32_t *)param;
+	param += sizeof(status);
+
+	DBG_VERBOSE("status 0x%x", status);
+
+	switch (msg->id) {
+	case STE_START_SAP_RSP:
+		if (status == STE_STATUS_OK) {
+			sap_connect_rsp(u8500.sap_data, SAP_STATUS_OK, 0);
+		} else {
+			sap_connect_rsp(u8500.sap_data,
+					SAP_STATUS_CONNECTION_FAILED, 0);
+			simd_close();
+		}
+		break;
+
+	case STE_SEND_APDU_RSP:
+		recv_pdu(STE_SEND_APDU_MSG, msg, status, param,
+							sap_transfer_apdu_rsp);
+		break;
+
+	case STE_GET_ATR_RSP:
+		recv_pdu(STE_GET_ATR_MSG, msg, status, param,
+							sap_transfer_atr_rsp);
+		break;
+
+	case STE_POWER_OFF_RSP:
+		recv_state_change(STE_POWER_OFF_MSG, status, STE_POWERED_OFF,
+							sap_power_sim_off_rsp);
+		break;
+
+	case STE_POWER_ON_RSP:
+		recv_state_change(STE_POWER_ON_MSG, status, STE_ENABLED,
+							sap_power_sim_on_rsp);
+		break;
+
+	case STE_RESET_RSP:
+		recv_state_change(STE_RESET_MSG, status, STE_ENABLED,
+							sap_reset_sim_rsp);
+		break;
+
+	case STE_GET_STATUS_RSP:
+		recv_card_status(status, param);
+		break;
+
+	case STE_STATUS_IND:
+		recv_status(status);
+		break;
+
+	default:
+		sap_error("unsupported message received (id 0x%x)", msg->id);
+	}
+}
+
+static int recv_message(void *buf, size_t size)
+{
+	uint8_t *iter = buf;
+	struct ste_message *msg = buf;
+
+	do {
+		DBG_VERBOSE("size %zu msg->len %u.", size, msg->len);
+
+		if (size < sizeof(*msg)) {
+			sap_error("invalid message received (%zu bytes)", size);
+			return -EBADMSG;
+		}
+
+		/* Message must be complete. */
+		if (size < (msg->len + sizeof(msg->len))) {
+			sap_error("incomplete message received (%zu bytes)",
+									size);
+			return -EBADMSG;
+		}
+
+		recv_response(msg);
+
+		/* Reduce total buffer size by just handled frame size. */
+		size -= msg->len + sizeof(msg->len);
+
+		/* Move msg pointer to the next message if any. */
+		iter += msg->len + sizeof(msg->len);
+		msg = (struct ste_message *)iter;
+	} while (size > 0);
+
+	return 0;
+}
+
+static gboolean simd_data_cb(GIOChannel *io, GIOCondition cond, gpointer data)
+{
+	char buf[SAP_BUF_SIZE];
+	gsize bytes_read;
+	GIOStatus gstatus;
+
+	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+		DBG("Error condition on sim socket (0x%x)", cond);
+		return FALSE;
+	}
+
+	gstatus = g_io_channel_read_chars(io, buf, sizeof(buf), &bytes_read,
+									NULL);
+	if (gstatus != G_IO_STATUS_NORMAL) {
+		sap_error("error while reading from channel (%d)", gstatus);
+		return TRUE;
+	}
+
+	if (recv_message(buf, bytes_read) < 0)
+		sap_error("error while parsing STE Sim message");
+
+	return TRUE;
+}
+
+static void simd_watch(int sock, void *sap_data)
+{
+	GIOChannel *io;
+
+	DBG("sock %d, sap_data %p ", sock, sap_data);
+
+	io = g_io_channel_unix_new(sock);
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+	g_io_channel_set_encoding(io, NULL, NULL);
+	g_io_channel_set_buffered(io, FALSE);
+
+	u8500.io = io;
+	u8500.sap_data = sap_data;
+	u8500.state = STE_DISABLED;
+
+	g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			simd_data_cb, NULL, NULL);
+}
+
+static int simd_connect(void *sap_data)
+{
+	struct sockaddr_un addr;
+	int sock;
+	int err;
+
+	/* Already connected to simd */
+	if (u8500.io)
+		return -EALREADY;
+
+	sock = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		err = errno;
+		sap_error("creating socket failed: %s", strerror(err));
+		return -err;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	memcpy(addr.sun_path, STE_SIMD_SOCK, sizeof(STE_SIMD_SOCK) - 1);
+
+	if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = errno;
+		sap_error("connect to the socket failed: %s", strerror(err));
+		goto failed;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) > 0) {
+		err = errno;
+		sap_error("setting up socket failed: %s", strerror(err));
+		goto failed;
+	}
+
+	simd_watch(sock, sap_data);
+
+	return 0;
+
+failed:
+	close(sock);
+	return -err;
+}
+
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+	DBG("sap_device %p maxmsgsize %u", sap_device, maxmsgsize);
+
+	sap_info("connect request");
+
+	if (simd_connect(sap_device) < 0) {
+		sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_START_SAP_REQ, NULL) < 0) {
+		sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+								SAP_BUF_SIZE);
+		simd_close();
+	}
+}
+
+void sap_disconnect_req(void *sap_device, uint8_t linkloss)
+{
+	DBG("sap_device %p linkloss %u", sap_device, linkloss);
+
+	sap_info("disconnect request %s", linkloss ? "by link loss" : "");
+
+	if (u8500.state == STE_DISABLED) {
+		sap_disconnect_rsp(sap_device);
+		simd_close();
+		return;
+	}
+
+	if (linkloss) {
+		simd_close();
+		return;
+	}
+
+	if (send_request(u8500.io, STE_END_SAP_REQ, NULL) < 0) {
+		sap_disconnect_rsp(sap_device);
+		return;
+	}
+}
+
+void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
+{
+	uint8_t result;
+
+	DBG_VERBOSE("sap_device %p param %p", sap_device, param);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_SEND_APDU_MSG, STE_STATUS_FAILURE);
+		sap_transfer_apdu_rsp(sap_device, result, NULL, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_SEND_APDU_REQ, param) < 0)
+		sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_NO_DATA,
+								NULL, 0);
+}
+
+void sap_transfer_atr_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_GET_ATR_MSG, STE_STATUS_FAILURE);
+		sap_transfer_atr_rsp(sap_device, result, NULL, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_GET_ATR_REQ, NULL) < 0)
+		sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_DATA, NULL,
+									0);
+}
+
+void sap_power_sim_off_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_POWER_OFF_MSG, STE_STATUS_FAILURE);
+		sap_power_sim_off_rsp(sap_device, result);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_POWER_OFF_REQ, NULL) < 0)
+		sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_power_sim_on_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_POWERED_OFF) {
+		result = get_sap_result(STE_POWER_ON_MSG, STE_STATUS_FAILURE);
+		sap_power_sim_on_rsp(sap_device, result);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_POWER_ON_REQ, NULL) < 0)
+		sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_reset_sim_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state != STE_ENABLED) {
+		result = get_sap_result(STE_RESET_MSG, STE_STATUS_FAILURE);
+		sap_reset_sim_rsp(sap_device, result);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_RESET_REQ, NULL) < 0)
+		sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_transfer_card_reader_status_req(void *sap_device)
+{
+	uint8_t result;
+
+	DBG("sap_device %p", sap_device);
+
+	if (u8500.state == STE_DISABLED) {
+		result = get_sap_result(STE_GET_STATUS_MSG, STE_STATUS_FAILURE);
+		sap_transfer_card_reader_status_rsp(sap_device, result, 0);
+		return;
+	}
+
+	if (send_request(u8500.io, STE_GET_STATUS_REQ, NULL) < 0)
+		sap_transfer_card_reader_status_rsp(sap_device,
+						SAP_RESULT_ERROR_NO_DATA, 0);
+}
+
+void sap_set_transport_protocol_req(void *sap_device,
+						struct sap_parameter *param)
+{
+	DBG("sap_device %p", sap_device);
+
+	sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
+}
+
+int sap_init(void)
+{
+	u8500.state = STE_DISABLED;
+	info("STE U8500 SAP driver initialized");
+	return 0;
+}
+
+void sap_exit(void)
+{
+}
-- 
on behalf of ST-Ericsson


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] Add SAP driver for ST-Ericsson U8500 platform
  2011-07-05 10:03   ` [PATCH v2] " Szymon Janc
@ 2011-07-13  8:53     ` Johan Hedberg
  0 siblings, 0 replies; 4+ messages in thread
From: Johan Hedberg @ 2011-07-13  8:53 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth, par-gunnar.p.hjalmdahl, ulrik.lauren

Hi Szymon,

On Tue, Jul 05, 2011, Szymon Janc wrote:
> ---
>  Makefile.am     |    4 +-
>  sap/sap-u8500.c |  708 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 710 insertions(+), 2 deletions(-)
>  create mode 100644 sap/sap-u8500.c

The patch has been applied, thanks. I had to fix whitespace in the
sim2sap_result table first though.

Johan

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-07-13  8:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-04 11:02 [PATCH] Add SAP driver for ST-Ericsson U8500 platform Szymon Janc
2011-07-04 12:20 ` Anderson Lizardo
2011-07-05 10:03   ` [PATCH v2] " Szymon Janc
2011-07-13  8:53     ` Johan Hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.