mirror of
https://gitlab.com/mobian1/eg25-manager.git
synced 2025-08-29 15:22:20 +02:00
196 lines
4.8 KiB
C
196 lines
4.8 KiB
C
/*
|
|
* Copyright (C) 2020 Arnaud Ferraris <arnaud.ferraris@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "at.h"
|
|
#include "gpio.h"
|
|
#include "manager.h"
|
|
#include "mm-iface.h"
|
|
#include "suspend.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <glib-unix.h>
|
|
#include <libusb.h>
|
|
|
|
#define EG25_USB_VID 0x2c7c
|
|
#define EG25_USB_PID 0x0125
|
|
|
|
static gboolean quit_app(struct EG25Manager *manager)
|
|
{
|
|
int i;
|
|
|
|
g_message("Request to quit...");
|
|
|
|
at_destroy(manager);
|
|
mm_iface_destroy(manager);
|
|
suspend_destroy(manager);
|
|
|
|
if (manager->modem_state >= EG25_STATE_STARTED) {
|
|
g_message("Powering down the modem...");
|
|
gpio_sequence_shutdown(manager);
|
|
manager->modem_state = EG25_STATE_FINISHING;
|
|
for (i = 0; i < 30; i++) {
|
|
if (gpio_check_poweroff(manager, TRUE))
|
|
break;
|
|
sleep(1);
|
|
}
|
|
}
|
|
g_message("Modem down, quitting...");
|
|
|
|
g_main_loop_quit(manager->loop);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean modem_start(struct EG25Manager *manager)
|
|
{
|
|
ssize_t i, count;
|
|
gboolean should_boot = TRUE;
|
|
libusb_context *ctx = NULL;
|
|
libusb_device **devices = NULL;
|
|
struct libusb_device_descriptor desc;
|
|
|
|
if (manager->braveheart) {
|
|
// BH don't have the STATUS line connected, so check if USB device is present
|
|
libusb_init(&ctx);
|
|
|
|
count = libusb_get_device_list(ctx, &devices);
|
|
for (i = 0; i < count; i++) {
|
|
libusb_get_device_descriptor(devices[i], &desc);
|
|
if (desc.idVendor == EG25_USB_VID && desc.idProduct == EG25_USB_PID) {
|
|
g_message("Found corresponding USB device, modem already powered");
|
|
should_boot = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
libusb_free_device_list(devices, 1);
|
|
libusb_exit(ctx);
|
|
} else if (!gpio_check_poweroff(manager, FALSE)) {
|
|
g_message("STATUS is low, modem already powered");
|
|
should_boot = FALSE;
|
|
}
|
|
|
|
if (should_boot) {
|
|
g_message("Starting modem...");
|
|
gpio_sequence_poweron(manager);
|
|
manager->modem_state = EG25_STATE_POWERED;
|
|
} else {
|
|
manager->modem_state = EG25_STATE_STARTED;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void modem_update_state(struct EG25Manager *manager, MMModemState state)
|
|
{
|
|
switch (state) {
|
|
case MM_MODEM_STATE_REGISTERED:
|
|
case MM_MODEM_STATE_DISCONNECTING:
|
|
case MM_MODEM_STATE_CONNECTING:
|
|
manager->modem_state = EG25_STATE_REGISTERED;
|
|
break;
|
|
case MM_MODEM_STATE_CONNECTED:
|
|
manager->modem_state = EG25_STATE_CONNECTED;
|
|
break;
|
|
default:
|
|
manager->modem_state = EG25_STATE_CONFIGURED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void modem_configure(struct EG25Manager *manager)
|
|
{
|
|
at_sequence_configure(manager);
|
|
}
|
|
|
|
void modem_reset(struct EG25Manager *manager)
|
|
{
|
|
int fd, ret, len = strlen(manager->modem_usb_id);
|
|
|
|
fd = open("/sys/bus/usb/drivers/usb/unbind", O_WRONLY);
|
|
if (fd < 0)
|
|
goto error;
|
|
ret = write(fd, manager->modem_usb_id, len);
|
|
if (ret < len)
|
|
g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len);
|
|
close(fd);
|
|
|
|
fd = open("/sys/bus/usb/drivers/usb/bind", O_WRONLY);
|
|
if (fd < 0)
|
|
goto error;
|
|
ret = write(fd, manager->modem_usb_id, len);
|
|
if (ret < len)
|
|
g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len);
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
error:
|
|
// Everything else failed, reset the modem
|
|
at_sequence_reset(manager);
|
|
manager->modem_state = EG25_STATE_RESETTING;
|
|
}
|
|
|
|
void modem_suspend(struct EG25Manager *manager)
|
|
{
|
|
gpio_sequence_suspend(manager);
|
|
at_sequence_suspend(manager);
|
|
}
|
|
|
|
void modem_resume_pre(struct EG25Manager *manager)
|
|
{
|
|
gpio_sequence_resume(manager);
|
|
}
|
|
|
|
void modem_resume_post(struct EG25Manager *manager)
|
|
{
|
|
at_sequence_resume(manager);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct EG25Manager manager;
|
|
char compatible[32];
|
|
int fd, ret;
|
|
|
|
memset(&manager, 0, sizeof(manager));
|
|
manager.at_fd = -1;
|
|
manager.suspend_inhibit_fd = -1;
|
|
|
|
manager.loop = g_main_loop_new(NULL, FALSE);
|
|
|
|
fd = open("/proc/device-tree/compatible", O_RDONLY);
|
|
if (fd < 0) {
|
|
g_critical("Unable to read 'compatible' string from device tree");
|
|
return 1;
|
|
}
|
|
ret = read(fd, compatible, sizeof(compatible));
|
|
if (ret > 0 && !strstr(compatible, "pine64,pinephone-1.2"))
|
|
manager.braveheart = TRUE;
|
|
close(fd);
|
|
|
|
at_init(&manager);
|
|
gpio_init(&manager);
|
|
mm_iface_init(&manager);
|
|
suspend_init(&manager);
|
|
|
|
g_idle_add(G_SOURCE_FUNC(modem_start), &manager);
|
|
|
|
g_unix_signal_add(SIGINT, G_SOURCE_FUNC(quit_app), &manager);
|
|
g_unix_signal_add(SIGTERM, G_SOURCE_FUNC(quit_app), &manager);
|
|
|
|
g_main_loop_run(manager.loop);
|
|
|
|
gpio_destroy(&manager);
|
|
|
|
return 0;
|
|
}
|