diff options
Diffstat (limited to 'samsung-ipc/devices/galaxys2/galaxys2.c')
-rw-r--r-- | samsung-ipc/devices/galaxys2/galaxys2.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/samsung-ipc/devices/galaxys2/galaxys2.c b/samsung-ipc/devices/galaxys2/galaxys2.c new file mode 100644 index 0000000..7070376 --- /dev/null +++ b/samsung-ipc/devices/galaxys2/galaxys2.c @@ -0,0 +1,398 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> + * + * libsamsung-ipc 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, either version 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc 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 libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include <samsung-ipc.h> +#include <ipc.h> + +#include "xmm6260.h" +#include "xmm6260_hsic.h" +#include "xmm6260_sec_modem.h" +#include "galaxys2.h" + +int galaxys2_boot(struct ipc_client *client) +{ + void *modem_image_data = NULL; + int modem_image_fd = -1; + int modem_boot_fd = -1; + int modem_link_fd = -1; + unsigned char *p; + int rc; + + if (client == NULL) + return -1; + + ipc_client_log(client, "Starting galaxys2 modem boot"); + + modem_image_fd = open(GALAXYS2_MODEM_IMAGE_DEVICE, O_RDONLY); + if (modem_image_fd < 0) { + ipc_client_log(client, "Opening modem image device failed"); + goto error; + } + ipc_client_log(client, "Opened modem image device"); + + modem_image_data = mmap(0, GALAXYS2_MODEM_IMAGE_SIZE, PROT_READ, MAP_SHARED, modem_image_fd, 0); + if (modem_image_data == NULL || modem_image_data == (void *) 0xffffffff) { + ipc_client_log(client, "Mapping modem image data to memory failed"); + goto error; + } + ipc_client_log(client, "Mapped modem image data to memory"); + + modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (modem_boot_fd < 0) { + ipc_client_log(client, "Opening modem boot device failed"); + goto error; + } + ipc_client_log(client, "Opened modem boot device"); + + modem_link_fd = open(XMM6260_SEC_MODEM_LINK_PM_DEVICE, O_RDWR); + if (modem_link_fd < 0) { + ipc_client_log(client, "Opening modem link device failed"); + goto error; + } + ipc_client_log(client, "Opened modem link device"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 0); + rc |= xmm6260_sec_modem_link_control_enable(modem_link_fd, 0); + rc |= xmm6260_sec_modem_hci_power(0); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 0); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem off failed"); + goto error; + } + ipc_client_log(client, "Turned the modem off"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 1); + rc |= xmm6260_sec_modem_link_control_enable(modem_link_fd, 1); + rc |= xmm6260_sec_modem_hci_power(1); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 1); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem on failed"); + goto error; + } + ipc_client_log(client, "Turned the modem on"); + + rc = xmm6260_sec_modem_link_connected_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for link connected failed"); + goto error; + } + ipc_client_log(client, "Waited for link connected"); + + p = (unsigned char *) modem_image_data + GALAXYS2_PSI_OFFSET; + + rc = xmm6260_hsic_psi_send(client, modem_boot_fd, (void *) p, GALAXYS2_PSI_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC PSI failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC PSI"); + + p = (unsigned char *) modem_image_data + GALAXYS2_EBL_OFFSET; + + rc = xmm6260_hsic_ebl_send(client, modem_boot_fd, (void *) p, GALAXYS2_EBL_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC EBL failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC EBL"); + + rc = xmm6260_hsic_port_config_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC port config failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC port config"); + + p = (unsigned char *) modem_image_data + GALAXYS2_SEC_START_OFFSET; + + rc = xmm6260_hsic_sec_start_send(client, modem_boot_fd, (void *) p, GALAXYS2_SEC_START_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC SEC start failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC SEC start"); + + p = (unsigned char *) modem_image_data + GALAXYS2_FIRMWARE_OFFSET; + + rc = xmm6260_hsic_firmware_send(client, modem_boot_fd, (void *) p, GALAXYS2_FIRMWARE_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC firmware failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC firmware"); + + rc = xmm6260_hsic_nv_data_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC nv_data failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC nv_data"); + + rc = xmm6260_hsic_sec_end_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC SEC end failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC SEC end"); + + rc = xmm6260_hsic_hw_reset_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC HW reset failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC HW reset"); + + usleep(300000); + + rc = xmm6260_sec_modem_link_get_hostwake_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for host wake failed"); + } + + rc = xmm6260_sec_modem_link_control_enable(modem_link_fd, 0); + rc |= xmm6260_sec_modem_hci_power(0); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 0); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem off failed"); + goto error; + } + + rc = xmm6260_sec_modem_link_get_hostwake_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for host wake failed"); + goto error; + } + ipc_client_log(client, "Waited for host wake"); + + rc = xmm6260_sec_modem_link_control_enable(modem_link_fd, 1); + rc |= xmm6260_sec_modem_hci_power(1); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 1); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem on failed"); + goto error; + } + + rc = xmm6260_sec_modem_link_connected_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for link connected failed"); + goto error; + } + ipc_client_log(client, "Waited for link connected"); + + usleep(300000); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (modem_image_data != NULL) + munmap(modem_image_data, GALAXYS2_MODEM_IMAGE_SIZE); + + if (modem_image_fd >= 0) + close(modem_image_fd); + + if (modem_boot_fd >= 0) + close(modem_boot_fd); + + if (modem_link_fd >= 0) + close(modem_link_fd); + + return rc; +} + +int galaxys2_open(void *data, int type) +{ + struct galaxys2_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_transport_data *) data; + + transport_data->fd = xmm6260_sec_modem_open(type); + if (transport_data->fd < 0) + return -1; + + return 0; +} + +int galaxys2_close(void *data) +{ + struct galaxys2_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_transport_data *) data; + + xmm6260_sec_modem_close(transport_data->fd); + transport_data->fd = -1; + + return 0; +} + +int galaxys2_read(void *data, void *buffer, size_t length) +{ + struct galaxys2_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_transport_data *) data; + + rc = xmm6260_sec_modem_read(transport_data->fd, buffer, length); + + return rc; +} + +int galaxys2_write(void *data, const void *buffer, size_t length) +{ + struct galaxys2_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_transport_data *) data; + + rc = xmm6260_sec_modem_write(transport_data->fd, buffer, length); + + return rc; +} + +int galaxys2_poll(void *data, struct timeval *timeout) +{ + struct galaxys2_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_transport_data *) data; + + rc = xmm6260_sec_modem_poll(transport_data->fd, timeout); + + return rc; +} + +int galaxys2_power_on(void *data) +{ + return 0; +} + +int galaxys2_power_off(void *data) +{ + int fd; + int rc; + + fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + return -1; + + rc = xmm6260_sec_modem_power(fd, 0); + + close(fd); + + if (rc < 0) + return -1; + + return 0; +} + +int galaxys2_data_create(void **transport_data, void **power_data, + void **gprs_data) +{ + if (transport_data == NULL) + return -1; + + *transport_data = calloc(1, sizeof(struct galaxys2_transport_data)); + + return 0; +} + +int galaxys2_data_destroy(void *transport_data, void *power_data, + void *gprs_data) +{ + if (transport_data == NULL) + return -1; + + free(transport_data); + + return 0; +} + +struct ipc_client_ops galaxys2_fmt_ops = { + .boot = galaxys2_boot, + .send = xmm6260_sec_modem_fmt_send, + .recv = xmm6260_sec_modem_fmt_recv, +}; + +struct ipc_client_ops galaxys2_rfs_ops = { + .boot = NULL, + .send = xmm6260_sec_modem_rfs_send, + .recv = xmm6260_sec_modem_rfs_recv, +}; + +struct ipc_client_handlers galaxys2_handlers = { + .read = galaxys2_read, + .write = galaxys2_write, + .open = galaxys2_open, + .close = galaxys2_close, + .poll = galaxys2_poll, + .transport_data = NULL, + .power_on = galaxys2_power_on, + .power_off = galaxys2_power_off, + .power_data = NULL, + .gprs_activate = NULL, + .gprs_deactivate = NULL, + .gprs_data = NULL, + .data_create = galaxys2_data_create, + .data_destroy = galaxys2_data_destroy, +}; + +struct ipc_client_gprs_specs galaxys2_gprs_specs = { + .gprs_get_iface = xmm6260_sec_modem_gprs_get_iface, + .gprs_get_capabilities = xmm6260_sec_modem_gprs_get_capabilities, +}; + +struct ipc_client_nv_data_specs galaxys2_nv_data_specs = { + .nv_data_path = XMM6260_NV_DATA_PATH, + .nv_data_md5_path = XMM6260_NV_DATA_MD5_PATH, + .nv_data_backup_path = XMM6260_NV_DATA_BACKUP_PATH, + .nv_data_backup_md5_path = XMM6260_NV_DATA_BACKUP_MD5_PATH, + .nv_data_secret = XMM6260_NV_DATA_SECRET, + .nv_data_size = XMM6260_NV_DATA_SIZE, + .nv_data_chunk_size = XMM6260_NV_DATA_CHUNK_SIZE, +}; + +// vim:ts=4:sw=4:expandtab |