@@ -34,6 +34,7 @@
#include <string.h>
#include <glib.h>
+#include <ell/ell.h>
#include <ofono/log.h>
@@ -54,6 +55,10 @@ struct qmi_version {
const char *name;
};
+struct qmi_device_ops {
+ void (*destroy)(struct qmi_device *device);
+};
+
struct qmi_device {
int ref_count;
int fd;
@@ -80,10 +85,15 @@ struct qmi_device {
void *shutdown_user_data;
qmi_destroy_func_t shutdown_destroy;
guint shutdown_source;
+ const struct qmi_device_ops *ops;
bool shutting_down : 1;
bool destroyed : 1;
};
+struct qmi_device_qmux {
+ struct qmi_device super;
+};
+
struct qmi_service {
int ref_count;
struct qmi_device *device;
@@ -949,15 +959,11 @@ static void service_destroy(gpointer data)
service->device = NULL;
}
-struct qmi_device *qmi_device_new(int fd)
+static int qmi_device_init(struct qmi_device *device, int fd,
+ const struct qmi_device_ops *ops)
{
- struct qmi_device *device;
long flags;
- device = g_try_new0(struct qmi_device, 1);
- if (!device)
- return NULL;
-
__debug_device(device, "device %p new", device);
device->ref_count = 1;
@@ -966,16 +972,14 @@ struct qmi_device *qmi_device_new(int fd)
device->close_on_unref = false;
flags = fcntl(device->fd, F_GETFL, NULL);
- if (flags < 0) {
- g_free(device);
- return NULL;
- }
+ if (flags < 0)
+ return -EIO;
if (!(flags & O_NONBLOCK)) {
- if (fcntl(device->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
- g_free(device);
- return NULL;
- }
+ int r = fcntl(device->fd, F_SETFL, flags | O_NONBLOCK);
+
+ if (r < 0)
+ return -errno;
}
device->io = g_io_channel_unix_new(device->fd);
@@ -1000,7 +1004,9 @@ struct qmi_device *qmi_device_new(int fd)
device->next_control_tid = 1;
device->next_service_tid = 256;
- return device;
+ device->ops = ops;
+
+ return 0;
}
struct qmi_device *qmi_device_ref(struct qmi_device *device)
@@ -1055,7 +1061,7 @@ void qmi_device_unref(struct qmi_device *device)
if (device->shutting_down)
device->destroyed = true;
else
- g_free(device);
+ device->ops->destroy(device);
}
void qmi_device_set_debug(struct qmi_device *device,
@@ -1646,6 +1652,38 @@ done:
return res;
}
+static void qmi_device_qmux_destroy(struct qmi_device *device)
+{
+ struct qmi_device_qmux *qmux =
+ l_container_of(device, struct qmi_device_qmux, super);
+
+ l_free(qmux);
+}
+
+static const struct qmi_device_ops qmux_ops = {
+ .destroy = qmi_device_qmux_destroy,
+};
+
+struct qmi_device *qmi_device_new_qmux(const char *device)
+{
+ struct qmi_device_qmux *qmux;
+ int fd;
+
+ fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0)
+ return NULL;
+
+ qmux = l_new(struct qmi_device_qmux, 1);
+
+ if (qmi_device_init(&qmux->super, fd, &qmux_ops) < 0) {
+ close(fd);
+ l_free(qmux);
+ return NULL;
+ }
+
+ return &qmux->super;
+}
+
struct qmi_param *qmi_param_new(void)
{
struct qmi_param *param;
@@ -81,8 +81,6 @@ typedef void (*qmi_debug_func_t)(const char *str, void *user_data);
typedef void (*qmi_shutdown_func_t)(void *user_data);
typedef void (*qmi_discover_func_t)(void *user_data);
-struct qmi_device *qmi_device_new(int fd);
-
struct qmi_device *qmi_device_ref(struct qmi_device *device);
void qmi_device_unref(struct qmi_device *device);
@@ -105,6 +103,8 @@ enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
bool qmi_device_set_expected_data_format(struct qmi_device *device,
enum qmi_device_expected_data_format format);
+struct qmi_device *qmi_device_new_qmux(const char *device);
+
struct qmi_param;
struct qmi_param *qmi_param_new(void);
@@ -423,7 +423,6 @@ static int gobi_enable(struct ofono_modem *modem)
{
struct gobi_data *data = ofono_modem_get_data(modem);
const char *device;
- int fd;
DBG("%p", modem);
@@ -431,15 +430,7 @@ static int gobi_enable(struct ofono_modem *modem)
if (!device)
return -EINVAL;
- fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
- if (fd < 0)
- return -EIO;
-
- data->device = qmi_device_new(fd);
- if (!data->device) {
- close(fd);
- return -ENOMEM;
- }
+ data->device = qmi_device_new_qmux(device);
if (getenv("OFONO_QMI_DEBUG"))
qmi_device_set_debug(data->device, gobi_debug, "QMI: ");