[PATCH] usbpnmodem: configure usbpn interfaces automatically
by Pekka Pessi
---
drivers/isimodem/isimodem.c | 2 +-
gisi/netlink.c | 246 +++++++++++++++++++++++++++++++++++++++---
gisi/netlink.h | 11 ++-
plugins/usbpnmodem.c | 10 ++-
4 files changed, 246 insertions(+), 23 deletions(-)
diff --git a/drivers/isimodem/isimodem.c b/drivers/isimodem/isimodem.c
index e6e0bc1..b6ae82b 100644
--- a/drivers/isimodem/isimodem.c
+++ b/drivers/isimodem/isimodem.c
@@ -256,7 +256,7 @@ static int isi_modem_probe(struct ofono_modem *modem)
return -errno;
}
- link = g_pn_netlink_by_name(ifname);
+ link = g_pn_netlink_by_modem(idx);
if (link) {
DBG("%s: %s", ifname, strerror(EBUSY));
return -EBUSY;
diff --git a/gisi/netlink.c b/gisi/netlink.c
index 1a18b45..36bf273 100644
--- a/gisi/netlink.c
+++ b/gisi/netlink.c
@@ -68,6 +68,7 @@
#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr*)(void*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define SIZE_NLMSG (16384)
struct _GPhonetNetlink {
GPhonetNetlinkFunc callback;
@@ -98,18 +99,6 @@ GPhonetNetlink *g_pn_netlink_by_modem(GIsiModem *idx)
return NULL;
}
-GPhonetNetlink *g_pn_netlink_by_name(const char *ifname)
-{
- if (ifname == NULL) {
- return g_pn_netlink_by_modem(make_modem(0));
- } else {
- GIsiModem *idx = g_isi_modem_by_name(ifname);
- if (!idx)
- return NULL;
- return g_pn_netlink_by_modem(idx);
- }
-}
-
static void bring_up(unsigned ifindex)
{
struct ifreq req = { .ifr_ifindex = ifindex, };
@@ -124,6 +113,25 @@ error:
close(fd);
}
+static int netlink_socket(void)
+{
+ int fd;
+ int bufsize = SIZE_NLMSG;
+
+ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd == -1)
+ return -1;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, (sizeof bufsize))) {
+ int error = errno;
+ g_warning("sockopt(SO_RCVBUF): %s", strerror(error));
+ close(fd), fd = -1;
+ errno = error;
+ }
+
+ return fd;
+}
+
static void g_pn_nl_addr(GPhonetNetlink *self, struct nlmsghdr *nlh)
{
int len;
@@ -196,7 +204,7 @@ static gboolean g_pn_nl_process(GIOChannel *channel, GIOCondition cond,
{
struct {
struct nlmsghdr nlh;
- char buf[16384];
+ char buf[SIZE_NLMSG];
} resp;
struct iovec iov = { &resp, (sizeof resp), };
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, };
@@ -225,10 +233,11 @@ static gboolean g_pn_nl_process(GIOChannel *channel, GIOCondition cond,
switch (nlh->nlmsg_type) {
case NLMSG_ERROR: {
- const struct nlmsgerr *err;
- err = (struct nlmsgerr *)NLMSG_DATA(nlh);
- g_critical("Netlink error: %s", strerror(-err->error));
- return FALSE;
+ const struct nlmsgerr *err = NLMSG_DATA(nlh);
+ if (err->error)
+ g_critical("Netlink error: %s",
+ strerror(-err->error));
+ return TRUE;
}
case RTM_NEWADDR:
case RTM_DELADDR:
@@ -271,6 +280,7 @@ static int g_pn_netlink_getlink(int fd)
(struct sockaddr *)&addr, sizeof(addr));
}
+
GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
GPhonetNetlinkFunc callback,
void *data)
@@ -281,7 +291,7 @@ GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
unsigned group = RTNLGRP_LINK;
unsigned interface = g_isi_modem_index(idx);
- fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ fd = netlink_socket();
if (fd == -1)
return NULL;
@@ -332,3 +342,203 @@ void g_pn_netlink_stop(GPhonetNetlink *self)
free(self);
}
}
+
+static int netlink_getack(int fd)
+{
+ struct {
+ struct nlmsghdr nlh;
+ char buf[SIZE_NLMSG];
+ } resp;
+ struct iovec iov = { &resp, (sizeof resp), };
+ struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, };
+ ssize_t ret;
+ struct nlmsghdr *nlh = &resp.nlh;
+
+ ret = recvmsg(fd, &msg, 0);
+ if (ret == -1)
+ return -errno;
+
+ if (msg.msg_flags & MSG_TRUNC) {
+ g_critical("Netlink message of %zu bytes truncated at %zu",
+ ret, (sizeof resp));
+ return -EIO;
+ }
+
+ for (; NLMSG_OK(nlh, (size_t)ret); nlh = NLMSG_NEXT(nlh, ret)) {
+
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ return 0;
+
+ if (nlh->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = NLMSG_DATA(nlh);
+ return err->error;
+ }
+ }
+
+ return -EIO;
+}
+
+/* Set local address */
+static int netlink_setaddr(int fd, uint32_t ifa_index, uint8_t ifa_local)
+{
+ struct ifaddrmsg *ifa;
+ struct rtattr *rta;
+ uint32_t reqlen = NLMSG_LENGTH(NLMSG_ALIGN(sizeof *ifa) + RTA_SPACE(1));
+ struct req {
+ struct nlmsghdr nlh;
+ char buf[512];
+ } req = {
+ .nlh = {
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ .nlmsg_type = RTM_NEWADDR,
+ .nlmsg_pid = getpid(),
+ .nlmsg_len = reqlen,
+ },
+ };
+
+ struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };
+
+ ifa = NLMSG_DATA(&req.nlh);
+ ifa->ifa_family = AF_PHONET;
+ ifa->ifa_prefixlen = 0;
+ ifa->ifa_index = ifa_index;
+
+ rta = IFA_RTA(ifa);
+ rta->rta_type = IFA_LOCAL;
+ rta->rta_len = RTA_LENGTH(1);
+ *(uint8_t *)RTA_DATA(rta) = ifa_local;
+
+ if (sendto(fd, &req, reqlen, 0, (void *)&addr, sizeof addr) == -1)
+ return -errno;
+
+ return 0;
+}
+
+int g_pn_netlink_set_address(GIsiModem *idx, uint8_t local)
+{
+ int fd = -1;
+ uint32_t ifindex;
+ int error = 0;
+
+ if (idx == NULL)
+ return -ENODEV;
+
+ if (local != PN_DEV_PC && local != PN_DEV_SOS)
+ return -EINVAL;
+
+ ifindex = g_isi_modem_index(idx);
+
+ fd = netlink_socket();
+ if (fd == -1)
+ goto error;
+
+ error = netlink_setaddr(fd, ifindex, local);
+ if (error)
+ goto error;
+
+ error = netlink_getack(fd);
+ if (error)
+ goto error;
+
+ close(fd);
+ return 0;
+
+error:
+ if (!error)
+ error = -(errno ? errno : -EIO);
+ if (fd != -1)
+ close(fd);
+ return error;
+}
+
+/* Add remote address */
+static int netlink_addroute(int fd, uint32_t ifa_index, uint8_t remote)
+{
+ struct rtmsg *rtm;
+ struct rtattr *rta;
+ uint32_t reqlen = NLMSG_LENGTH(
+ NLMSG_ALIGN(sizeof *rtm) +
+ RTA_SPACE(1) +
+ RTA_SPACE(sizeof ifa_index));
+ struct req {
+ struct nlmsghdr nlh;
+ char buf[512];
+ } req = {
+ .nlh = {
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK
+ | NLM_F_CREATE | NLM_F_APPEND,
+ .nlmsg_type = RTM_NEWROUTE,
+ .nlmsg_pid = getpid(),
+ .nlmsg_len = reqlen,
+ },
+ };
+ size_t buflen = (sizeof req.buf) - (sizeof *rtm);
+
+ struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };
+
+ rtm = NLMSG_DATA(&req.nlh);
+ rtm->rtm_family = AF_PHONET;
+ rtm->rtm_dst_len = 6;
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = 0;
+
+ rtm->rtm_table = RT_TABLE_MAIN;
+ rtm->rtm_protocol = RTPROT_STATIC;
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ rtm->rtm_type = RTN_UNICAST;
+ rtm->rtm_flags = 0;
+
+ rta = IFA_RTA(rtm);
+ rta->rta_type = RTA_DST;
+ rta->rta_len = RTA_LENGTH(1);
+ *(uint8_t *)RTA_DATA(rta) = remote;
+
+ rta = RTA_NEXT(rta, buflen);
+ rta->rta_type = RTA_OIF;
+ rta->rta_len = RTA_LENGTH(sizeof ifa_index);
+ *(uint32_t *)(void *)RTA_DATA(rta) = ifa_index;
+
+ if (sendto(fd, &req, reqlen, 0, (void *)&addr, sizeof addr) == -1)
+ return -errno;
+
+ return 0;
+}
+
+int g_pn_netlink_add_route(GIsiModem *idx, uint8_t remote)
+{
+ int fd = -1;
+ uint32_t ifindex;
+ int error = 0;
+
+ if (idx == NULL)
+ return -ENODEV;
+
+ if (remote != PN_DEV_SOS && remote != PN_DEV_HOST)
+ return -EINVAL;
+
+ ifindex = g_isi_modem_index(idx);
+
+ fd = netlink_socket();
+ if (fd == -1)
+ goto error;
+
+ error = netlink_addroute(fd, ifindex, remote);
+ if (error)
+ goto error;
+
+ error = netlink_getack(fd);
+ if (error)
+ goto error;
+
+ close(fd);
+ return 0;
+
+error:
+ if (!error)
+ error = -errno;
+ if (!error)
+ error = -EIO;
+ if (fd != -1)
+ close(fd);
+ return error;
+}
diff --git a/gisi/netlink.h b/gisi/netlink.h
index dfade5b..5b58fa4 100644
--- a/gisi/netlink.h
+++ b/gisi/netlink.h
@@ -41,13 +41,17 @@ typedef enum {
PN_LINK_UP
} GPhonetLinkState;
+enum {
+ PN_DEV_PC = 0x10, /* PC Suite */
+ PN_DEV_HOST = 0x00, /* Modem */
+ PN_DEV_SOS = 0x6C, /* Symbian or Linux */
+};
+
typedef void (*GPhonetNetlinkFunc)(GIsiModem *idx,
GPhonetLinkState st,
char const *iface,
void *data);
-GPhonetNetlink *g_pn_netlink_by_name(char const *ifname);
-
GPhonetNetlink *g_pn_netlink_by_modem(GIsiModem *idx);
GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
@@ -56,6 +60,9 @@ GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
void g_pn_netlink_stop(GPhonetNetlink *self);
+int g_pn_netlink_set_address(GIsiModem *, uint8_t local);
+int g_pn_netlink_add_route(GIsiModem *, uint8_t remote);
+
#ifdef __cplusplus
}
#endif
diff --git a/plugins/usbpnmodem.c b/plugins/usbpnmodem.c
index 5f06e9d..e1ce4fd 100644
--- a/plugins/usbpnmodem.c
+++ b/plugins/usbpnmodem.c
@@ -49,6 +49,7 @@ static void usbpn_status_cb(GIsiModem *idx,
void *data)
{
struct ofono_modem *modem;
+ int error;
DBG("Phonet link %s (%u) is %s",
ifname, g_isi_modem_index(idx),
@@ -63,12 +64,17 @@ static void usbpn_status_cb(GIsiModem *idx,
if (st == PN_LINK_REMOVED)
return;
- link = g_pn_netlink_by_name(ifname);
- if (link) {
+ if (g_pn_netlink_by_modem(idx)) {
DBG("Modem for interface %s already exists", ifname);
return;
}
+ error = g_pn_netlink_set_address(idx, PN_DEV_SOS);
+ if (error && error != -EEXIST) {
+ DBG("g_pn_netlink_set_address: %s\n", strerror(-error));
+ return;
+ }
+
modem = ofono_modem_create(NULL, "isimodem");
if (!modem)
return;
--
1.6.3.3
10 years, 10 months
[PATCH 3/4] gatchat: Emit notification when command is sent to modem.
by Andrzej Zaborowski
Function g_at_chat_send_with_callback takes an additional parameter
that is a function to call when command is sent to hardware.
---
gatchat/gatchat.c | 35 +++++++++++++++++++++++++++--------
gatchat/gatchat.h | 17 +++++++++++++++++
2 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index 4552767..000b624 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -49,6 +49,7 @@ struct at_command {
guint id;
GAtResultFunc callback;
GAtNotifyFunc listing;
+ GAtSubmitNotifyFunc submit_callback;
gpointer user_data;
GDestroyNotify notify;
};
@@ -148,6 +149,7 @@ static struct at_command *at_command_create(const char *cmd,
const char **prefix_list,
gboolean expect_pdu,
GAtNotifyFunc listing,
+ GAtSubmitNotifyFunc sent,
GAtResultFunc func,
gpointer user_data,
GDestroyNotify notify,
@@ -203,6 +205,7 @@ static struct at_command *at_command_create(const char *cmd,
c->prefixes = prefixes;
c->callback = func;
c->listing = listing;
+ c->submit_callback = sent;
c->user_data = user_data;
c->notify = notify;
@@ -700,7 +703,7 @@ static gboolean wakeup_no_response(gpointer user_data)
g_at_chat_finish_command(chat, FALSE, NULL);
cmd = at_command_create(chat->wakeup, none_prefix, FALSE,
- NULL, wakeup_cb, chat, NULL, TRUE);
+ NULL, NULL, wakeup_cb, chat, NULL, TRUE);
if (!cmd) {
chat->timeout_source = 0;
@@ -752,7 +755,8 @@ static gboolean can_write_data(gpointer data)
if (chat->cmd_bytes_written == 0 && wakeup_first == TRUE) {
cmd = at_command_create(chat->wakeup, none_prefix, FALSE,
- NULL, wakeup_cb, chat, NULL, TRUE);
+ NULL, NULL, wakeup_cb, chat, NULL,
+ TRUE);
if (!cmd)
return FALSE;
@@ -789,6 +793,9 @@ static gboolean can_write_data(gpointer data)
if (bytes_written < towrite)
return TRUE;
+ if (cmd->submit_callback)
+ cmd->submit_callback(cmd->id, cmd->user_data);
+
/* Full command submitted, update timer */
if (chat->wakeup_timer)
g_timer_start(chat->wakeup_timer);
@@ -967,7 +974,8 @@ gboolean g_at_chat_set_debug(GAtChat *chat,
static guint send_common(GAtChat *chat, const char *cmd,
const char **prefix_list,
gboolean expect_pdu,
- GAtNotifyFunc listing, GAtResultFunc func,
+ GAtNotifyFunc listing, GAtSubmitNotifyFunc sent,
+ GAtResultFunc func,
gpointer user_data, GDestroyNotify notify)
{
struct at_command *c;
@@ -975,8 +983,8 @@ static guint send_common(GAtChat *chat, const char *cmd,
if (chat == NULL || chat->command_queue == NULL)
return 0;
- c = at_command_create(cmd, prefix_list, expect_pdu, listing, func,
- user_data, notify, FALSE);
+ c = at_command_create(cmd, prefix_list, expect_pdu, listing,
+ sent, func, user_data, notify, FALSE);
if (!c)
return 0;
@@ -995,7 +1003,7 @@ guint g_at_chat_send(GAtChat *chat, const char *cmd,
const char **prefix_list, GAtResultFunc func,
gpointer user_data, GDestroyNotify notify)
{
- return send_common(chat, cmd, prefix_list, FALSE, NULL, func,
+ return send_common(chat, cmd, prefix_list, FALSE, NULL, NULL, func,
user_data, notify);
}
@@ -1007,7 +1015,7 @@ guint g_at_chat_send_listing(GAtChat *chat, const char *cmd,
if (listing == NULL)
return 0;
- return send_common(chat, cmd, prefix_list, FALSE, listing, func,
+ return send_common(chat, cmd, prefix_list, FALSE, listing, NULL, func,
user_data, notify);
}
@@ -1019,7 +1027,18 @@ guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
if (listing == NULL)
return 0;
- return send_common(chat, cmd, prefix_list, TRUE, listing, func,
+ return send_common(chat, cmd, prefix_list, TRUE, listing, NULL, func,
+ user_data, notify);
+}
+
+guint g_at_chat_send_with_callback(GAtChat *chat, const char *cmd,
+ const char **valid_resp,
+ GAtSubmitNotifyFunc sent,
+ GAtResultFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ return send_common(chat, cmd, valid_resp, TRUE, NULL, sent, func,
user_data, notify);
}
diff --git a/gatchat/gatchat.h b/gatchat/gatchat.h
index ea6626e..80d87be 100644
--- a/gatchat/gatchat.h
+++ b/gatchat/gatchat.h
@@ -37,6 +37,7 @@ typedef struct _GAtChat GAtChat;
typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
gpointer user_data);
typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
+typedef void (*GAtSubmitNotifyFunc)(guint id, gpointer user_data);
GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax);
GAtChat *g_at_chat_new_blocking(GIOChannel *channel, GAtSyntax *syntax);
@@ -117,6 +118,22 @@ guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
GAtNotifyFunc listing, GAtResultFunc func,
gpointer user_data, GDestroyNotify notify);
+/*!
+ * Same as g_at_chat_send but with an ability to return a notification the
+ * moment the command finally leaves the queue and is submitted to lower
+ * layer.
+ *
+ * This is useful for cases where the modem's response time needs to be
+ * measured, assuming that the lower layers processing time is shorter
+ * than the minimum accuracy needed.
+ */
+guint g_at_chat_send_with_callback(GAtChat *chat, const char *cmd,
+ const char **valid_resp,
+ GAtSubmitNotifyFunc sent,
+ GAtResultFunc func,
+ gpointer user_data,
+ GDestroyNotify notify);
+
gboolean g_at_chat_cancel(GAtChat *chat, guint id);
gboolean g_at_chat_cancel_all(GAtChat *chat);
--
1.6.1
10 years, 10 months
[PATCH] add vid/pid for Dell 5541 and 5542
by torgny.johansson@ericsson.com
From: Torgny Johansson <torgny.johansson(a)ericsson.com>
---
plugins/ofono.rules | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/plugins/ofono.rules b/plugins/ofono.rules
index e6da49d..0575362 100644
--- a/plugins/ofono.rules
+++ b/plugins/ofono.rules
@@ -42,6 +42,10 @@ ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{OFONO_DRIVER}="mbm"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{OFONO_DRIVER}="mbm"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{OFONO_DRIVER}="mbm"
+# Dell F3307
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{OFONO_DRIVER}="mbm"
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{OFONO_DRIVER}="mbm"
+
# Toshiba
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{OFONO_DRIVER}="mbm"
--
1.7.0.4
10 years, 10 months
[PATCH 2/4][RFC] gatchat: Allow cancelling a running command.
by Andrzej Zaborowski
Users need to be extra careful using the cancel functions because
there's a potential race condition where an OK or ERROR for the command
being cancelled arrives just the same moment the next command in the
queue is being submitted, and is treated as a response to that command.
Ideally we would have some kind of "barrier" command that could be
inserted into the queue and whose response would be different than
OK or ERROR.
---
gatchat/gatchat.c | 32 +++++++++++++++-----------------
1 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index f94605f..4552767 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -1026,6 +1026,7 @@ guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
gboolean g_at_chat_cancel(GAtChat *chat, guint id)
{
GList *l;
+ gboolean head;
if (chat == NULL || chat->command_queue == NULL)
return FALSE;
@@ -1040,18 +1041,20 @@ gboolean g_at_chat_cancel(GAtChat *chat, guint id)
if (!l)
return FALSE;
- if (l == g_queue_peek_head(chat->command_queue) &&
- chat->cmd_bytes_written > 0) {
- struct at_command *c = l->data;
+ head = l->data == g_queue_peek_head(chat->command_queue);
- /* We can't actually remove it since it is most likely
- * already in progress, just null out the callback
- * so it won't be called
- */
- c->callback = NULL;
- } else {
- at_command_destroy(l->data);
- g_queue_remove(chat->command_queue, l->data);
+ at_command_destroy(l->data);
+ g_queue_remove(chat->command_queue, l->data);
+
+ if (head) {
+ chat->cmd_bytes_written = 0;
+
+ g_slist_foreach(chat->response_lines, (GFunc)g_free, NULL);
+ g_slist_free(chat->response_lines);
+ chat->response_lines = NULL;
+
+ if (g_queue_get_length(chat->command_queue) > 0)
+ chat_wakeup_writer(chat);
}
return TRUE;
@@ -1071,15 +1074,10 @@ gboolean g_at_chat_cancel_all(GAtChat *chat)
continue;
}
- if (n == 0 && chat->cmd_bytes_written > 0) {
- c->callback = NULL;
- n += 1;
- continue;
- }
-
at_command_destroy(c);
g_queue_remove(chat->command_queue, c);
}
+ chat->cmd_bytes_written = 0;
return TRUE;
}
--
1.6.1
10 years, 10 months
[PATCH] Add a Calypso STK driver.
by Andrzej Zaborowski
---
Makefile.am | 3 +-
drivers/calypsomodem/calypsomodem.c | 2 +
drivers/calypsomodem/calypsomodem.h | 3 +
drivers/calypsomodem/stk.c | 274 +++++++++++++++++++++++++++++++++++
plugins/phonesim.c | 46 +++++-
5 files changed, 318 insertions(+), 10 deletions(-)
create mode 100644 drivers/calypsomodem/stk.c
diff --git a/Makefile.am b/Makefile.am
index 463e52e..58d2dc0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -161,7 +161,8 @@ builtin_modules += calypsomodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/calypsomodem/calypsomodem.h \
drivers/calypsomodem/calypsomodem.c \
- drivers/calypsomodem/voicecall.c
+ drivers/calypsomodem/voicecall.c \
+ drivers/calypsomodem/stk.c
builtin_modules += hfpmodem
builtin_sources += drivers/atmodem/atutil.h \
diff --git a/drivers/calypsomodem/calypsomodem.c b/drivers/calypsomodem/calypsomodem.c
index 8cd213e..2ae436a 100644
--- a/drivers/calypsomodem/calypsomodem.c
+++ b/drivers/calypsomodem/calypsomodem.c
@@ -35,12 +35,14 @@
static int calypsomodem_init(void)
{
calypso_voicecall_init();
+ calypso_stk_init();
return 0;
}
static void calypsomodem_exit(void)
{
+ calypso_stk_exit();
calypso_voicecall_exit();
}
diff --git a/drivers/calypsomodem/calypsomodem.h b/drivers/calypsomodem/calypsomodem.h
index 80af134..caf7a3d 100644
--- a/drivers/calypsomodem/calypsomodem.h
+++ b/drivers/calypsomodem/calypsomodem.h
@@ -23,3 +23,6 @@
extern void calypso_voicecall_init();
extern void calypso_voicecall_exit();
+
+extern void calypso_stk_init();
+extern void calypso_stk_exit();
diff --git a/drivers/calypsomodem/stk.c b/drivers/calypsomodem/stk.c
new file mode 100644
index 0000000..7143009
--- /dev/null
+++ b/drivers/calypsomodem/stk.c
@@ -0,0 +1,274 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/stk.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "calypsomodem.h"
+
+struct stk_data {
+ GAtChat *chat;
+ guint8 *set_up_menu_pdu;
+ guint set_up_menu_pdu_len;
+};
+
+static void calypso_sate_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_stk_envelope_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok)
+ goto error;
+
+ cb(&error, (const guint8 *) "", 0, cbd->data);
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+}
+
+static void calypso_stk_envelope(struct ofono_stk *stk, int length,
+ const unsigned char *command,
+ ofono_stk_envelope_cb_t cb, void *data)
+{
+ struct stk_data *sd = ofono_stk_get_data(stk);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ char *buf = g_try_new(char, 64 + length * 2);
+ int len, ret;
+
+ if (!cbd || !buf)
+ goto error;
+
+ len = sprintf(buf, "AT%%SATE=\"");
+ for (; length; length--)
+ len += sprintf(buf + len, "%02hhX", *command++);
+ len += sprintf(buf + len, "\"");
+
+ ret = g_at_chat_send(sd->chat, buf, NULL,
+ calypso_sate_cb, cbd, g_free);
+
+ g_free(buf);
+ buf = NULL;
+
+ if (ret > 0)
+ return;
+
+error:
+ if (buf)
+ g_free(buf);
+
+ if (cbd)
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+}
+
+static void calypso_satr_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_stk_generic_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (ok)
+ cb(&error, cbd->data);
+ else
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void calypso_stk_terminal_response(struct ofono_stk *stk, int length,
+ const unsigned char *command,
+ ofono_stk_generic_cb_t cb, void *data)
+{
+ struct stk_data *sd = ofono_stk_get_data(stk);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ char *buf = g_try_new(char, 64 + length * 2);
+ int len, ret;
+
+ if (!cbd || !buf)
+ goto error;
+
+ len = sprintf(buf, "AT%%SATR=\"");
+ for (; length; length--)
+ len += sprintf(buf + len, "%02hhX", *command++);
+ len += sprintf(buf + len, "\"");
+
+ ret = g_at_chat_send(sd->chat, buf, NULL,
+ calypso_satr_cb, cbd, g_free);
+
+ g_free(buf);
+ buf = NULL;
+
+ if (ret > 0)
+ return;
+
+error:
+ if (buf)
+ g_free(buf);
+
+ if (cbd)
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void sati_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_stk *stk = user_data;
+ struct stk_data *sd = ofono_stk_get_data(stk);
+ GAtResultIter iter;
+ const guint8 *pdu;
+ gint len, length_bytes;
+ gboolean ret;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "%SATI:"))
+ return;
+
+ ret = g_at_result_iter_next_hexstring(&iter, &pdu, &len);
+ if (!ret || len == 0) {
+ /* An empty notification is a request to go back to main
+ * menu, effectively like resending the previous Set Up
+ * Menu proactive command. */
+ if (sd->set_up_menu_pdu)
+ ofono_stk_proactive_command_notify(stk,
+ sd->set_up_menu_pdu_len,
+ sd->set_up_menu_pdu);
+
+ return;
+ }
+
+ ofono_stk_proactive_command_notify(stk, len, pdu);
+
+ /* Check if this is a Set Up Menu command, if so, cache the PDU
+ * because Calypso sends it only once. */
+
+ while (len > 0 && (*pdu == 0x00 || *pdu == 0xff))
+ pdu++, len--;
+ if (len < 7)
+ return;
+ if (pdu[0] != 0xd0) /* Command BER-TLV tag */
+ return;
+ if (pdu[1] < 0x80)
+ length_bytes = 1;
+ else
+ length_bytes = pdu[1] - 0x7f;
+ if (len < length_bytes + 6)
+ return;
+ if (pdu[1 + length_bytes] != 0x01) /* Command Details CTLV tag */
+ return;
+ if (pdu[2 + length_bytes] != 0x03) /* Command Details CTLV length */
+ return;
+ if (pdu[4 + length_bytes] != 0x25) /* Set Up Menu command type */
+ return;
+
+ if (sd->set_up_menu_pdu)
+ g_free(sd->set_up_menu_pdu);
+
+ sd->set_up_menu_pdu = g_memdup(pdu, len);
+ sd->set_up_menu_pdu_len = len;
+}
+
+static void satn_notify(GAtResult *result, gpointer user_data)
+{
+ /* TODO */
+}
+
+static gboolean calypso_stk_register(gpointer user)
+{
+ struct ofono_stk *stk = user;
+ struct stk_data *sd = ofono_stk_get_data(stk);
+
+ g_at_chat_register(sd->chat, "%SATI:", sati_notify, FALSE, stk, NULL);
+ g_at_chat_register(sd->chat, "%SATA:", sati_notify, FALSE, stk, NULL);
+ g_at_chat_register(sd->chat, "%SATN:", satn_notify, FALSE, stk, NULL);
+
+ ofono_stk_register(stk);
+
+ return FALSE;
+}
+
+static int calypso_stk_probe(struct ofono_stk *stk,
+ unsigned int vendor, void *data)
+{
+ GAtChat *chat = data;
+ struct stk_data *sd;
+
+ sd = g_new0(struct stk_data, 1);
+ sd->chat = chat;
+
+ ofono_stk_set_data(stk, sd);
+ g_idle_add(calypso_stk_register, stk);
+
+ return 0;
+}
+
+static void calypso_stk_remove(struct ofono_stk *stk)
+{
+ struct stk_data *sd = ofono_stk_get_data(stk);
+
+ ofono_stk_set_data(stk, NULL);
+
+ if (sd->set_up_menu_pdu)
+ g_free(sd->set_up_menu_pdu);
+
+ g_free(sd);
+}
+
+static struct ofono_stk_driver driver = {
+ .name = "calypsomodem",
+ .probe = calypso_stk_probe,
+ .remove = calypso_stk_remove,
+ .envelope = calypso_stk_envelope,
+ .terminal_response = calypso_stk_terminal_response,
+};
+
+void calypso_stk_init()
+{
+ ofono_stk_driver_register(&driver);
+}
+
+void calypso_stk_exit()
+{
+ ofono_stk_driver_unregister(&driver);
+}
diff --git a/plugins/phonesim.c b/plugins/phonesim.c
index d0cd7f3..2712a15 100644
--- a/plugins/phonesim.c
+++ b/plugins/phonesim.c
@@ -66,6 +66,7 @@ struct phonesim_data {
GAtChat *chat;
gboolean calypso;
gboolean use_mux;
+ gboolean have_sim;
};
static int phonesim_probe(struct ofono_modem *modem)
@@ -98,15 +99,29 @@ static void phonesim_debug(const char *str, void *user_data)
ofono_info("%s", str);
}
-static void cfun_set_on_cb(gboolean ok, GAtResult *result, gpointer user_data)
+static void cpin_check_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
+ struct phonesim_data *data = ofono_modem_get_data(modem);
DBG("");
+ data->have_sim = ok;
+
ofono_modem_set_powered(modem, ok);
}
+static void cfun_set_on_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct phonesim_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ g_at_chat_send(data->chat, "AT+CPIN?", NULL,
+ cpin_check_cb, modem, NULL);
+}
+
static void phonesim_disconnected(gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -241,6 +256,23 @@ static int phonesim_enable(struct ofono_modem *modem)
g_at_chat_send(data->chat, "AT%CUNS=0",
NULL, NULL, NULL, NULL);
+
+ /* It looks like the PROFILE DOWNLOAD is done by the modem
+ * as part of +CFUN=1. By default the profile indicates that
+ * TE supports no Proactive UICC. We need to enable the
+ * %SATA and other notifications here for STK support and
+ * give the modem our profile bits (first N bytes) according
+ * to ETSI TS 102 223 section 5.2. The modem seems to AND
+ * the given value with its own capabilities and OR with some
+ * minimum value. The bits are reset to the minimal values
+ * on +CFUN=0.
+ *
+ * Default value is 450F80021F0000A4020000000000000000000000.
+ * The mask is 4DFF973F7F0200FC0303FF00009FFFE700000000.
+ */
+ g_at_chat_send(data->chat,
+ "AT%SATC=1,\"19E1FFFF0000FF7FFF03FE\"",
+ NULL, NULL, NULL, NULL);
}
if (data->use_mux) {
@@ -278,20 +310,16 @@ static void phonesim_pre_sim(struct ofono_modem *modem)
{
struct phonesim_data *data = ofono_modem_get_data(modem);
struct ofono_sim *sim;
+ const char *drivername = data->calypso ? "calypsomodem" : "atmodem";
DBG("%p", modem);
ofono_devinfo_create(modem, 0, "atmodem", data->chat);
sim = ofono_sim_create(modem, 0, "atmodem", data->chat);
+ ofono_voicecall_create(modem, 0, drivername, data->chat);
+ ofono_stk_create(modem, 0, drivername, data->chat);
- if (data->calypso)
- ofono_voicecall_create(modem, 0, "calypsomodem", data->chat);
- else
- ofono_voicecall_create(modem, 0, "atmodem", data->chat);
-
- ofono_stk_create(modem, 0, "atmodem", data->chat);
-
- if (sim)
+ if (data->have_sim && sim)
ofono_sim_inserted_notify(sim, TRUE);
}
--
1.6.1
10 years, 10 months
[PATCH] add vid/pid for Dell 5541 and 5542
by Torgny Johansson
Hi!
The following patch adds two new devices in the ofono.rules file:
Regards
Torgny Johansson
diff --git a/plugins/ofono.rules b/plugins/ofono.rules
index e6da49d..0575362 100644
--- a/plugins/ofono.rules
+++ b/plugins/ofono.rules
@@ -42,6 +42,10 @@ ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147",
ENV{OFONO_DRIVER}="mbm"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{OFONO_DRIVER}="mbm"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{OFONO_DRIVER}="mbm"
+# Dell F3307
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{OFONO_DRIVER}="mbm"
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{OFONO_DRIVER}="mbm"
+
# Toshiba
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{OFONO_DRIVER}="mbm"
10 years, 10 months
[PATCH v2 0/6] Huawei GPRS support
by Kalle Valo
Hello all,
here's my current patch set of adding Huawei GPRS support to ofono. I
have tested it with Huawei E1552 USB dongle and finnish Saunalahti prepaid
sim.
Because I had to somehow provide the second GAtChat to atmodem's gprs and
netreg modules, I decided to add two new structs.
There's one major bug still, ofono segfaults when I deactivate the gprs
context. I don't know the reason for this yet.
Please comment.
---
Kalle Valo (6):
huawei: add gprs context
atmodem: add signal strength support for huawei
atmodem: follow separate event chat with huawei
huawei: detect SecondaryDevice which is used for events
atmodem: create struct atmodem_network_registration
atmodem: create struct atmodem_gprs
drivers/atmodem/gprs.c | 23 ++++++++---
drivers/atmodem/gprs.h | 29 ++++++++++++++
drivers/atmodem/network-registration.c | 37 ++++++++++++++++--
drivers/atmodem/network-registration.h | 29 ++++++++++++++
plugins/atgen.c | 7 +++
plugins/calypso.c | 7 +++
plugins/em770.c | 2 +
plugins/g1.c | 8 +++-
plugins/hso.c | 15 ++++++-
plugins/huawei.c | 66 +++++++++++++++++++++++++++++++-
plugins/mbm.c | 14 ++++++-
plugins/novatel.c | 9 ++++
plugins/palmpre.c | 15 ++++++-
plugins/phonesim.c | 16 ++++++--
plugins/ste.c | 15 ++++++-
plugins/udev.c | 61 ++++++++++++++++++++++++++----
16 files changed, 319 insertions(+), 34 deletions(-)
create mode 100644 drivers/atmodem/gprs.h
create mode 100644 drivers/atmodem/network-registration.h
10 years, 10 months