From: Baptiste Reynal <b.rey...@virtualopensystems.com> This is the socket implementation of an SDM communication channel. A master device can communicate with a slave over a socket.
Parameters: socket=[socket_id] - specifies the multi-client socket This patch depends on "[RFC v2 1/1] backend: multi-client-socket" Signed-off-by: Baptiste Reynal <b.rey...@virtualopensystems.com> Signed-off-by: Christian Pinto <c.pi...@virtualopensystems.com> --- v2 -> v3: - added sdm_socket_update_num_slaves to socket based communication channel - realloc slaves array in case of max slaves num change --- hw/misc/Makefile.objs | 1 + hw/misc/sdm-communication-socket.c | 160 +++++++++++++++++++++++++++++ include/hw/misc/sdm-communication-socket.h | 42 ++++++++ 3 files changed, 203 insertions(+) create mode 100644 hw/misc/sdm-communication-socket.c create mode 100644 include/hw/misc/sdm-communication-socket.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index cad0b4c..8f38d35 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -26,6 +26,7 @@ obj-$(CONFIG_SDM) += sdm-communication.o obj-$(CONFIG_SDM) += sdm-signal.o obj-$(CONFIG_SDM) += sdm-platform.o obj-$(CONFIG_SDM) += sdm-communication-local.o +obj-$(CONFIG_SDM) += sdm-communication-socket.o obj-$(CONFIG_REALVIEW) += arm_sysctl.o obj-$(CONFIG_NSERIES) += cbus.o diff --git a/hw/misc/sdm-communication-socket.c b/hw/misc/sdm-communication-socket.c new file mode 100644 index 0000000..15ebed7 --- /dev/null +++ b/hw/misc/sdm-communication-socket.c @@ -0,0 +1,160 @@ +/* + * SDM Communication Socket + * + * Copyright (C) 2016 - Virtual Open Systems + * + * Author: Baptiste Reynal <b.rey...@virtualopensystems.com> + * Christian Pinto <c.pi...@virtualopensystems.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include "hw/misc/sdm-communication-socket.h" +#include "hw/qdev-properties.h" +#include "qemu/error-report.h" + +static int sdm_socket_signal(SDMCommunication *sdmc, SDMDevice *sdm, + SDMSignalData *signal) +{ + SDMCommunicationSocket *sdmcs = SDM_COMMUNICATION_SOCKET(sdmc); + int len; + char *message; + SDMSignalData *payload; + + if (!sdmcs->slaves[signal->slave]) { + error_report("SDMCommunicationSocket: invalid slave ID %d", + signal->slave); + return -1; + } + + len = strlen(SDM_SIGNAL_CMD) + sizeof(SDMSignalData) + 1; + message = malloc(len); + + strcpy((char *) message, SDM_SIGNAL_CMD); + payload = (SDMSignalData *) (message + strlen(SDM_SIGNAL_CMD) + 1); + memcpy(payload, signal, sizeof(SDMSignalData)); + + multi_socket_write_to(sdmcs->slaves[signal->slave], + message, + len); + + return 0; +} + +static void sdm_register_ms_handler(MSClient *c, const char *message, + void *opaque) +{ + SDMCommunication *sdmc = opaque; + SDMCommunicationSocket *sdmcs = SDM_COMMUNICATION_SOCKET(sdmc); + int slave_id; + + slave_id = sdm_device_accept(sdmcs->master); + if (slave_id >= 0) { + sdmcs->slaves[slave_id] = c; + } else { + error_report("SDMCommunicationSocket: Slave rejected, no ID available"); + } +} + +static void sdm_signal_ms_handler(MSClient *c, const char *message, + void *opaque) +{ + SDMCommunication *sdmc = opaque; + SDMCommunicationSocket *sdmcs = SDM_COMMUNICATION_SOCKET(sdmc); + int slave; + SDMSignalData *signal; + + signal = (SDMSignalData *) message; + + /* Find slave id */ + for (slave=0; slave<=sdmcs->num_slaves; slave++) { + if (sdmcs->slaves[slave] == c) + break; + } + + signal->slave = slave; + + while (sdm_device_notify(sdmcs->master, signal) < 0) { + sleep(100); + } +} + +static int sdm_socket_connect(SDMCommunication *sdmc, SDMDevice *sdm) +{ + SDMCommunicationSocket *sdmcs = SDM_COMMUNICATION_SOCKET(sdmc); + + sdmcs->master = sdm; + + sdmcs->num_slaves = sdm_device_get_num_slaves(sdm); + sdmcs->slaves = calloc(sdmcs->num_slaves + 1, + sizeof(MSClient *)); + + sdmcs->slaves[0] = &sdmcs->socket->listener; + multi_socket_add_handler(sdmcs->socket, SDM_SIGNAL_CMD, + sdm_signal_ms_handler, sdmc); + + if (sdm_device_is_master(sdm)) { + multi_socket_add_handler(sdmcs->socket, SDM_REGISTER_CMD, + sdm_register_ms_handler, sdmc); + } else { + multi_socket_write_to(sdmcs->slaves[0], + SDM_REGISTER_CMD, + strlen(SDM_REGISTER_CMD) + 1); + } + + return 0; +} + +static int sdm_socket_update_num_slaves(SDMCommunication *sdmc, SDMDevice *sdm, + uint16_t num_slaves) +{ + SDMCommunicationSocket *sdmcs = SDM_COMMUNICATION_SOCKET(sdmc); + MSClient **tmp_slaves; + + tmp_slaves = realloc(sdmcs->slaves, (num_slaves + 1) * + sizeof(MSClient *)); + + if(tmp_slaves == NULL) + return -1; + + sdmcs->slaves = tmp_slaves; + sdmcs->num_slaves = num_slaves; + sdm_device_set_num_slaves(sdm, num_slaves); + + return 0; +} + +static void sdm_communication_socket_class_init(ObjectClass *oc, void *data) +{ + SDMCommunicationClass *sdmck = SDM_COMMUNICATION_CLASS(oc); + + sdmck->signal = sdm_socket_signal; + sdmck->connect = sdm_socket_connect; + sdmck->update_num_slaves = sdm_socket_update_num_slaves; +} + +static void sdm_communication_socket_init(Object *obj) +{ + SDMCommunicationSocket *s = SDM_COMMUNICATION_SOCKET(obj); + + object_property_add_link(obj, "socket", TYPE_MULTI_SOCKET_BACKEND, + (Object **)&s->socket, + object_property_allow_set_link, + OBJ_PROP_LINK_UNREF_ON_RELEASE, + &error_abort); +} + +static const TypeInfo sdm_communication_socket_info = { + .name = TYPE_SDM_COMMUNICATION_SOCKET, + .parent = TYPE_SDM_COMMUNICATION, + .class_init = sdm_communication_socket_class_init, + .instance_size = sizeof(SDMCommunicationSocket), + .instance_init = sdm_communication_socket_init, +}; + +static void register_types(void) +{ + type_register_static(&sdm_communication_socket_info); +} + +type_init(register_types); diff --git a/include/hw/misc/sdm-communication-socket.h b/include/hw/misc/sdm-communication-socket.h new file mode 100644 index 0000000..aa24454 --- /dev/null +++ b/include/hw/misc/sdm-communication-socket.h @@ -0,0 +1,42 @@ +/* + * SDM Communication Socket + * + * Copyright (C) 2016 - Virtual Open Systems + * + * Author: Baptiste Reynal <b.rey...@virtualopensystems.com> + * + * This works is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#ifndef HW_SDM_COMM_SOCK_H +#define HW_SDM_COMM_SOCK_H + +#include "hw/misc/sdm-communication.h" +#include "qemu/multi-socket.h" + +#define SDM_REGISTER_CMD "sdm_register" +#define SDM_SIGNAL_CMD "sdm_signal" + +#define TYPE_SDM_COMMUNICATION_SOCKET "sdm-communication-socket" +#define SDM_COMMUNICATION_SOCKET(obj) \ + OBJECT_CHECK(SDMCommunicationSocket, (obj), \ + TYPE_SDM_COMMUNICATION_SOCKET) + +typedef struct SDMCommunicationSocket SDMCommunicationSocket; + +/** + * @SDMCommunicationSocket + * + * @parent: opaque parent object container + */ +struct SDMCommunicationSocket { + /* private */ + SDMCommunication parent; + + SDMDevice *master; + MSBackend *socket; + + int num_slaves; + MSClient **slaves; +}; +#endif -- 1.9.1