diff options
Diffstat (limited to 'net/can')
-rw-r--r-- | net/can/Makefile.objs | 1 | ||||
-rw-r--r-- | net/can/can_core.c | 138 | ||||
-rw-r--r-- | net/can/can_host.c | 112 |
3 files changed, 251 insertions, 0 deletions
diff --git a/net/can/Makefile.objs b/net/can/Makefile.objs new file mode 100644 index 0000000000..ef97fdb8d1 --- /dev/null +++ b/net/can/Makefile.objs @@ -0,0 +1 @@ +common-obj-y += can_core.o can_host.o diff --git a/net/can/can_core.c b/net/can/can_core.c new file mode 100644 index 0000000000..2a83cadfc5 --- /dev/null +++ b/net/can/can_core.c @@ -0,0 +1,138 @@ +/* + * CAN common CAN bus emulation support + * + * Copyright (c) 2013-2014 Jin Yang + * Copyright (c) 2014-2018 Pavel Pisa + * + * Initial development supported by Google GSoC 2013 from RTEMS project slot + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "chardev/char.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "net/can_emu.h" +#include "qom/object_interfaces.h" + +struct CanBusState { + Object object; + + QTAILQ_HEAD(, CanBusClientState) clients; +}; + +static void can_bus_instance_init(Object *object) +{ + CanBusState *bus = (CanBusState *)object; + + QTAILQ_INIT(&bus->clients); +} + +int can_bus_insert_client(CanBusState *bus, CanBusClientState *client) +{ + client->bus = bus; + QTAILQ_INSERT_TAIL(&bus->clients, client, next); + return 0; +} + +int can_bus_remove_client(CanBusClientState *client) +{ + CanBusState *bus = client->bus; + if (bus == NULL) { + return 0; + } + + QTAILQ_REMOVE(&bus->clients, client, next); + client->bus = NULL; + return 1; +} + +ssize_t can_bus_client_send(CanBusClientState *client, + const struct qemu_can_frame *frames, size_t frames_cnt) +{ + int ret = 0; + CanBusState *bus = client->bus; + CanBusClientState *peer; + if (bus == NULL) { + return -1; + } + + QTAILQ_FOREACH(peer, &bus->clients, next) { + if (peer->info->can_receive(peer)) { + if (peer == client) { + /* No loopback support for now */ + continue; + } + if (peer->info->receive(peer, frames, frames_cnt) > 0) { + ret = 1; + } + } + } + + return ret; +} + +int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id) +{ + int m; + if (((can_id | filter->can_mask) & QEMU_CAN_ERR_FLAG)) { + return (filter->can_mask & QEMU_CAN_ERR_FLAG) != 0; + } + m = (can_id & filter->can_mask) == (filter->can_id & filter->can_mask); + return filter->can_id & QEMU_CAN_INV_FILTER ? !m : m; +} + +int can_bus_client_set_filters(CanBusClientState *client, + const struct qemu_can_filter *filters, size_t filters_cnt) +{ + return 0; +} + + +static bool can_bus_can_be_deleted(UserCreatable *uc) +{ + return false; +} + +static void can_bus_class_init(ObjectClass *klass, + void *class_data G_GNUC_UNUSED) +{ + UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); + + uc_klass->can_be_deleted = can_bus_can_be_deleted; +} + +static const TypeInfo can_bus_info = { + .parent = TYPE_OBJECT, + .name = TYPE_CAN_BUS, + .instance_size = sizeof(CanBusState), + .instance_init = can_bus_instance_init, + .class_init = can_bus_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void can_bus_register_types(void) +{ + type_register_static(&can_bus_info); +} + +type_init(can_bus_register_types); diff --git a/net/can/can_host.c b/net/can/can_host.c new file mode 100644 index 0000000000..c3d26521cd --- /dev/null +++ b/net/can/can_host.c @@ -0,0 +1,112 @@ +/* + * CAN generic CAN host connection support + * + * Copyright (c) 2013-2014 Jin Yang + * Copyright (c) 2014-2018 Pavel Pisa + * + * Initial development supported by Google GSoC 2013 from RTEMS project slot + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "chardev/char.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "net/can_emu.h" +#include "net/can_host.h" + +struct CanBusState { + Object object; + + QTAILQ_HEAD(, CanBusClientState) clients; +}; + +static void can_host_disconnect(CanHostState *ch) +{ + CanHostClass *chc = CAN_HOST_GET_CLASS(ch); + + can_bus_remove_client(&ch->bus_client); + chc->disconnect(ch); +} + +static void can_host_connect(CanHostState *ch, Error **errp) +{ + CanHostClass *chc = CAN_HOST_GET_CLASS(ch); + Error *local_err = NULL; + + chc->connect(ch, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + can_bus_insert_client(ch->bus, &ch->bus_client); +} + +static void can_host_unparent(Object *obj) +{ + can_host_disconnect(CAN_HOST(obj)); +} + +static void can_host_complete(UserCreatable *uc, Error **errp) +{ + can_host_connect(CAN_HOST(uc), errp); +} + +static void can_host_instance_init(Object *obj) +{ + CanHostState *ch = CAN_HOST(obj); + + object_property_add_link(obj, "canbus", TYPE_CAN_BUS, + (Object **)&ch->bus, + object_property_allow_set_link, + OBJ_PROP_LINK_UNREF_ON_RELEASE, + &error_abort); +} + +static void can_host_class_init(ObjectClass *klass, + void *class_data G_GNUC_UNUSED) +{ + UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); + + klass->unparent = can_host_unparent; + uc_klass->complete = can_host_complete; +} + +static const TypeInfo can_host_info = { + .parent = TYPE_OBJECT, + .name = TYPE_CAN_HOST, + .instance_size = sizeof(CanHostState), + .class_size = sizeof(CanHostClass), + .abstract = true, + .instance_init = can_host_instance_init, + .class_init = can_host_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void can_host_register_types(void) +{ + type_register_static(&can_host_info); +} + +type_init(can_host_register_types); |