diff --git a/Makefile.am b/Makefile.am index 58bb532b..32ee3dcf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -623,7 +623,8 @@ builtin_sources += $(mbim_sources) \ drivers/mbimmodem/devinfo.c \ drivers/mbimmodem/sim.c \ drivers/mbimmodem/network-registration.c \ - drivers/mbimmodem/sms.c + drivers/mbimmodem/sms.c \ + drivers/mbimmodem/gprs.c builtin_modules += mbim builtin_sources += plugins/mbim.c diff --git a/drivers/mbimmodem/gprs.c b/drivers/mbimmodem/gprs.c new file mode 100644 index 00000000..8eda61ec --- /dev/null +++ b/drivers/mbimmodem/gprs.c @@ -0,0 +1,248 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2017 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 +#endif + +#define _GNU_SOURCE +#include +#include +#include + +#include +#include +#include +#include "common.h" + +#include "drivers/mbimmodem/mbim.h" +#include "drivers/mbimmodem/mbim-message.h" +#include "drivers/mbimmodem/mbimmodem.h" + +struct gprs_data { + struct mbim_device *device; + struct l_idle *delayed_register; +}; + +static void mbim_packet_service_set_cb(struct mbim_message *message, void *user) +{ + struct cb_data *cbd = user; + ofono_gprs_cb_t cb = cbd->cb; + + DBG(""); + + if (mbim_message_get_error(message) != 0) + CALLBACK_WITH_FAILURE(cb, cbd->data); + else + CALLBACK_WITH_SUCCESS(cb, cbd->data); +} + +static void mbim_gprs_set_attached(struct ofono_gprs *gprs, int attached, + ofono_gprs_cb_t cb, void *data) +{ + struct gprs_data *gd = ofono_gprs_get_data(gprs); + struct cb_data *cbd = cb_data_new(cb, data); + struct mbim_message *message; + + DBG(""); + + message = mbim_message_new(mbim_uuid_basic_connect, + MBIM_CID_PACKET_SERVICE, + MBIM_COMMAND_TYPE_SET); + /* + * MBIMPacketServiceActionAttach (0) or + * MBIMPacketServiceActionDetach (1) + */ + mbim_message_set_arguments(message, "u", attached ? 0 : 1); + + if (mbim_device_send(gd->device, GPRS_GROUP, message, + mbim_packet_service_set_cb, cbd, l_free) > 0) + return; + + l_free(cbd); + mbim_message_unref(message); + CALLBACK_WITH_FAILURE(cb, data); +} + +static void mbim_packet_service_query_cb(struct mbim_message *message, + void *user) +{ + struct cb_data *cbd = user; + ofono_gprs_status_cb_t cb = cbd->cb; + uint32_t dummy; + uint32_t state; + + DBG("%u", mbim_message_get_error(message)); + + if (mbim_message_get_error(message) != 0) + goto error; + + if (!mbim_message_get_arguments(message, "uu", &dummy, &state)) + goto error; + + if (state == 2) + CALLBACK_WITH_SUCCESS(cb, + NETWORK_REGISTRATION_STATUS_REGISTERED, + cbd->data); + else + CALLBACK_WITH_SUCCESS(cb, NETWORK_REGISTRATION_STATUS_UNKNOWN, + cbd->data); + + return; + +error: + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); +} + +static void mbim_gprs_registration_status(struct ofono_gprs *gprs, + ofono_gprs_status_cb_t cb, + void *data) +{ + struct gprs_data *gd = ofono_gprs_get_data(gprs); + struct cb_data *cbd = cb_data_new(cb, data); + struct mbim_message *message; + + DBG(""); + + message = mbim_message_new(mbim_uuid_basic_connect, + MBIM_CID_PACKET_SERVICE, + MBIM_COMMAND_TYPE_QUERY); + mbim_message_set_arguments(message, ""); + + if (mbim_device_send(gd->device, GPRS_GROUP, message, + mbim_packet_service_query_cb, cbd, l_free) > 0) + return; + + l_free(cbd); + mbim_message_unref(message); + CALLBACK_WITH_FAILURE(cb, -1, data); +} + +static void mbim_packet_service_changed(struct mbim_message *message, + void *user) +{ + struct ofono_gprs *gprs = user; + uint32_t nw_error; + uint32_t packet_service_state; + uint32_t highest_avail_data_class; + uint64_t uplink_speed; + uint64_t downlink_speed; + + DBG(""); + + if (!mbim_message_get_arguments(message, "uuutt", + &nw_error, + &packet_service_state, + &highest_avail_data_class, + &uplink_speed, + &downlink_speed)) + return; + + DBG("uplink: %"PRIu64", downlink: %"PRIu64, + uplink_speed, downlink_speed); + DBG("nw_error: %u", nw_error); + + if (packet_service_state == 2) { + uint32_t bearer = + mbim_data_class_to_tech(highest_avail_data_class); + + ofono_gprs_status_notify(gprs, + NETWORK_REGISTRATION_STATUS_REGISTERED); + ofono_gprs_bearer_notify(gprs, bearer); + } else + ofono_gprs_status_notify(gprs, + NETWORK_REGISTRATION_STATUS_UNKNOWN); +} + +static void delayed_register(struct l_idle *idle, void *user_data) +{ + struct ofono_gprs *gprs = user_data; + struct gprs_data *gd = ofono_gprs_get_data(gprs); + + DBG(""); + + l_idle_remove(idle); + gd->delayed_register = NULL; + + if (!mbim_device_register(gd->device, GPRS_GROUP, + mbim_uuid_basic_connect, + MBIM_CID_PACKET_SERVICE, + mbim_packet_service_changed, + gprs, NULL)) + goto error; + + ofono_gprs_register(gprs); + return; + +error: + ofono_gprs_remove(gprs); +} + +static int mbim_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor, + void *data) +{ + struct mbim_device *device = data; + struct gprs_data *gd; + + DBG(""); + + gd = l_new(struct gprs_data, 1); + gd->device = mbim_device_ref(device); + gd->delayed_register = l_idle_create(delayed_register, gprs, NULL); + + ofono_gprs_set_data(gprs, gd); + + return 0; +} + +static void mbim_gprs_remove(struct ofono_gprs *gprs) +{ + struct gprs_data *gd = ofono_gprs_get_data(gprs); + + DBG(""); + + ofono_gprs_set_data(gprs, NULL); + + l_idle_remove(gd->delayed_register); + mbim_device_cancel_group(gd->device, GPRS_GROUP); + mbim_device_unregister_group(gd->device, GPRS_GROUP); + mbim_device_unref(gd->device); + gd->device = NULL; + l_free(gd); +} + +static struct ofono_gprs_driver driver = { + .name = "mbim", + .probe = mbim_gprs_probe, + .remove = mbim_gprs_remove, + .set_attached = mbim_gprs_set_attached, + .attached_status = mbim_gprs_registration_status, +}; + +void mbim_gprs_init(void) +{ + ofono_gprs_driver_register(&driver); +} + +void mbim_gprs_exit(void) +{ + ofono_gprs_driver_unregister(&driver); +} diff --git a/drivers/mbimmodem/mbimmodem.c b/drivers/mbimmodem/mbimmodem.c index 6eb23db4..5b8b3aca 100644 --- a/drivers/mbimmodem/mbimmodem.c +++ b/drivers/mbimmodem/mbimmodem.c @@ -33,12 +33,14 @@ static int mbimmodem_init(void) mbim_devinfo_init(); mbim_sim_init(); mbim_netreg_init(); - mbim_sms_init(); + mbim_sms_exit(); + mbim_gprs_init(); return 0; } static void mbimmodem_exit(void) { + mbim_gprs_exit(); mbim_sms_exit(); mbim_netreg_exit(); mbim_sim_exit(); diff --git a/drivers/mbimmodem/mbimmodem.h b/drivers/mbimmodem/mbimmodem.h index 0b9b6cf1..c5d8d889 100644 --- a/drivers/mbimmodem/mbimmodem.h +++ b/drivers/mbimmodem/mbimmodem.h @@ -25,6 +25,7 @@ enum MBIM_GROUP { SIM_GROUP = 1, NETREG_GROUP = 2, SMS_GROUP = 3, + GPRS_GROUP = 4, }; extern void mbim_devinfo_init(void); @@ -38,3 +39,6 @@ extern void mbim_netreg_exit(void); extern void mbim_sms_init(void); extern void mbim_sms_exit(void); + +extern void mbim_gprs_init(void); +extern void mbim_gprs_exit(void);