All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
@ 2018-01-06 20:47 pisa
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU pisa
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Basic emulation of CAN bus controller and interconnection for QEMU.

Patches version 3:
Support to connect to host SocketCAN interface has been
separated from the core bus implementation. Only simple
statically initialize pointer to the connection function
is used, no QOM concept for now.
SJA1000 message filters redone and code unified where
possible.
Basic documentation added.
QEMU_ALIGNED used in definition of CAN frame structure,
structure and defines still separated from Linux/SocketCAN
API defined ones to allow to keep QEMU message format
independed from host system one. Check for correspondence
to socketcan one added.

Patches version 2:
The bus emulation and the SJA1000 chip emulation introduced
by individual patches as suggested by Frederic Konrad.
Simple example board to test SJA1000 as single memory-mapped BAR
has been omitted in a new series because emulation of real
existing boards can provide same functions now.
Conditionalized debug printfs changed to be exposed to compiler
syntax check as suggested in review.

The work has been started by Jin Yang in the frame of GSoC 2013 slot
contributed by RTEMS project which has been looking for environment
to allow develop and test CAN drivers for multiple CPU architectures.

I have menthored the project and then done substantial code cleanup
and update to QOM. Deniz Eren then used emulation for SJA1000 base card
driver development for other operating system and contributed
PCM-3680I and MIOe-3680 support.

Some page about the project

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/wikis/home

FEE CTU GitLab repository with can-pci branch for 2.3, 2.4, 2.7, 2.8, 2.10 and 2.11
version if QEMU is available there

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci

mirror at GitHub

  https://github.com/CTU-IIG/qemu

There are many areas for improvement and extension of the code still
(for example freeze and migration is not implemented. CAN controllers
use proper QOM model but bus/interconnection emulation uses simple broadcast
connection which is required for CAN, but it is not based on QEMU bus model).
I have tried to look into QEMU VLANs implementation but it
does not map straightforward to CAN and I would need some help/opinion
from more advanced developers to decide what is their right
mapping to CAN.

CAN-FD support would be interesting requires other developers/
companies contributions or setup of some project to allow invite
some students and colleagues from my university into project.

But I believe that (even in its actual state) provided solution
is great help for embedded systems developers when they can connect
SocketCAN from one or more embedded systems running in virtual
environment together or with Linux host SocketCAN virtual
or real bus interfaces.

We have even tested our generic CANopen device configured
for CANopen 401 profile for generic I/O running in the virtual
system which can control GPIO inputs/outputs through virtual
industrial I/O card.

Generally QEMU can be interesting setup which allows
to test complete industrial and automotive applications
in virtual environment even before real hardware is availabe.

Deniz Eren (2):
  CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.

Pavel Pisa (5):
  CAN bus simple messages transport implementation for QEMU
  CAN bus support to connect bust to Linux host SocketCAN interface.
  CAN bus SJA1000 chip register level emulation for QEMU
  CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  QEMU CAN bus emulation documentation

 default-configs/pci.mak   |   3 +
 docs/can.txt              |  78 ++++
 hw/Makefile.objs          |   1 +
 hw/can/Makefile.objs      |  14 +
 hw/can/can_core.c         | 129 ++++++
 hw/can/can_host_stub.c    |  36 ++
 hw/can/can_kvaser_pci.c   | 375 +++++++++++++++++
 hw/can/can_mioe3680_pci.c | 335 ++++++++++++++++
 hw/can/can_pcm3680_pci.c  | 335 ++++++++++++++++
 hw/can/can_sja1000.c      | 996 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/can/can_sja1000.h      | 176 ++++++++
 hw/can/can_socketcan.c    | 294 ++++++++++++++
 include/can/can_emu.h     | 143 +++++++
 13 files changed, 2915 insertions(+)
 create mode 100644 docs/can.txt
 create mode 100644 hw/can/Makefile.objs
 create mode 100644 hw/can/can_core.c
 create mode 100644 hw/can/can_host_stub.c
 create mode 100644 hw/can/can_kvaser_pci.c
 create mode 100644 hw/can/can_mioe3680_pci.c
 create mode 100644 hw/can/can_pcm3680_pci.c
 create mode 100644 hw/can/can_sja1000.c
 create mode 100644 hw/can/can_sja1000.h
 create mode 100644 hw/can/can_socketcan.c
 create mode 100644 include/can/can_emu.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-12 10:07   ` KONRAD Frederic
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

The CanBusState state structure is created for each
emulated CAN channel. Individual clients/emulated
CAN interfaces or host interface connection registers
to the bus by CanBusClientState structure.

The CAN core is prepared to support connection to the
real host CAN bus network. The commit with such support
for Linux SocketCAN follows.

Implementation is as simple as possible, no migration,
messages prioritization and queuing considered for now.
But it is intended to be extended when need arises.

Development repository and more documentation at

https://gitlab.fel.cvut.cz/canbus/qemu-canbus

The work is based on Jin Yang GSoC 2013 work funded
by Google and mentored in frame of RTEMS project GSoC
slot donated to QEMU.

Rewritten for QEMU-2.0+ versions and architecture cleanup
by Pavel Pisa (Czech Technical University in Prague).

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 default-configs/pci.mak |   1 +
 hw/Makefile.objs        |   1 +
 hw/can/Makefile.objs    |   6 ++
 hw/can/can_core.c       | 129 +++++++++++++++++++++++++++++++++++++++++++
 hw/can/can_host_stub.c  |  36 ++++++++++++
 include/can/can_emu.h   | 143 ++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 316 insertions(+)
 create mode 100644 hw/can/Makefile.objs
 create mode 100644 hw/can/can_core.c
 create mode 100644 hw/can/can_host_stub.c
 create mode 100644 include/can/can_emu.h

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index e514bdef42..bbe11887a1 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -31,6 +31,7 @@ CONFIG_ESP_PCI=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_ISA=y
 CONFIG_SERIAL_PCI=y
+CONFIG_CAN_CORE=y
 CONFIG_IPACK=y
 CONFIG_WDT_IB6300ESB=y
 CONFIG_PCI_TESTDEV=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index cf4cb2010b..9d84b8faaa 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -6,6 +6,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += block/
 devices-dirs-$(CONFIG_SOFTMMU) += bt/
 devices-dirs-$(CONFIG_SOFTMMU) += char/
 devices-dirs-$(CONFIG_SOFTMMU) += cpu/
+devices-dirs-$(CONFIG_SOFTMMU) += can/
 devices-dirs-$(CONFIG_SOFTMMU) += display/
 devices-dirs-$(CONFIG_SOFTMMU) += dma/
 devices-dirs-$(CONFIG_SOFTMMU) += gpio/
diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
new file mode 100644
index 0000000000..1028d7c455
--- /dev/null
+++ b/hw/can/Makefile.objs
@@ -0,0 +1,6 @@
+# CAN bus interfaces emulation and infrastructure
+
+ifeq ($(CONFIG_CAN_CORE),y)
+common-obj-y += can_core.o
+common-obj-y += can_host_stub.o
+endif
diff --git a/hw/can/can_core.c b/hw/can/can_core.c
new file mode 100644
index 0000000000..49ba3c6ef2
--- /dev/null
+++ b/hw/can/can_core.c
@@ -0,0 +1,129 @@
+/*
+ * 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 "qemu/error-report.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+#ifndef DEBUG_CAN
+#define DEBUG_CAN 0
+#endif /*DEBUG_CAN*/
+
+static QTAILQ_HEAD(, CanBusState) can_buses =
+    QTAILQ_HEAD_INITIALIZER(can_buses);
+
+CanBusState *can_bus_find_by_name(const char *name, bool create_missing)
+{
+    CanBusState *bus;
+
+    if (name == NULL) {
+        name = "canbus0";
+    }
+
+    QTAILQ_FOREACH(bus, &can_buses, next) {
+        if (!strcmp(bus->name, name)) {
+            return bus;
+        }
+    }
+
+    if (!create_missing) {
+        return 0;
+    }
+
+    bus = g_malloc0(sizeof(*bus));
+    if (bus == NULL) {
+        return NULL;
+    }
+
+    QTAILQ_INIT(&bus->clients);
+
+    bus->name = g_strdup(name);
+
+    QTAILQ_INSERT_TAIL(&can_buses, bus, next);
+    return bus;
+}
+
+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_client_set_filters(CanBusClientState *client,
+             const struct qemu_can_filter *filters, size_t filters_cnt)
+{
+    return 0;
+}
+
+int can_bus_connect_to_host_device(CanBusState *bus, const char *name)
+{
+    if (can_bus_connect_to_host_variant == NULL) {
+        error_report("CAN bus connect to host device not supported on this system");
+        exit(1);
+    }
+    return can_bus_connect_to_host_variant(bus, name);
+}
diff --git a/hw/can/can_host_stub.c b/hw/can/can_host_stub.c
new file mode 100644
index 0000000000..748d25f995
--- /dev/null
+++ b/hw/can/can_host_stub.c
@@ -0,0 +1,36 @@
+/*
+ * CAN stub to connect to host system CAN interface
+ *
+ * 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 "qemu/error-report.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+
+int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
+        NULL;
diff --git a/include/can/can_emu.h b/include/can/can_emu.h
new file mode 100644
index 0000000000..5c149a2ae9
--- /dev/null
+++ b/include/can/can_emu.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#ifndef NET_CAN_EMU_H
+#define NET_CAN_EMU_H
+
+#include "qemu/queue.h"
+
+/* NOTE: the following two structures is copied from <linux/can.h>. */
+
+/*
+ * Controller Area Network Identifier structure
+ *
+ * bit 0-28    : CAN identifier (11/29 bit)
+ * bit 29      : error frame flag (0 = data frame, 1 = error frame)
+ * bit 30      : remote transmission request flag (1 = rtr frame)
+ * bit 31      : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+typedef uint32_t qemu_canid_t;
+
+typedef struct qemu_can_frame {
+    qemu_canid_t    can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+    uint8_t         can_dlc; /* data length code: 0 .. 8 */
+    uint8_t         data[8] QEMU_ALIGNED(8);
+} qemu_can_frame;
+
+/* Keep defines for QEMU separate from Linux ones for now */
+
+#define QEMU_CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
+#define QEMU_CAN_RTR_FLAG 0x40000000U /* remote transmission request */
+#define QEMU_CAN_ERR_FLAG 0x20000000U /* error message frame */
+
+#define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
+#define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
+
+/**
+ * struct qemu_can_filter - CAN ID based filter in can_register().
+ * @can_id:   relevant bits of CAN ID which are not masked out.
+ * @can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *          <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (QEMU_CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error message frames (QEMU_CAN_ERR_FLAG bit set in mask).
+ */
+typedef struct qemu_can_filter {
+    qemu_canid_t    can_id;
+    qemu_canid_t    can_mask;
+} qemu_can_filter;
+
+#define QEMU_CAN_INV_FILTER 0x20000000U /* to be set in qemu_can_filter.can_id */
+
+typedef struct CanBusClientState CanBusClientState;
+typedef struct CanBusState CanBusState;
+
+typedef struct CanBusClientInfo {
+    /*CanBusClientOptionsKind type;*/
+    size_t size;
+    int (*can_receive)(CanBusClientState *);
+    ssize_t (*receive)(CanBusClientState *,
+        const struct qemu_can_frame *frames, size_t frames_cnt);
+    void (*cleanup) (CanBusClientState *);
+    void (*poll)(CanBusClientState *, bool enable);
+} CanBusClientInfo;
+
+struct CanBusClientState {
+    CanBusClientInfo *info;
+    CanBusState *bus;
+    int link_down;
+    QTAILQ_ENTRY(CanBusClientState) next;
+    CanBusClientState *peer;
+    /*CanBusQueue *incoming_queue;*/
+    char *model;
+    char *name;
+    /*unsigned receive_disabled : 1;*/
+    void (*destructor)(CanBusClientState *);
+    /*unsigned int queue_index;*/
+    /*unsigned rxfilter_notify_enabled:1;*/
+};
+
+struct CanBusState {
+    char *name;
+    QTAILQ_HEAD(, CanBusClientState) clients;
+    QTAILQ_ENTRY(CanBusState) next;
+};
+
+extern int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name);
+
+static inline
+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;
+}
+
+CanBusState *can_bus_find_by_name(const char *name, bool create_missing);
+
+int can_bus_insert_client(CanBusState *bus, CanBusClientState *client);
+
+int can_bus_remove_client(CanBusClientState *client);
+
+ssize_t can_bus_client_send(CanBusClientState *,
+                            const struct qemu_can_frame *frames,
+                            size_t frames_cnt);
+
+int can_bus_client_set_filters(CanBusClientState *,
+                               const struct qemu_can_filter *filters,
+                               size_t filters_cnt);
+
+int can_bus_connect_to_host_device(CanBusState *bus, const char *host_dev_name);
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Connection to the real host CAN bus network through
SocketCAN network interface is available only for Linux
host system. Mechanism is generic, support for another
CAN API and operating systems can be implemented in future.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 hw/can/Makefile.objs   |   4 +
 hw/can/can_socketcan.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 298 insertions(+)
 create mode 100644 hw/can/can_socketcan.c

diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 1028d7c455..f999085f7a 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -2,5 +2,9 @@
 
 ifeq ($(CONFIG_CAN_CORE),y)
 common-obj-y += can_core.o
+ifeq ($(CONFIG_LINUX),y)
+common-obj-y += can_socketcan.o
+else
 common-obj-y += can_host_stub.o
 endif
+endif
diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
new file mode 100644
index 0000000000..130c80ba27
--- /dev/null
+++ b/hw/can/can_socketcan.c
@@ -0,0 +1,294 @@
+/*
+ * CAN socketcan support to connect to the Linux host SocketCAN interfaces
+ *
+ * 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 "qemu/error-report.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/can.h>
+#include <linux/can/raw.h>
+
+#ifndef DEBUG_CAN
+#define DEBUG_CAN 0
+#endif /*DEBUG_CAN*/
+
+#define CAN_READ_BUF_LEN  5
+typedef struct {
+    CanBusClientState  bus_client;
+    qemu_can_filter    *rfilter;
+    int                rfilter_num;
+    can_err_mask_t     err_mask;
+
+    qemu_can_frame     buf[CAN_READ_BUF_LEN];
+    int                bufcnt;
+    int                bufptr;
+
+    int                fd;
+} CanBusSocketcanConnectState;
+
+static void can_display_msg(struct qemu_can_frame *msg)
+{
+    int i;
+
+    /* Check that QEMU and Linux kernel flags encoding matches */
+    assert(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
+    assert(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
+    assert(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
+
+    assert(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
+
+    fprintf(stderr, "%03X [%01d]:", (msg->can_id & 0x1fffffff), msg->can_dlc);
+    for (i = 0; i < msg->can_dlc; i++) {
+        fprintf(stderr, "  %02X", msg->data[i]);
+    }
+    fprintf(stderr, "\n");
+}
+
+static void can_bus_socketcan_read(void *opaque)
+{
+    CanBusSocketcanConnectState *c;
+    c = (CanBusSocketcanConnectState *)opaque;
+
+
+
+    /* CAN_READ_BUF_LEN for multiple messages syscall is possible for future */
+    c->bufcnt = read(c->fd, c->buf, sizeof(qemu_can_frame));
+    if (c->bufcnt < 0) {
+        perror("CAN bus host read");
+        return;
+    }
+
+    can_bus_client_send(&c->bus_client, c->buf, 1);
+
+    if (DEBUG_CAN) {
+        can_display_msg(c->buf); /* Just display the first one. */
+    }
+}
+
+static int can_bus_socketcan_can_receive(CanBusClientState *client)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+
+    if (c->fd < 0) {
+        return -1;
+    }
+
+    return 1;
+}
+
+static ssize_t can_bus_socketcan_receive(CanBusClientState *client,
+                            const qemu_can_frame *frames, size_t frames_cnt)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+    size_t len = sizeof(qemu_can_frame);
+    int res;
+
+    if (c->fd < 0) {
+        return -1;
+    }
+
+    res = write(c->fd, frames, len);
+
+    if (!res) {
+        fprintf(stderr, "CAN bus write to host device zero length\n");
+        return -1;
+    }
+
+    /* send frame */
+    if (res != len) {
+        perror("CAN bus write to host device error");
+        return -1;
+    }
+
+    return 1;
+}
+
+static void can_bus_socketcan_cleanup(CanBusClientState *client)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+
+    if (c->fd >= 0) {
+        qemu_set_fd_handler(c->fd, NULL, NULL, c);
+        close(c->fd);
+        c->fd = -1;
+    }
+
+    c->rfilter_num = 0;
+    if (c->rfilter != NULL) {
+        g_free(c->rfilter);
+    }
+}
+
+static int can_bus_socketcan_set_filters(CanBusClientState *client,
+                   const struct qemu_can_filter *filters, size_t filters_cnt)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+
+    int i;
+
+    if (filters_cnt > 4) {
+        return -1;
+    }
+
+    if (DEBUG_CAN) {
+        for (i = 0; i < filters_cnt; i++) {
+            fprintf(stderr, "[%i]  id=0x%08x maks=0x%08x\n",
+                   i, filters[i].can_id, filters[i].can_mask);
+        }
+    }
+
+    setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
+               filters, filters_cnt * sizeof(qemu_can_filter));
+
+    return 0;
+}
+
+static
+void can_bus_socketcan_update_read_handler(CanBusSocketcanConnectState *c)
+{
+    if (c->fd >= 0) {
+        qemu_set_fd_handler(c->fd, can_bus_socketcan_read, NULL, c);
+    }
+}
+
+static CanBusClientInfo can_bus_socketcan_bus_client_info = {
+    .can_receive = can_bus_socketcan_can_receive,
+    .receive = can_bus_socketcan_receive,
+    .cleanup = can_bus_socketcan_cleanup,
+    .poll = NULL
+};
+
+static
+CanBusSocketcanConnectState *can_bus_socketcan_connect_new(const char *host_dev_name)
+{
+    int s; /* can raw socket */
+    CanBusSocketcanConnectState    *c;
+    struct sockaddr_can addr;
+    struct ifreq ifr;
+
+    c = g_malloc0(sizeof(CanBusSocketcanConnectState));
+    if (c == NULL) {
+        goto fail1;
+    }
+
+    c->fd = -1;
+
+    /* open socket */
+    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+    if (s < 0) {
+        perror("socket");
+        goto fail;
+    }
+
+    addr.can_family = AF_CAN;
+    memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
+    strcpy(ifr.ifr_name, host_dev_name);
+    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+        perror("SIOCGIFINDEX");
+        goto fail;
+    }
+    addr.can_ifindex = ifr.ifr_ifindex;
+
+    c->err_mask = 0xffffffff; /* Receive error frame. */
+    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
+                   &c->err_mask, sizeof(c->err_mask));
+
+    c->rfilter_num = 1;
+    c->rfilter = g_malloc0(c->rfilter_num * sizeof(struct qemu_can_filter));
+    if (c->rfilter == NULL) {
+        goto fail;
+    }
+
+    /* Receive all data frame. If |= CAN_INV_FILTER no data. */
+    c->rfilter[0].can_id = 0;
+    c->rfilter[0].can_mask = 0;
+    c->rfilter[0].can_mask &= ~CAN_ERR_FLAG;
+
+    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, c->rfilter,
+               c->rfilter_num * sizeof(struct qemu_can_filter));
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        perror("bind");
+        goto fail;
+    }
+
+    c->fd = s;
+
+    c->bus_client.info = &can_bus_socketcan_bus_client_info;
+
+    can_bus_socketcan_update_read_handler(c);
+
+    return c;
+
+fail:
+    can_bus_socketcan_cleanup(&c->bus_client);
+    g_free(c);
+fail1:
+
+    return NULL;
+}
+
+static
+int can_bus_connect_to_host_socketcan(CanBusState *bus, const char *host_dev_name)
+{
+    CanBusSocketcanConnectState *c;
+
+    c = can_bus_socketcan_connect_new(host_dev_name);
+    if (c == NULL) {
+        error_report("CAN bus setup of host connect to \"%s\" failed",
+                      host_dev_name);
+        exit(1);
+    }
+
+    if (can_bus_insert_client(bus, &c->bus_client) < 0) {
+        error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
+                      host_dev_name, bus->name);
+        exit(1);
+    }
+
+    if (0) {
+        /*
+         * Not used there or as a CanBusSocketcanConnectState method
+         * for now but included there for documentation purposes
+         * and to suppress warning.
+         */
+        can_bus_socketcan_set_filters(&c->bus_client, NULL, 0);
+    }
+
+    return 0;
+}
+
+int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
+        can_bus_connect_to_host_socketcan;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 3/7] CAN bus SJA1000 chip register level emulation for QEMU
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU pisa
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-12 10:23   ` KONRAD Frederic
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

The core SJA1000 support is independent of following
patches which map SJA1000 chip to PCI boards.

The work is based on Jin Yang GSoC 2013 work funded
by Google and mentored in frame of RTEMS project GSoC
slot donated to QEMU.

Rewritten for QEMU-2.0+ versions and architecture cleanup
by Pavel Pisa (Czech Technical University in Prague).

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 default-configs/pci.mak |   1 +
 hw/can/Makefile.objs    |   1 +
 hw/can/can_sja1000.c    | 996 ++++++++++++++++++++++++++++++++++++++++++++++++
 hw/can/can_sja1000.h    | 176 +++++++++
 4 files changed, 1174 insertions(+)
 create mode 100644 hw/can/can_sja1000.c
 create mode 100644 hw/can/can_sja1000.h

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index bbe11887a1..979b649fe5 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -32,6 +32,7 @@ CONFIG_SERIAL=y
 CONFIG_SERIAL_ISA=y
 CONFIG_SERIAL_PCI=y
 CONFIG_CAN_CORE=y
+CONFIG_CAN_SJA1000=y
 CONFIG_IPACK=y
 CONFIG_WDT_IB6300ESB=y
 CONFIG_PCI_TESTDEV=y
diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index f999085f7a..3c4bf3bfc1 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -7,4 +7,5 @@ common-obj-y += can_socketcan.o
 else
 common-obj-y += can_host_stub.o
 endif
+common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 endif
diff --git a/hw/can/can_sja1000.c b/hw/can/can_sja1000.c
new file mode 100644
index 0000000000..17e5b46f07
--- /dev/null
+++ b/hw/can/can_sja1000.c
@@ -0,0 +1,996 @@
+/*
+ * CAN device - SJA1000 chip emulation for QEMU
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2017 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 "hw/hw.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#ifndef DEBUG_FILTER
+#define DEBUG_FILTER 0
+#endif /*DEBUG_FILTER*/
+
+static void can_sja_software_reset(CanSJA1000State *s)
+{
+    s->mode        &= ~0x31;
+    s->mode        |= 0x01;
+    s->status_pel  &= ~0x37;
+    s->status_pel  |= 0x34;
+
+    s->rxbuf_start = 0x00;
+    s->rxmsg_cnt   = 0x00;
+    s->rx_cnt      = 0x00;
+}
+
+void can_sja_hardware_reset(CanSJA1000State *s)
+{
+    /* Reset by hardware, p10 */
+    s->mode        = 0x01;
+    s->status_pel  = 0x3c;
+    s->interrupt_pel = 0x00;
+    s->clock       = 0x00;
+    s->rxbuf_start = 0x00;
+    s->rxmsg_cnt   = 0x00;
+    s->rx_cnt      = 0x00;
+
+    s->control     = 0x01;
+    s->status_bas  = 0x0c;
+    s->interrupt_bas = 0x00;
+
+    s->irq_lower(s->irq_opaque);
+}
+
+static
+void can_sja_single_filter(struct qemu_can_filter *filter,
+            const uint8_t *acr,  const uint8_t *amr, int extended)
+{
+    if (extended) {
+        filter->can_id = (uint32_t)acr[0] << 21;
+        filter->can_id |= (uint32_t)acr[1] << 13;
+        filter->can_id |= (uint32_t)acr[2] << 5;
+        filter->can_id |= (uint32_t)acr[3] >> 3;
+        if (acr[3] & 4) {
+            filter->can_id |= QEMU_CAN_RTR_FLAG;
+        }
+
+        filter->can_mask = (uint32_t)amr[0] << 21;
+        filter->can_mask |= (uint32_t)amr[1] << 13;
+        filter->can_mask |= (uint32_t)amr[2] << 5;
+        filter->can_mask |= (uint32_t)amr[3] >> 3;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK;
+        if (!(amr[3] & 4)) {
+            filter->can_mask |= QEMU_CAN_RTR_FLAG;
+        }
+    } else {
+        filter->can_id = (uint32_t)acr[0] << 3;
+        filter->can_id |= (uint32_t)acr[1] >> 5;
+        if (acr[1] & 0x10) {
+            filter->can_id |= QEMU_CAN_RTR_FLAG;
+        }
+
+        filter->can_mask = (uint32_t)amr[0] << 3;
+        filter->can_mask |= (uint32_t)amr[1] << 5;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
+        if (!(amr[1] & 4)) {
+            filter->can_mask |= QEMU_CAN_RTR_FLAG;
+        }
+    }
+}
+
+static
+void can_sja_dual_filter(struct qemu_can_filter *filter,
+            const uint8_t *acr,  const uint8_t *amr, int extended)
+{
+    if (extended) {
+        filter->can_id = (uint32_t)acr[0] << 21;
+        filter->can_id |= (uint32_t)acr[1] << 13;
+
+        filter->can_mask = (uint32_t)amr[0] << 21;
+        filter->can_mask |= (uint32_t)amr[1] << 13;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK & ~0x1fff;
+    } else {
+        filter->can_id = (uint32_t)acr[0] << 3;
+        filter->can_id |= (uint32_t)acr[1] >> 5;
+        if (acr[1] & 0x10) {
+            filter->can_id |= QEMU_CAN_RTR_FLAG;
+        }
+
+        filter->can_mask = (uint32_t)amr[0] << 3;
+        filter->can_mask |= (uint32_t)amr[1] >> 5;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
+        if (!(amr[1] & 0x10)) {
+            filter->can_mask |= QEMU_CAN_RTR_FLAG;
+        }
+    }
+}
+
+/* Details in DS-p22, what we need to do here is to test the data. */
+static
+int can_sja_accept_filter(CanSJA1000State *s,
+                                 const qemu_can_frame *frame)
+{
+
+    struct qemu_can_filter filter;
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        if (s->mode & (1 << 3)) { /* Single mode. */
+            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
+                can_sja_single_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 1);
+
+                if (!can_bus_filter_match(&filter, frame->can_id)) {
+                    return 0;
+                }
+            } else { /* SFF */
+                can_sja_single_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 0);
+
+                if (!can_bus_filter_match(&filter, frame->can_id)) {
+                    return 0;
+                }
+
+                if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
+                    return 1;
+                }
+
+                if (frame->can_dlc == 0) {
+                    return 1;
+                }
+
+                if ((frame->data[0] & ~(s->code_mask[6])) !=
+                   (s->code_mask[2] & ~(s->code_mask[6]))) {
+                    return 0;
+                }
+
+                if (frame->can_dlc < 2) {
+                    return 1;
+                }
+
+                if ((frame->data[1] & ~(s->code_mask[7])) ==
+                    (s->code_mask[3] & ~(s->code_mask[7]))) {
+                    return 1;
+                }
+
+                return 0;
+            }
+        } else { /* Dual mode */
+            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 1);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    return 1;
+                }
+
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 2, s->code_mask + 6, 1);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    return 1;
+                }
+
+                return 0;
+            } else {
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 0);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    uint8_t expect;
+                    uint8_t mask;
+                    expect = s->code_mask[1] << 4;
+                    expect |= s->code_mask[3] & 0x0f;
+
+                    mask = s->code_mask[5] << 4;
+                    mask |= s->code_mask[7] & 0x0f;
+                        mask = ~mask & 0xff;
+
+                    if ((frame->data[0] & mask) ==
+                        (expect & mask)) {
+                        return 1;
+                    }
+                }
+
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 2, s->code_mask + 6, 0);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    return 1;
+                }
+
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+static void can_display_msg(const qemu_can_frame *msg)
+{
+    int i;
+
+    fprintf(stderr, "%03X [%01d] -", (msg->can_id & QEMU_CAN_EFF_MASK),
+            msg->can_dlc);
+
+    if (msg->can_id & QEMU_CAN_EFF_FLAG) {
+        fprintf(stderr, "EFF ");
+    } else {
+        fprintf(stderr, "SFF ");
+    }
+    if (msg->can_id & QEMU_CAN_RTR_FLAG) {
+        fprintf(stderr, "RTR-");
+    } else {
+        fprintf(stderr, "DAT-");
+    }
+    for (i = 0; i < msg->can_dlc; i++) {
+        fprintf(stderr, "  %02X", msg->data[i]);
+    }
+    for (; i < 8; i++) {
+        fprintf(stderr, "    ");
+    }
+    fflush(stdout);
+}
+
+static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame)
+{
+    uint8_t i;
+
+    frame->can_id = 0;
+    if (buff[0] & 0x40) { /* RTR */
+        frame->can_id = QEMU_CAN_RTR_FLAG;
+    }
+    frame->can_dlc = buff[0] & 0x0f;
+
+    if (buff[0] & 0x80) { /* Extended */
+        frame->can_id |= QEMU_CAN_EFF_FLAG;
+        frame->can_id |= buff[1] << 21; /* ID.28~ID.21 */
+        frame->can_id |= buff[2] << 13; /* ID.20~ID.13 */
+        frame->can_id |= buff[3] <<  5;
+        frame->can_id |= buff[4] >>  3;
+        for (i = 0; i < frame->can_dlc; i++) {
+            frame->data[i] = buff[5 + i];
+        }
+        for (; i < 8; i++) {
+            frame->data[i] = 0;
+        }
+    } else {
+        frame->can_id |= buff[1] <<  3;
+        frame->can_id |= buff[2] >>  5;
+        for (i = 0; i < frame->can_dlc; i++) {
+            frame->data[i] = buff[3 + i];
+        }
+        for (; i < 8; i++) {
+            frame->data[i] = 0;
+        }
+    }
+}
+
+
+static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame)
+{
+    uint8_t i;
+
+    frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07);
+    if (buff[1] & 0x10) { /* RTR */
+        frame->can_id = QEMU_CAN_RTR_FLAG;
+    }
+    frame->can_dlc = buff[1] & 0x0f;
+
+    for (i = 0; i < frame->can_dlc; i++) {
+        frame->data[i] = buff[2 + i];
+    }
+    for (; i < 8; i++) {
+        frame->data[i] = 0;
+    }
+}
+
+
+static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
+{
+    int i;
+
+    if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */
+        return -1;
+    }
+
+    buff[0] = 0x0f & frame->can_dlc; /* DLC */
+    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
+        buff[0] |= (1 << 6);
+    }
+    if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
+        buff[0] |= (1 << 7);
+        buff[1] = extract32(frame->can_id, 21, 8); /* ID.28~ID.21 */
+        buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */
+        buff[3] = extract32(frame->can_id, 5, 8);  /* ID.12~ID.05 */
+        buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,x,x,x */
+        for (i = 0; i < frame->can_dlc; i++) {
+            buff[5 + i] = frame->data[i];
+        }
+        return frame->can_dlc + 5;
+    } else { /* SFF */
+        buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
+        buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,x,x,x,x,x */
+        for (i = 0; i < frame->can_dlc; i++) {
+            buff[3 + i] = frame->data[i];
+        }
+
+        return frame->can_dlc + 3;
+    }
+
+    return -1;
+}
+
+static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff)
+{
+    int i;
+
+    if ((frame->can_id & QEMU_CAN_EFF_FLAG) || /* EFF, not support for BasicMode. */
+       (frame->can_id & QEMU_CAN_ERR_FLAG)) {  /* or Error frame, NOT support now. */
+        return -1;
+    }
+
+    buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
+    buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,x,x,x,x,x */
+    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
+        buff[1] |= (1 << 4);
+    }
+    buff[1] |= frame->can_dlc & 0x0f;
+    for (i = 0; i < frame->can_dlc; i++) {
+        buff[2 + i] = frame->data[i];
+    }
+
+    return frame->can_dlc + 2;
+}
+
+void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
+                       unsigned size)
+{
+    qemu_can_frame   frame;
+    uint32_t         tmp;
+    uint8_t          tmp8, count;
+
+
+    DPRINTF("write 0x%02llx addr 0x%02x\n",
+            (unsigned long long)val, (unsigned int)addr);
+
+    if (addr > CAN_SJA_MEM_SIZE) {
+        return ;
+    }
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        switch (addr) {
+        case SJA_MOD: /* Mode register */
+            s->mode = 0x1f & val;
+            if ((s->mode & 0x01) && ((val & 0x01) == 0)) {
+                /* Go to operation mode from reset mode. */
+                if (s->mode & (1 << 3)) { /* Single mode. */
+                    /* For EFF */
+                    can_sja_single_filter(&s->filter[0],
+                        s->code_mask + 0, s->code_mask + 4, 1);
+
+                    /* For SFF */
+                    can_sja_single_filter(&s->filter[1],
+                        s->code_mask + 0, s->code_mask + 4, 0);
+
+                    can_bus_client_set_filters(&s->bus_client, s->filter, 2);
+                } else { /* Dual mode */
+                    /* For EFF */
+                    can_sja_dual_filter(&s->filter[0],
+                        s->code_mask + 0, s->code_mask + 4, 1);
+
+                    can_sja_dual_filter(&s->filter[1],
+                        s->code_mask + 2, s->code_mask + 6, 1);
+
+                    /* For SFF */
+                    can_sja_dual_filter(&s->filter[2],
+                        s->code_mask + 0, s->code_mask + 4, 0);
+
+                    can_sja_dual_filter(&s->filter[3],
+                        s->code_mask + 2, s->code_mask + 6, 0);
+
+                    can_bus_client_set_filters(&s->bus_client, s->filter, 4);
+                }
+
+                s->rxmsg_cnt = 0;
+                s->rx_cnt = 0;
+            }
+            break;
+
+        case SJA_CMR: /* Command register. */
+            if (0x01 & val) { /* Send transmission request. */
+                buff2frame_pel(s->tx_buff, &frame);
+                if (DEBUG_FILTER) {
+                    can_display_msg(&frame);
+                    fprintf(stderr, "\n");
+                }
+
+                /*
+                 * Clear transmission complete status,
+                 * and Transmit Buffer Status.
+                 * write to the backends.
+                 */
+                s->status_pel &= ~(3 << 2);
+
+                can_bus_client_send(&s->bus_client, &frame, 1);
+                s->status_pel |= (3 << 2); /* Set transmission complete status, */
+                                       /* and Transmit Buffer Status. */
+                s->status_pel &= ~(1 << 5); /* Clear transmit status. */
+                s->interrupt_pel |= 0x02;
+                if (s->interrupt_en & 0x02) {
+                    s->irq_raise(s->irq_opaque);
+                }
+            } else if (0x04 & val) { /* Release Receive Buffer */
+                if (s->rxmsg_cnt <= 0) {
+                    break;
+                }
+
+                tmp8 = s->rx_buff[s->rxbuf_start]; count = 0;
+                if (tmp8 & (1 << 7)) { /* EFF */
+                    count += 2;
+                }
+                count += 3;
+                if (!(tmp8 & (1 << 6))) { /* DATA */
+                    count += (tmp8 & 0x0f);
+                }
+                s->rxbuf_start += count;
+                s->rxbuf_start %= SJA_RCV_BUF_LEN;
+
+                s->rx_cnt -= count;
+                s->rxmsg_cnt--;
+                if (s->rxmsg_cnt == 0) {
+                    s->status_pel &= ~(1 << 0);
+                    s->interrupt_pel &= ~(1 << 0);
+                }
+                if ((s->interrupt_en & 0x01) && (s->interrupt_pel == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            } else if (0x08 & val) { /* Clear data overrun */
+                s->status_pel &= ~(1 << 1);
+                s->interrupt_pel &= ~(1 << 3);
+                if ((s->interrupt_en & 0x80) && (s->interrupt_pel == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            }
+            break;
+        case SJA_SR: /* Status register */
+        case SJA_IR: /* Interrupt register */
+            break; /* Do nothing */
+        case SJA_IER: /* Interrupt enable register */
+            s->interrupt_en = val;
+            break;
+        case 16: /* RX frame information addr16-28. */
+            s->status_pel |= (1 << 5); /* Set transmit status. */
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
+        case 23:
+        case 24:
+        case 25:
+        case 26:
+        case 27:
+        case 28:
+            if (s->mode & 0x01) { /* Reset mode */
+                if (addr < 24) {
+                    s->code_mask[addr - 16] = val;
+                }
+            } else { /* Operation mode */
+                s->tx_buff[addr - 16] = val; /* Store to TX buffer directly. */
+            }
+            break;
+        case SJA_CDR:
+            s->clock = val;
+            break;
+        }
+    } else { /* Basic Mode */
+        switch (addr) {
+        case SJA_BCAN_CTR: /* Control register, addr 0 */
+            if ((s->control & 0x01) && ((val & 0x01) == 0)) {
+                /* Go to operation mode from reset mode. */
+                s->filter[0].can_id = (s->code << 3) & (0xff << 3);
+                tmp = (~(s->mask << 3)) & (0xff << 3);
+                tmp |= QEMU_CAN_EFF_FLAG; /* Only Basic CAN Frame. */
+                s->filter[0].can_mask = tmp;
+                can_bus_client_set_filters(&s->bus_client, s->filter, 1);
+
+                s->rxmsg_cnt = 0;
+                s->rx_cnt = 0;
+            } else if (!(s->control & 0x01) && !(val & 0x01)) {
+                can_sja_software_reset(s);
+            }
+
+            s->control = 0x1f & val;
+            break;
+        case SJA_BCAN_CMR: /* Command register, addr 1 */
+            if (0x01 & val) { /* Send transmission request. */
+                buff2frame_bas(s->tx_buff, &frame);
+                if (DEBUG_FILTER) {
+                    can_display_msg(&frame);
+                    fprintf(stderr, "\n");
+                }
+
+                /*
+                 * Clear transmission complete status,
+                 * and Transmit Buffer Status.
+                 */
+                s->status_bas &= ~(3 << 2);
+
+                /* write to the backends. */
+                can_bus_client_send(&s->bus_client, &frame, 1);
+                s->status_bas |= (3 << 2); /* Set transmission complete status, */
+                                       /* and Transmit Buffer Status. */
+                s->status_bas &= ~(1 << 5); /* Clear transmit status. */
+                s->interrupt_bas |= 0x02;
+                if (s->control & 0x04) {
+                    s->irq_raise(s->irq_opaque);
+                }
+            } else if (0x04 & val) { /* Release Receive Buffer */
+                if (s->rxmsg_cnt <= 0) {
+                    break;
+                }
+
+                qemu_mutex_lock(&s->rx_lock);
+                tmp8 = s->rx_buff[(s->rxbuf_start + 1) % SJA_RCV_BUF_LEN];
+                count = 2 + (tmp8 & 0x0f);
+
+                if (DEBUG_FILTER) {
+                    int i;
+                    fprintf(stderr, "\nRelease");
+                    for (i = 0; i < count; i++) {
+                        fprintf(stderr, " %02X", s->rx_buff[(s->rxbuf_start + i) %
+                                        SJA_RCV_BUF_LEN]);
+                    }
+                    for (; i < 11; i++) {
+                        fprintf(stderr, "   ");
+                    }
+                    fprintf(stderr, "==== cnt=%d, count=%d\n",
+                            s->rx_cnt, count);
+                }
+
+                s->rxbuf_start += count;
+                s->rxbuf_start %= SJA_RCV_BUF_LEN;
+                s->rx_cnt -= count;
+                s->rxmsg_cnt--;
+                qemu_mutex_unlock(&s->rx_lock);
+
+                if (s->rxmsg_cnt == 0) {
+                    s->status_bas &= ~(1 << 0);
+                    s->interrupt_bas &= ~(1 << 0);
+                }
+                if ((s->control & 0x02) && (s->interrupt_bas == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            } else if (0x08 & val) { /* Clear data overrun */
+                s->status_bas &= ~(1 << 1);
+                s->interrupt_bas &= ~(1 << 3);
+                if ((s->control & 0x10) && (s->interrupt_bas == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            }
+            break;
+        case 4:
+            s->code = val;
+            break;
+        case 5:
+            s->mask = val;
+            break;
+        case 10:
+            s->status_bas |= (1 << 5); /* Set transmit status. */
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+            if ((s->control & 0x01) == 0) { /* Operation mode */
+                s->tx_buff[addr - 10] = val; /* Store to TX buffer directly. */
+            }
+            break;
+        case SJA_CDR:
+            s->clock = val;
+            break;
+        }
+    }
+}
+
+uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size)
+{
+    uint64_t temp = 0;
+
+    DPRINTF("read addr 0x%x", (unsigned int)addr);
+
+    if (addr > CAN_SJA_MEM_SIZE) {
+        return 0;
+    }
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        switch (addr) {
+        case SJA_MOD: /* Mode register, addr 0 */
+            temp = s->mode;
+            break;
+        case SJA_CMR: /* Command register, addr 1 */
+            temp = 0x00; /* Command register, cannot be read. */
+            break;
+        case SJA_SR: /* Status register, addr 2 */
+            temp = s->status_pel;
+            break;
+        case SJA_IR: /* Interrupt register, addr 3 */
+            temp = s->interrupt_pel;
+            s->interrupt_pel = 0;
+            if (s->rxmsg_cnt) {
+                s->interrupt_pel |= (1 << 0); /* Receive interrupt. */
+                break;
+            }
+            s->irq_lower(s->irq_opaque);
+            break;
+        case SJA_IER: /* Interrupt enable register, addr 4 */
+            temp = s->interrupt_en;
+            break;
+        case 5: /* Reserved */
+        case 6: /* Bus timing 0, hardware related, not support now. */
+        case 7: /* Bus timing 1, hardware related, not support now. */
+        case 8: /*
+                 * Output control register, hardware related,
+                 * not supported for now.
+                 */
+        case 9: /* Test. */
+        case 10: /* Reserved */
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+            temp = 0x00;
+            break;
+
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
+        case 23:
+        case 24:
+        case 25:
+        case 26:
+        case 27:
+        case 28:
+            if (s->mode & 0x01) { /* Reset mode */
+                if (addr < 24) {
+                    temp = s->code_mask[addr - 16];
+                } else {
+                    temp = 0x00;
+                }
+            } else { /* Operation mode */
+                temp = s->rx_buff[(s->rxbuf_start + addr - 16) %
+                       SJA_RCV_BUF_LEN];
+            }
+            break;
+        case SJA_CDR:
+            temp = s->clock;
+            break;
+        default:
+            temp = 0xff;
+        }
+    } else { /* Basic Mode */
+        switch (addr) {
+        case SJA_BCAN_CTR: /* Control register, addr 0 */
+            temp = s->control;
+            break;
+        case SJA_BCAN_SR: /* Status register, addr 2 */
+            temp = s->status_bas;
+            break;
+        case SJA_BCAN_IR: /* Interrupt register, addr 3 */
+            temp = s->interrupt_bas;
+            s->interrupt_bas = 0;
+            if (s->rxmsg_cnt) {
+                s->interrupt_bas |= (1 << 0); /* Receive interrupt. */
+                break;
+            }
+            s->irq_lower(s->irq_opaque);
+            break;
+        case 4:
+            temp = s->code;
+            break;
+        case 5:
+            temp = s->mask;
+            break;
+        case 20:
+            if (DEBUG_FILTER) {
+                printf("Read   ");
+            }
+        case 21:
+        case 22:
+        case 23:
+        case 24:
+        case 25:
+        case 26:
+        case 27:
+        case 28:
+        case 29:
+            temp = s->rx_buff[(s->rxbuf_start + addr - 20) % SJA_RCV_BUF_LEN];
+            if (DEBUG_FILTER) {
+                fprintf(stderr, " %02X", (unsigned int)(temp & 0xff));
+            }
+            break;
+        case 31:
+            temp = s->clock;
+            break;
+        default:
+            temp = 0xff;
+            break;
+        }
+    }
+    DPRINTF("     %d bytes of 0x%lx from addr %d\n",
+            size, (long unsigned int)temp, (int)addr);
+
+    return temp;
+}
+
+int can_sja_can_receive(CanBusClientState *client)
+{
+    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        if (s->mode & 0x01) { /* reset mode. */
+            return 0;
+        }
+    } else { /* BasicCAN mode */
+        if (s->control & 0x01) {
+            return 0;
+        }
+    }
+
+    return 1; /* always return 1, when operation mode */
+}
+
+ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,
+                        size_t frames_cnt)
+{
+    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
+    static uint8_t rcv[SJA_MSG_MAX_LEN];
+    int i;
+    int ret = -1;
+    const qemu_can_frame *frame = frames;
+
+    if (frames_cnt <= 0) {
+        return 0;
+    }
+    if (DEBUG_FILTER) {
+        fprintf(stderr, "#################################################\n");
+        can_display_msg(frame);
+    }
+
+    qemu_mutex_lock(&s->rx_lock); /* Just do it quickly :) */
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        s->status_pel |= (1 << 4); /* the CAN controller is receiving a message */
+
+        if (can_sja_accept_filter(s, frame) == 0) {
+            s->status_pel &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                fprintf(stderr, "     NOT\n");
+            }
+            goto fail;
+        }
+
+        ret = frame2buff_pel(frame, rcv);
+        if (ret < 0) {
+            s->status_pel &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                fprintf(stderr, "     ERR\n");
+            }
+            goto fail; /* maybe not support now. */
+        }
+
+        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
+            s->status_pel |= (1 << 1); /* Overrun status */
+            s->interrupt_pel |= (1 << 3);
+            if (s->interrupt_en & (1 << 3)) { /* Overrun interrupt enable */
+                s->irq_raise(s->irq_opaque);
+            }
+            s->status_pel &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                fprintf(stderr, "     OVER\n");
+            }
+            goto fail;
+        }
+        s->rx_cnt += ret;
+        s->rxmsg_cnt++;
+        if (DEBUG_FILTER) {
+            fprintf(stderr, "     OK\n");
+        }
+
+        for (i = 0; i < ret; i++) {
+            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
+        }
+        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
+
+        s->status_pel |= 0x01; /* Set the Receive Buffer Status. DS-p23 */
+        s->interrupt_pel |= 0x01;
+        s->status_pel &= ~(1 << 4);
+        s->status_pel |= (1 << 0);
+        if (s->interrupt_en & 0x01) { /* Receive Interrupt enable. */
+            s->irq_raise(s->irq_opaque);
+        }
+    } else { /* BasicCAN mode */
+        s->status_bas |= (1 << 4); /* the CAN controller is receiving a message */
+
+        ret = frame2buff_bas(frame, rcv);
+        if (ret < 0) {
+            s->status_bas &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                fprintf(stderr, "     NOT\n");
+            }
+            goto fail; /* maybe not support now. */
+        }
+
+        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
+            s->status_bas |= (1 << 1); /* Overrun status */
+            s->status_bas &= ~(1 << 4);
+            s->interrupt_bas |= (1 << 3);
+            if (s->control & (1 << 4)) { /* Overrun interrupt enable */
+                s->irq_raise(s->irq_opaque);
+            }
+            if (DEBUG_FILTER) {
+                fprintf(stderr, "     OVER\n");
+            }
+            goto fail;
+        }
+        s->rx_cnt += ret;
+        s->rxmsg_cnt++;
+
+        if (DEBUG_FILTER) {
+            fprintf(stderr, "     OK\n");
+            fprintf(stderr, "RCV B ret=%2d, ptr=%2d cnt=%2d msg=%2d\n",
+                   ret, s->rx_ptr, s->rx_cnt, s->rxmsg_cnt);
+        }
+
+        for (i = 0; i < ret; i++) {
+            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
+        }
+        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
+
+        s->status_bas |= 0x01; /* Set the Receive Buffer Status. DS-p15 */
+        s->status_bas &= ~(1 << 4);
+        s->interrupt_bas |= 0x01;
+        if (s->control & 0x02) { /* Receive Interrupt enable. */
+            s->irq_raise(s->irq_opaque);
+        }
+    }
+    ret = 1;
+fail:
+    qemu_mutex_unlock(&s->rx_lock);
+
+    return ret;
+}
+
+static CanBusClientInfo can_sja_bus_client_info = {
+    .can_receive = can_sja_can_receive,
+    .receive = can_sja_receive,
+    .cleanup = NULL,
+    .poll = NULL
+};
+
+
+int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus)
+{
+    s->bus_client.info = &can_sja_bus_client_info;
+
+    if (can_bus_insert_client(bus, &s->bus_client) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void can_sja_disconnect(CanSJA1000State *s)
+{
+    can_bus_remove_client(&s->bus_client);
+}
+
+int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
+                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque)
+{
+    qemu_mutex_init(&s->rx_lock);
+
+    s->irq_raise = irq_raise;
+    s->irq_lower = irq_lower;
+    s->irq_opaque = irq_opaque;
+
+    s->irq_lower(s->irq_opaque);
+
+    can_sja_hardware_reset(s);
+
+    return 0;
+}
+
+void can_sja_exit(CanSJA1000State *s)
+{
+    qemu_mutex_destroy(&s->rx_lock);
+}
+
+const VMStateDescription vmstate_qemu_can_filter = {
+    .name = "qemu_can_filter",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(can_id, qemu_can_filter),
+        VMSTATE_UINT32(can_mask, qemu_can_filter),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* VMState is needed for live migration of QEMU images */
+const VMStateDescription vmstate_can_sja = {
+    .name = "can_sja",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(mode, CanSJA1000State),
+
+        VMSTATE_UINT8(status_pel, CanSJA1000State),
+        VMSTATE_UINT8(interrupt_pel, CanSJA1000State),
+        VMSTATE_UINT8(interrupt_en, CanSJA1000State),
+        VMSTATE_UINT8(rxmsg_cnt, CanSJA1000State),
+        VMSTATE_UINT8(rxbuf_start, CanSJA1000State),
+        VMSTATE_UINT8(clock, CanSJA1000State),
+
+        VMSTATE_BUFFER(code_mask, CanSJA1000State),
+        VMSTATE_BUFFER(tx_buff, CanSJA1000State),
+
+        VMSTATE_BUFFER(rx_buff, CanSJA1000State),
+
+        VMSTATE_UINT32(rx_ptr, CanSJA1000State),
+        VMSTATE_UINT32(rx_cnt, CanSJA1000State),
+
+        VMSTATE_UINT8(control, CanSJA1000State),
+
+        VMSTATE_UINT8(status_bas, CanSJA1000State),
+        VMSTATE_UINT8(interrupt_bas, CanSJA1000State),
+        VMSTATE_UINT8(code, CanSJA1000State),
+        VMSTATE_UINT8(mask, CanSJA1000State),
+
+        VMSTATE_STRUCT_ARRAY(filter, CanSJA1000State, 4, 0,
+                             vmstate_qemu_can_filter, qemu_can_filter),
+
+
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/hw/can/can_sja1000.h b/hw/can/can_sja1000.h
new file mode 100644
index 0000000000..0830e78456
--- /dev/null
+++ b/hw/can/can_sja1000.h
@@ -0,0 +1,176 @@
+/*
+ * CAN device - SJA1000 chip emulation for QEMU
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2017 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.
+ */
+#ifndef HW_CAN_SJA1000_H
+#define HW_CAN_SJA1000_H
+
+#include "can/can_emu.h"
+
+#define CAN_SJA_MEM_SIZE      128
+
+/* The max size for a message buffer, EFF and DLC=8, DS-p39 */
+#define SJA_MSG_MAX_LEN       13
+/* The receive buffer size. */
+#define SJA_RCV_BUF_LEN       64
+
+//#define DEBUG_CAN
+
+#ifndef DEBUG_CAN
+#define DEBUG_CAN 0
+#endif /*DEBUG_CAN*/
+
+#define DPRINTF(fmt, ...) \
+    do { \
+        if (DEBUG_CAN) { \
+            fprintf(stderr, "[cansja]: " fmt , ## __VA_ARGS__); \
+        } \
+    } while (0)
+
+typedef void (CanSJAIrqRaiseLower)(void *opaque);
+
+typedef struct CanSJA1000State {
+    /* Some registers ... */
+    uint8_t         mode;          /* PeliCAN, addr 0, Mode register, DS-p26 */
+                                   /* PeliCAN, addr 1, Command register */
+    uint8_t         status_pel;    /* PeliCAN, addr 2, Status register, p15 */
+    uint8_t         interrupt_pel; /* PeliCAN, addr 3, Interrupt register */
+    uint8_t         interrupt_en;  /* PeliCAN, addr 4, Interrupt Enable register */
+    uint8_t         rxmsg_cnt;     /* PeliCAN, addr 29, RX message counter. DS-p49 */
+    uint8_t         rxbuf_start;   /* PeliCAN, addr 30, RX buffer start address, DS-p49 */
+    uint8_t         clock;         /* PeliCAN, addr 31, Clock Divider register, DS-p55 */
+
+    uint8_t         code_mask[8];  /* PeliCAN, addr 16~23 */
+    uint8_t         tx_buff[13];   /* PeliCAN, addr 96~108, transmit buffer */
+                                   /* BasicCAN, addr 10~19, transmit buffer */
+
+    uint8_t         rx_buff[SJA_RCV_BUF_LEN];  /* 32~95, 64bytes */
+    uint32_t        rx_ptr;        /* Count by bytes. */
+    uint32_t        rx_cnt;        /* Count by bytes. */
+
+    uint8_t         control;       /* BasicCAN, addr 0, Control register */
+                                   /* BasicCAN, addr 1, Command register */
+    uint8_t         status_bas;    /* BasicCAN, addr 2, Status register */
+    uint8_t         interrupt_bas; /* BasicCAN, addr 3, Interrupt register */
+    uint8_t         code;          /* BasicCAN, addr 4, Acceptance code register */
+    uint8_t         mask;          /* BasicCAN, addr 5, Acceptance mask register */
+
+    qemu_can_filter filter[4];
+
+    QemuMutex       rx_lock;
+    CanSJAIrqRaiseLower *irq_raise;
+    CanSJAIrqRaiseLower *irq_lower;
+    void            *irq_opaque;
+    CanBusClientState bus_client;
+} CanSJA1000State;
+
+/* PeliCAN mode */
+enum SJA1000_PeliCAN_regs {
+        SJA_MOD      = 0x00,
+/* Command register */
+        SJA_CMR      = 0x01,
+/* Status register */
+        SJA_SR       = 0x02,
+/* Interrupt register */
+        SJA_IR       = 0x03,
+/* Interrupt Enable */
+        SJA_IER      = 0x04,
+/* Bus Timing register 0 */
+        SJA_BTR0     = 0x06,
+/* Bus Timing register 1 */
+        SJA_BTR1     = 0x07,
+/* Output Control register */
+        SJA_OCR      = 0x08,
+/* Arbitration Lost Capture */
+        SJA_ALC      = 0x0b,
+/* Error Code Capture */
+        SJA_ECC      = 0x0c,
+/* Error Warning Limit */
+        SJA_EWLR     = 0x0d,
+/* RX Error Counter */
+        SJA_RXERR    = 0x0e,
+/* TX Error Counter */
+        SJA_TXERR0   = 0x0e,
+        SJA_TXERR1   = 0x0f,
+/* Rx Message Counter (number of msgs. in RX FIFO */
+        SJA_RMC      = 0x1d,
+/* Rx Buffer Start Addr. (address of current MSG) */
+        SJA_RBSA     = 0x1e,
+/* Transmit Buffer (write) Receive Buffer (read) Frame Information */
+        SJA_FRM      = 0x10,
+/* ID bytes (11 bits in 0 and 1 or 16 bits in 0,1 and 13 bits in 2,3 (extended)) */
+        SJA_ID0      = 0x11, SJA_ID1 = 0x12,
+/* ID cont. for extended frames */
+        SJA_ID2      = 0x13, SJA_ID3 = 0x14,
+/* Data start standard frame */
+        SJA_DATS     = 0x13,
+/* Data start extended frame */
+        SJA_DATE     = 0x15,
+/* Acceptance Code (4 bytes) in RESET mode */
+        SJA_ACR0     = 0x10,
+/* Acceptance Mask (4 bytes) in RESET mode */
+        SJA_AMR0     = 0x14,
+/* 4 bytes */
+        SJA_PeliCAN_AC_LEN = 4,
+/* Clock Divider */
+        SJA_CDR      = 0x1f
+};
+
+
+/* PeliCAN mode */
+enum SJA1000_BasicCAN_regs {
+        SJA_BCAN_CTR = 0x00,
+/* Command register */
+        SJA_BCAN_CMR = 0x01,
+/* Status register */
+        SJA_BCAN_SR  = 0x02,
+/* Interrupt register */
+        SJA_BCAN_IR  = 0x03
+};
+
+void can_sja_hardware_reset(CanSJA1000State *s);
+
+void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
+                       unsigned size);
+
+uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size);
+
+int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus);
+
+void can_sja_disconnect(CanSJA1000State *s);
+
+int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
+                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque);
+
+void can_sja_exit(CanSJA1000State *s);
+
+int can_sja_can_receive(CanBusClientState *client);
+
+ssize_t can_sja_receive(CanBusClientState *client,
+                        const qemu_can_frame *frames, size_t frames_cnt);
+
+extern const VMStateDescription vmstate_can_sja;
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (2 preceding siblings ...)
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual " pisa
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 default-configs/pci.mak |   1 +
 hw/can/Makefile.objs    |   1 +
 hw/can/can_kvaser_pci.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 377 insertions(+)
 create mode 100644 hw/can/can_kvaser_pci.c

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 979b649fe5..72c0802ced 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -33,6 +33,7 @@ CONFIG_SERIAL_ISA=y
 CONFIG_SERIAL_PCI=y
 CONFIG_CAN_CORE=y
 CONFIG_CAN_SJA1000=y
+CONFIG_CAN_PCI=y
 CONFIG_IPACK=y
 CONFIG_WDT_IB6300ESB=y
 CONFIG_PCI_TESTDEV=y
diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 3c4bf3bfc1..c9d07b9b16 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -8,4 +8,5 @@ else
 common-obj-y += can_host_stub.o
 endif
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
+common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
 endif
diff --git a/hw/can/can_kvaser_pci.c b/hw/can/can_kvaser_pci.c
new file mode 100644
index 0000000000..d85d38b74b
--- /dev/null
+++ b/hw/can/can_kvaser_pci.c
@@ -0,0 +1,375 @@
+/*
+ * Kvaser PCI CAN device (SJA1000 based) emulation
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014 Pavel Pisa
+ *
+ * Partially based on educational PCIexpress APOHW hardware
+ * emulator used fro class A0B36APO at CTU FEE course by
+ *    Rostislav Lisovy and 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 "qemu/event_notifier.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#define TYPE_CAN_PCI_DEV "kvaser_pci"
+
+#define KVASER_PCI_DEV(obj) \
+    OBJECT_CHECK(KvaserPCIState, (obj), TYPE_CAN_PCI_DEV)
+
+#ifndef KVASER_PCI_VENDOR_ID1
+#define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
+#endif
+
+#ifndef KVASER_PCI_DEVICE_ID1
+#define KVASER_PCI_DEVICE_ID1     0x8406
+#endif
+
+#define KVASER_PCI_S5920_RANGE    0x80
+#define KVASER_PCI_SJA_RANGE      0x80
+#define KVASER_PCI_XILINX_RANGE   0x8
+
+#define KVASER_PCI_BYTES_PER_SJA  0x20
+
+#define S5920_OMB                 0x0C
+#define S5920_IMB                 0x1C
+#define S5920_MBEF                0x34
+#define S5920_INTCSR              0x38
+#define S5920_RCR                 0x3C
+#define S5920_PTCR                0x60
+
+#define S5920_INTCSR_ADDON_INTENABLE_M        0x2000
+#define S5920_INTCSR_INTERRUPT_ASSERTED_M     0x800000
+
+#define KVASER_PCI_XILINX_VERINT  7   /* Lower nibble simulate interrupts,
+                                         high nibble version number. */
+
+#define KVASER_PCI_XILINX_VERSION_NUMBER 13
+
+typedef struct KvaserPCIState {
+    /*< private >*/
+    PCIDevice       dev;
+    /*< public >*/
+    MemoryRegion    s5920_io;
+    MemoryRegion    sja_io;
+    MemoryRegion    xilinx_io;
+
+    CanSJA1000State sja_state;
+    qemu_irq        irq;
+
+    uint32_t        s5920_intcsr;
+    uint32_t        s5920_irqstate;
+
+    char            *model; /* The model that support, only SJA1000 now. */
+    char            *canbus;
+    char            *host;
+} KvaserPCIState;
+
+static void kvaser_pci_irq_raise(void *opaque)
+{
+    KvaserPCIState *d = (KvaserPCIState *)opaque;
+    d->s5920_irqstate = 1;
+
+    if (d->s5920_intcsr & S5920_INTCSR_ADDON_INTENABLE_M) {
+        qemu_irq_raise(d->irq);
+    }
+}
+
+static void kvaser_pci_irq_lower(void *opaque)
+{
+    KvaserPCIState *d = (KvaserPCIState *)opaque;
+    d->s5920_irqstate = 0;
+    qemu_irq_lower(d->irq);
+}
+
+static void
+kvaser_pci_reset(void *opaque)
+{
+    KvaserPCIState *d = (KvaserPCIState *)opaque;
+    CanSJA1000State *s = &d->sja_state;
+
+    can_sja_hardware_reset(s);
+}
+
+static uint64_t kvaser_pci_s5920_io_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    KvaserPCIState *d = opaque;
+    uint64_t val;
+
+    switch (addr) {
+    case S5920_INTCSR:
+        val = d->s5920_intcsr;
+        val &= ~S5920_INTCSR_INTERRUPT_ASSERTED_M;
+        if (d->s5920_irqstate) {
+            val |= S5920_INTCSR_INTERRUPT_ASSERTED_M;
+        }
+        return val;
+    }
+    return 0;
+}
+
+static void kvaser_pci_s5920_io_write(void *opaque, hwaddr addr, uint64_t data,
+                                      unsigned size)
+{
+    KvaserPCIState *d = opaque;
+
+    switch (addr) {
+    case S5920_INTCSR:
+        if (~d->s5920_intcsr & data & S5920_INTCSR_ADDON_INTENABLE_M) {
+            if (d->s5920_irqstate) {
+                qemu_irq_raise(d->irq);
+            }
+        }
+        d->s5920_intcsr = data;
+        break;
+    }
+}
+
+static uint64_t kvaser_pci_sja_io_read(void *opaque, hwaddr addr, unsigned size)
+{
+    KvaserPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state;
+
+    if (addr >= KVASER_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr, size);
+}
+
+static void kvaser_pci_sja_io_write(void *opaque, hwaddr addr, uint64_t data,
+                                    unsigned size)
+{
+    KvaserPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state;
+
+    if (addr >= KVASER_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr, data, size);
+}
+
+static uint64_t kvaser_pci_xilinx_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    /*KvaserPCIState *d = opaque;*/
+
+    switch (addr) {
+    case KVASER_PCI_XILINX_VERINT:
+        return (KVASER_PCI_XILINX_VERSION_NUMBER << 4) | 0;
+    }
+
+    return 0;
+}
+
+static void kvaser_pci_xilinx_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    /*KvaserPCIState *d = opaque;*/
+}
+
+static const MemoryRegionOps kvaser_pci_s5920_io_ops = {
+    .read = kvaser_pci_s5920_io_read,
+    .write = kvaser_pci_s5920_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps kvaser_pci_sja_io_ops = {
+    .read = kvaser_pci_sja_io_read,
+    .write = kvaser_pci_sja_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps kvaser_pci_xilinx_io_ops = {
+    .read = kvaser_pci_xilinx_io_read,
+    .write = kvaser_pci_xilinx_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int kvaser_pci_init(PCIDevice *pci_dev)
+{
+    KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
+    CanSJA1000State *s = &d->sja_state;
+    uint8_t *pci_conf;
+    CanBusState *can_bus;
+
+    if (d->model) {
+        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
+            error_report("Can't create CAN device, "
+                         "the model %s is not supported now.", d->model);
+            exit(1);
+        }
+    }
+
+    can_bus = can_bus_find_by_name(d->canbus, true);
+    if (can_bus == NULL) {
+        error_report("Cannot create can find/allocate CAN bus");
+        exit(1);
+
+    }
+
+    if (d->host != NULL) {
+        if (can_bus_connect_to_host_device(can_bus, d->host) < 0) {
+            error_report("Cannot connect CAN bus to host device \"%s\"",
+                         d->host);
+            exit(1);
+        }
+    }
+
+    pci_conf = pci_dev->config;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    d->irq = pci_allocate_irq(&d->dev);
+
+    can_sja_init(s, kvaser_pci_irq_raise, kvaser_pci_irq_lower, d);
+
+    qemu_register_reset(kvaser_pci_reset, d);
+
+    if (can_sja_connect_to_bus(s, can_bus) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    memory_region_init_io(&d->s5920_io, OBJECT(d), &kvaser_pci_s5920_io_ops,
+                          d, "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE);
+    memory_region_init_io(&d->sja_io, OBJECT(d), &kvaser_pci_sja_io_ops,
+                          d, "kvaser_pci-sja", KVASER_PCI_SJA_RANGE);
+    memory_region_init_io(&d->xilinx_io, OBJECT(d), &kvaser_pci_xilinx_io_ops,
+                          d, "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE);
+
+    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->s5920_io);
+    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->sja_io);
+    pci_register_bar(&d->dev, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->xilinx_io);
+
+    return 0;
+}
+
+static void kvaser_pci_exit(PCIDevice *pci_dev)
+{
+    KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
+    CanSJA1000State *s = &d->sja_state;
+
+    can_sja_disconnect(s);
+
+    qemu_unregister_reset(kvaser_pci_reset, d);
+
+    /*
+     * regions d->s5920_io, d->sja_io and d->xilinx_io
+     * are destroyed by QOM now
+     */
+
+    can_sja_exit(s);
+
+    qemu_free_irq(d->irq);
+}
+
+static const VMStateDescription vmstate_kvaser_pci = {
+    .name = "kvaser_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
+        VMSTATE_STRUCT(sja_state, KvaserPCIState, 0, vmstate_can_sja,
+                       CanSJA1000State),
+        /*char *model,*/
+        VMSTATE_UINT32(s5920_intcsr, KvaserPCIState),
+        VMSTATE_UINT32(s5920_irqstate, KvaserPCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void qdev_kvaser_pci_reset(DeviceState *dev)
+{
+    KvaserPCIState *d = KVASER_PCI_DEV(dev);
+    kvaser_pci_reset(d);
+}
+
+static Property kvaser_pci_properties[] = {
+    DEFINE_PROP_STRING("canbus",   KvaserPCIState, canbus),
+    DEFINE_PROP_STRING("host",  KvaserPCIState, host),
+    DEFINE_PROP_STRING("model", KvaserPCIState, model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void kvaser_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = kvaser_pci_init;
+    k->exit = kvaser_pci_exit;
+    k->vendor_id = KVASER_PCI_VENDOR_ID1;
+    k->device_id = KVASER_PCI_DEVICE_ID1;
+    k->revision = 0x00;
+    k->class_id = 0x00ff00;
+    dc->desc = "Kvaser PCICANx";
+    dc->props = kvaser_pci_properties;
+    dc->vmsd = &vmstate_kvaser_pci;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->reset = qdev_kvaser_pci_reset;
+}
+
+static const TypeInfo kvaser_pci_info = {
+    .name          = TYPE_CAN_PCI_DEV,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(KvaserPCIState),
+    .class_init    = kvaser_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void kvaser_pci_register_types(void)
+{
+    type_register_static(&kvaser_pci_info);
+}
+
+type_init(kvaser_pci_register_types)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (3 preceding siblings ...)
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-12 10:34   ` KONRAD Frederic
  2018-01-14  0:02   ` Deniz Eren
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 6/7] CAN bus MIOe-3680 " pisa
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Deniz Eren <deniz.eren@icloud.com>

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 hw/can/Makefile.objs     |   1 +
 hw/can/can_pcm3680_pci.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 336 insertions(+)
 create mode 100644 hw/can/can_pcm3680_pci.c

diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index c9d07b9b16..6a328f0c3a 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -9,4 +9,5 @@ common-obj-y += can_host_stub.o
 endif
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
+common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
 endif
diff --git a/hw/can/can_pcm3680_pci.c b/hw/can/can_pcm3680_pci.c
new file mode 100644
index 0000000000..692aab6ab8
--- /dev/null
+++ b/hw/can/can_pcm3680_pci.c
@@ -0,0 +1,335 @@
+/*
+ * PCM-3680i PCI CAN device (SJA1000 based) emulation
+ *
+ * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
+ *
+ * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
+ * Jin Yang and Pavel Pisa
+ *
+ * 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 "qemu/event_notifier.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#define TYPE_CAN_PCI_DEV "pcm3680_pci"
+
+#define PCM3680i_PCI_DEV(obj) \
+    OBJECT_CHECK(Pcm3680iPCIState, (obj), TYPE_CAN_PCI_DEV)
+
+#ifndef PCM3680i_PCI_VENDOR_ID1
+#define PCM3680i_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */
+#endif
+
+#ifndef PCM3680i_PCI_DEVICE_ID1
+#define PCM3680i_PCI_DEVICE_ID1     0xc002
+#endif
+
+#define PCM3680i_PCI_SJA_RANGE     0x200
+
+#define PCM3680i_PCI_BYTES_PER_SJA 0x20
+
+typedef struct Pcm3680iPCIState {
+    /*< private >*/
+    PCIDevice       dev;
+    /*< public >*/
+    MemoryRegion    sja_io[2];
+
+    CanSJA1000State sja_state[2];
+    qemu_irq        irq;
+
+    char            *model; /* The model that support, only SJA1000 now. */
+    char            *canbus[2];
+    char            *host[2];
+} Pcm3680iPCIState;
+
+static void pcm3680i_pci_irq_raise(void *opaque)
+{
+    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
+
+    qemu_irq_raise(d->irq);
+}
+
+static void pcm3680i_pci_irq_lower(void *opaque)
+{
+    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
+
+    qemu_irq_lower(d->irq);
+}
+
+static void
+pcm3680i_pci_reset(void *opaque)
+{
+    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_hardware_reset(s1);
+    can_sja_hardware_reset(s2);
+}
+
+static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr, size);
+}
+
+static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
+                                       uint64_t data, unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr, data, size);
+}
+
+static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr, size);
+}
+
+static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr, data, size);
+}
+
+static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
+    .read = pcm3680i_pci_sja1_io_read,
+    .write = pcm3680i_pci_sja1_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
+    .read = pcm3680i_pci_sja2_io_read,
+    .write = pcm3680i_pci_sja2_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int pcm3680i_pci_init(PCIDevice *pci_dev)
+{
+    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+    uint8_t *pci_conf;
+    CanBusState *can_bus1;
+    CanBusState *can_bus2;
+
+    if (d->model) {
+        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
+            error_report("Can't create CAN device, "
+                         "the model %s is not supported now.", d->model);
+            exit(1);
+        }
+    }
+
+    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
+    if (can_bus1 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #1");
+        exit(1);
+    }
+
+    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
+    if (can_bus2 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #2");
+        exit(1);
+    }
+
+    if (d->host[0] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
+            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
+                         d->host[0]);
+            exit(1);
+        }
+    }
+
+    if (d->host[1] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
+            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
+                         d->host[1]);
+            exit(1);
+        }
+    }
+
+    pci_conf = pci_dev->config;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    d->irq = pci_allocate_irq(&d->dev);
+
+    can_sja_init(s1, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
+    can_sja_init(s2, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
+
+    qemu_register_reset(pcm3680i_pci_reset, d);
+
+    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
+                          d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE / 2);
+    memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
+                          d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE / 2);
+
+    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
+                                             &d->sja_io[0]);
+    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
+                                             &d->sja_io[1]);
+
+    return 0;
+}
+
+static void pcm3680i_pci_exit(PCIDevice *pci_dev)
+{
+    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_disconnect(s1);
+    can_sja_disconnect(s2);
+
+    qemu_unregister_reset(pcm3680i_pci_reset, d);
+
+    /*
+     * region d->sja_io is destroyed by QOM now
+     */
+    /* memory_region_destroy(&d->sja_io[0]); */
+    /* memory_region_destroy(&d->sja_io[1]); */
+
+    can_sja_exit(s1);
+    can_sja_exit(s2);
+
+    qemu_free_irq(d->irq);
+}
+
+static const VMStateDescription vmstate_pcm3680i_pci = {
+    .name = "pcm3680i_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
+        VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
+                       vmstate_can_sja, CanSJA1000State),
+        VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
+                       vmstate_can_sja, CanSJA1000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void qdev_pcm3680i_pci_reset(DeviceState *dev)
+{
+    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
+    pcm3680i_pci_reset(d);
+}
+
+static Property pcm3680i_pci_properties[] = {
+    DEFINE_PROP_STRING("canbus1",   Pcm3680iPCIState, canbus[0]),
+    DEFINE_PROP_STRING("canbus2",   Pcm3680iPCIState, canbus[1]),
+    DEFINE_PROP_STRING("host1",  Pcm3680iPCIState, host[0]),
+    DEFINE_PROP_STRING("host2",  Pcm3680iPCIState, host[1]),
+    DEFINE_PROP_STRING("model", Pcm3680iPCIState, model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pcm3680i_pci_init;
+    k->exit = pcm3680i_pci_exit;
+    k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
+    k->device_id = PCM3680i_PCI_DEVICE_ID1;
+    k->revision = 0x00;
+    k->class_id = 0x000c09;
+    k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
+    k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
+    dc->desc = "Pcm3680i PCICANx";
+    dc->props = pcm3680i_pci_properties;
+    dc->vmsd = &vmstate_pcm3680i_pci;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->reset = qdev_pcm3680i_pci_reset;
+}
+
+static const TypeInfo pcm3680i_pci_info = {
+    .name          = TYPE_CAN_PCI_DEV,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(Pcm3680iPCIState),
+    .class_init    = pcm3680i_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void pcm3680i_pci_register_types(void)
+{
+    type_register_static(&pcm3680i_pci_info);
+}
+
+type_init(pcm3680i_pci_register_types)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 6/7] CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (4 preceding siblings ...)
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual " pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-14  0:03   ` Deniz Eren
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 7/7] QEMU CAN bus emulation documentation pisa
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Deniz Eren <deniz.eren@icloud.com>

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 hw/can/Makefile.objs      |   1 +
 hw/can/can_mioe3680_pci.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 336 insertions(+)
 create mode 100644 hw/can/can_mioe3680_pci.c

diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 6a328f0c3a..8fcc455800 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -10,4 +10,5 @@ endif
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
 common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
+common-obj-$(CONFIG_CAN_PCI) += can_mioe3680_pci.o
 endif
diff --git a/hw/can/can_mioe3680_pci.c b/hw/can/can_mioe3680_pci.c
new file mode 100644
index 0000000000..799e74a7ac
--- /dev/null
+++ b/hw/can/can_mioe3680_pci.c
@@ -0,0 +1,335 @@
+/*
+ * MIOe-3680 PCI CAN device (SJA1000 based) emulation
+ *
+ * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
+ *
+ * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
+ * Jin Yang and Pavel Pisa
+ *
+ * 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 "qemu/event_notifier.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#define TYPE_CAN_PCI_DEV "mioe3680_pci"
+
+#define MIOe3680_PCI_DEV(obj) \
+    OBJECT_CHECK(Mioe3680PCIState, (obj), TYPE_CAN_PCI_DEV)
+
+#ifndef MIOe3680_PCI_VENDOR_ID1
+#define MIOe3680_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */
+#endif
+
+#ifndef MIOe3680_PCI_DEVICE_ID1
+#define MIOe3680_PCI_DEVICE_ID1     0xc302
+#endif
+
+#define MIOe3680_PCI_SJA_RANGE     0x800
+
+#define MIOe3680_PCI_BYTES_PER_SJA 0x80
+
+typedef struct Mioe3680PCIState {
+    /*< private >*/
+    PCIDevice       dev;
+    /*< public >*/
+    MemoryRegion    sja_io[2];
+
+    CanSJA1000State sja_state[2];
+    qemu_irq        irq;
+
+    char            *model; /* The model that support, only SJA1000 now. */
+    char            *canbus[2];
+    char            *host[2];
+} Mioe3680PCIState;
+
+static void mioe3680_pci_irq_raise(void *opaque)
+{
+    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
+
+    qemu_irq_raise(d->irq);
+}
+
+static void mioe3680_pci_irq_lower(void *opaque)
+{
+    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
+
+    qemu_irq_lower(d->irq);
+}
+
+static void
+mioe3680_pci_reset(void *opaque)
+{
+    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_hardware_reset(s1);
+    can_sja_hardware_reset(s2);
+}
+
+static uint64_t mioe3680_pci_sja1_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr >> 2, size);
+}
+
+static void mioe3680_pci_sja1_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr >> 2, data, size);
+}
+
+static uint64_t mioe3680_pci_sja2_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr >> 2, size);
+}
+
+static void mioe3680_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr >> 2, data, size);
+}
+
+static const MemoryRegionOps mioe3680_pci_sja1_io_ops = {
+    .read = mioe3680_pci_sja1_io_read,
+    .write = mioe3680_pci_sja1_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps mioe3680_pci_sja2_io_ops = {
+    .read = mioe3680_pci_sja2_io_read,
+    .write = mioe3680_pci_sja2_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int mioe3680_pci_init(PCIDevice *pci_dev)
+{
+    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+    uint8_t *pci_conf;
+    CanBusState *can_bus1;
+    CanBusState *can_bus2;
+
+    if (d->model) {
+        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
+            error_report("Can't create CAN device, "
+                         "the model %s is not supported now.", d->model);
+            exit(1);
+        }
+    }
+
+    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
+    if (can_bus1 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #1");
+        exit(1);
+    }
+
+    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
+    if (can_bus2 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #2");
+        exit(1);
+    }
+
+    if (d->host[0] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
+            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
+                         d->host[0]);
+            exit(1);
+        }
+    }
+
+    if (d->host[1] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
+            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
+                         d->host[1]);
+            exit(1);
+        }
+    }
+
+    pci_conf = pci_dev->config;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    d->irq = pci_allocate_irq(&d->dev);
+
+    can_sja_init(s1, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
+    can_sja_init(s2, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
+
+    qemu_register_reset(mioe3680_pci_reset, d);
+
+    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    memory_region_init_io(&d->sja_io[0], OBJECT(d), &mioe3680_pci_sja1_io_ops,
+                          d, "mioe3680_pci-sja1", MIOe3680_PCI_SJA_RANGE / 2);
+    memory_region_init_io(&d->sja_io[1], OBJECT(d), &mioe3680_pci_sja2_io_ops,
+                          d, "mioe3680_pci-sja2", MIOe3680_PCI_SJA_RANGE / 2);
+
+    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->sja_io[0]);
+    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->sja_io[1]);
+
+    return 0;
+}
+
+static void mioe3680_pci_exit(PCIDevice *pci_dev)
+{
+    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_disconnect(s1);
+    can_sja_disconnect(s2);
+
+    qemu_unregister_reset(mioe3680_pci_reset, d);
+
+    /*
+     * region d->sja_io is destroyed by QOM now
+     */
+    /* memory_region_destroy(&d->sja_io[0]); */
+    /* memory_region_destroy(&d->sja_io[1]); */
+
+    can_sja_exit(s1);
+    can_sja_exit(s2);
+
+    qemu_free_irq(d->irq);
+}
+
+static const VMStateDescription vmstate_mioe3680_pci = {
+    .name = "mioe3680_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState),
+        VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja,
+                       CanSJA1000State),
+        VMSTATE_STRUCT(sja_state[1], Mioe3680PCIState, 0, vmstate_can_sja,
+                       CanSJA1000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void qdev_mioe3680_pci_reset(DeviceState *dev)
+{
+    Mioe3680PCIState *d = MIOe3680_PCI_DEV(dev);
+    mioe3680_pci_reset(d);
+}
+
+static Property mioe3680_pci_properties[] = {
+    DEFINE_PROP_STRING("canbus1",   Mioe3680PCIState, canbus[0]),
+    DEFINE_PROP_STRING("canbus2",   Mioe3680PCIState, canbus[1]),
+    DEFINE_PROP_STRING("host1",  Mioe3680PCIState, host[0]),
+    DEFINE_PROP_STRING("host2",  Mioe3680PCIState, host[1]),
+    DEFINE_PROP_STRING("model", Mioe3680PCIState, model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = mioe3680_pci_init;
+    k->exit = mioe3680_pci_exit;
+    k->vendor_id = MIOe3680_PCI_VENDOR_ID1;
+    k->device_id = MIOe3680_PCI_DEVICE_ID1;
+    k->revision = 0x00;
+    k->class_id = 0x000c09;
+    k->subsystem_vendor_id = MIOe3680_PCI_VENDOR_ID1;
+    k->subsystem_id = MIOe3680_PCI_DEVICE_ID1;
+    dc->desc = "Mioe3680 PCICANx";
+    dc->props = mioe3680_pci_properties;
+    dc->vmsd = &vmstate_mioe3680_pci;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->reset = qdev_mioe3680_pci_reset;
+}
+
+static const TypeInfo mioe3680_pci_info = {
+    .name          = TYPE_CAN_PCI_DEV,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(Mioe3680PCIState),
+    .class_init    = mioe3680_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void mioe3680_pci_register_types(void)
+{
+    type_register_static(&mioe3680_pci_info);
+}
+
+type_init(mioe3680_pci_register_types)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 7/7] QEMU CAN bus emulation documentation
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (5 preceding siblings ...)
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 6/7] CAN bus MIOe-3680 " pisa
@ 2018-01-06 20:47 ` pisa
  2018-01-06 21:10 ` [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) no-reply
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: pisa @ 2018-01-06 20:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 docs/can.txt | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 docs/can.txt

diff --git a/docs/can.txt b/docs/can.txt
new file mode 100644
index 0000000000..ac3170e947
--- /dev/null
+++ b/docs/can.txt
@@ -0,0 +1,78 @@
+QEMU CAN bus emulation support
+==============================
+
+The CAN bus emulation provides mechanism to connect multiple
+emulated CAN controller chips together by one or multiple CAN busses
+(the controller device "canbus"  parameter). The individual busses
+can be connected to host system CAN API (at this time only Linux
+SocketCAN is supported).
+
+The concept of busses is generic and different CAN controllers
+can be implemented for it but at this time only SJA1000 chip
+controller is implemented.
+
+The PCI addon card hardware has been selected as the first CAN
+interface to implement because such device can be easily connected
+to systems with different CPU architectures (x86, PowerPC, ARM, etc.).
+
+The project has been initially started in frame of RTEMS GSoC 2013
+slot by Jin Yang under our mentoring  The initial idea was to provide generic
+CAN subsystem for RTEMS. But lack of common environment for code and RTEMS
+testing lead to goal change to provide environment which provides complete
+emulated environment for testing and RTEMS GSoC slot has been donated
+to work on CAN hardware emulation on QEMU.
+
+Examples how to use CAN emulation
+=================================
+
+When QEMU with CAN PCI support is compiled then one of the next
+CAN boards can be selected
+
+ (1) CAN bus Kvaser PCI CAN-S (single SJA1000 channel) boad. QEMU startup options
+    -device kvaser_pci,canbus=canbus0
+    Add "host" parameter to connect device to host system CAN bus
+    -device kvaser_pci,canbus=canbus0,host=can0
+
+ (2) CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation
+    -device pcm3680_pci,canbus=canbus0,host=can0
+
+ (3) CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation
+    -device mioe3680_pci,canbus=canbus0,host=can0
+
+
+The ''kvaser_pci'' board/device model is compatible with and has been tested with
+''kvaser_pci'' driver included in mainline Linux kernel.
+The tested setup was Linux 4.9 kernel on the host and guest side.
+
+Next parameters has been used for qemu-system-x86_64
+
+    qemu-system-x86_64 -enable-kvm -kernel /boot/vmlinuz-4.9.0-4-amd64 \
+      -initrd ramdisk.cpio \
+      -virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \
+      -vga cirrus \
+      -device kvaser_pci,canbus=canbus0,host=can0 \
+      -nographic -append "console=ttyS0"
+
+The list of parameters for qemu-system-arm
+
+    qemu-system-arm -cpu arm1176 -m 256 -M versatilepb \
+      -kernel kernel-qemu-arm1176-versatilepb \
+      -hda rpi-wheezy-overlay \
+      -append "console=ttyAMA0 root=/dev/sda2 ro init=/sbin/init-overlay" \
+      -nographic \
+      -virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \
+      -device kvaser_pci,canbus=canbus0,host=can0 \
+
+Links to other resources
+========================
+
+ (1) Repository with development branch can-pci at Czech Technical University
+     https://gitlab.fel.cvut.cz/canbus/qemu-canbus
+ (2) GitHub repository with can-pci and our other changes included
+     https://gitlab.fel.cvut.cz/canbus/qemu-canbus
+ (3) RTEMS page describing project
+     https://devel.rtems.org/wiki/Developer/Simulators/QEMU/CANEmulation
+ (4) RTLWS 2015 article about the projevt and its use with CANopen emulation
+     http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can.pdf
+     Slides
+     http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can-slides.pdf
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (6 preceding siblings ...)
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 7/7] QEMU CAN bus emulation documentation pisa
@ 2018-01-06 21:10 ` no-reply
  2018-01-11 11:45 ` Oleksij Rempel
  2018-01-12 10:43 ` KONRAD Frederic
  9 siblings, 0 replies; 17+ messages in thread
From: no-reply @ 2018-01-06 21:10 UTC (permalink / raw)
  To: pisa
  Cc: famz, qemu-devel, marex, socketcan, stefanha, deniz.eren,
	o.rempel, frederic.konrad, jan.kiszka

Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: cover.1515260163.git.pisa@cmp.felk.cvut.cz
Subject: [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far)

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
f6555aed49 QEMU CAN bus emulation documentation
b43b31c8f5 CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
49228bb881 CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
94bf8a7051 CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
137eb4460e CAN bus SJA1000 chip register level emulation for QEMU
7b408f317f CAN bus support to connect bust to Linux host SocketCAN interface.
a56657c636 CAN bus simple messages transport implementation for QEMU

=== OUTPUT BEGIN ===
Checking PATCH 1/7: CAN bus simple messages transport implementation for QEMU...
WARNING: line over 80 characters
#199: FILE: hw/can/can_core.c:125:
+        error_report("CAN bus connect to host device not supported on this system");

WARNING: line over 80 characters
#329: FILE: include/can/can_emu.h:78:
+#define QEMU_CAN_INV_FILTER 0x20000000U /* to be set in qemu_can_filter.can_id */

WARNING: line over 80 characters
#365: FILE: include/can/can_emu.h:114:
+extern int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name);

total: 0 errors, 3 warnings, 328 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 2/7: CAN bus support to connect bust to Linux host SocketCAN interface....
WARNING: line over 80 characters
#228: FILE: hw/can/can_socketcan.c:194:
+CanBusSocketcanConnectState *can_bus_socketcan_connect_new(const char *host_dev_name)

WARNING: line over 80 characters
#298: FILE: hw/can/can_socketcan.c:264:
+int can_bus_connect_to_host_socketcan(CanBusState *bus, const char *host_dev_name)

total: 0 errors, 2 warnings, 303 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 3/7: CAN bus SJA1000 chip register level emulation for QEMU...
WARNING: line over 80 characters
#383: FILE: hw/can/can_sja1000.c:337:
+        buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,x,x,x,x,x */

WARNING: line over 80 characters
#398: FILE: hw/can/can_sja1000.c:352:
+    if ((frame->can_id & QEMU_CAN_EFF_FLAG) || /* EFF, not support for BasicMode. */

WARNING: line over 80 characters
#399: FILE: hw/can/can_sja1000.c:353:
+       (frame->can_id & QEMU_CAN_ERR_FLAG)) {  /* or Error frame, NOT support now. */

WARNING: line over 80 characters
#486: FILE: hw/can/can_sja1000.c:440:
+                s->status_pel |= (3 << 2); /* Set transmission complete status, */

WARNING: line over 80 characters
#595: FILE: hw/can/can_sja1000.c:549:
+                s->status_bas |= (3 << 2); /* Set transmission complete status, */

WARNING: line over 80 characters
#615: FILE: hw/can/can_sja1000.c:569:
+                        fprintf(stderr, " %02X", s->rx_buff[(s->rxbuf_start + i) %

WARNING: line over 80 characters
#847: FILE: hw/can/can_sja1000.c:801:
+        s->status_pel |= (1 << 4); /* the CAN controller is receiving a message */

WARNING: line over 80 characters
#897: FILE: hw/can/can_sja1000.c:851:
+        s->status_bas |= (1 << 4); /* the CAN controller is receiving a message */

ERROR: do not use C99 // comments
#1087: FILE: hw/can/can_sja1000.h:39:
+//#define DEBUG_CAN

WARNING: line over 80 characters
#1108: FILE: hw/can/can_sja1000.h:60:
+    uint8_t         interrupt_en;  /* PeliCAN, addr 4, Interrupt Enable register */

WARNING: line over 80 characters
#1109: FILE: hw/can/can_sja1000.h:61:
+    uint8_t         rxmsg_cnt;     /* PeliCAN, addr 29, RX message counter. DS-p49 */

WARNING: line over 80 characters
#1110: FILE: hw/can/can_sja1000.h:62:
+    uint8_t         rxbuf_start;   /* PeliCAN, addr 30, RX buffer start address, DS-p49 */

WARNING: line over 80 characters
#1111: FILE: hw/can/can_sja1000.h:63:
+    uint8_t         clock;         /* PeliCAN, addr 31, Clock Divider register, DS-p55 */

WARNING: line over 80 characters
#1125: FILE: hw/can/can_sja1000.h:77:
+    uint8_t         code;          /* BasicCAN, addr 4, Acceptance code register */

WARNING: line over 80 characters
#1126: FILE: hw/can/can_sja1000.h:78:
+    uint8_t         mask;          /* BasicCAN, addr 5, Acceptance mask register */

WARNING: line over 80 characters
#1171: FILE: hw/can/can_sja1000.h:123:
+/* ID bytes (11 bits in 0 and 1 or 16 bits in 0,1 and 13 bits in 2,3 (extended)) */

total: 1 errors, 15 warnings, 1184 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 4/7: CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added....
Checking PATCH 5/7: CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added....
WARNING: line over 80 characters
#70: FILE: hw/can/can_pcm3680_pci.c:46:
+#define PCM3680i_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */

total: 0 errors, 1 warnings, 340 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 6/7: CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added....
WARNING: line over 80 characters
#70: FILE: hw/can/can_mioe3680_pci.c:46:
+#define MIOe3680_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */

total: 0 errors, 1 warnings, 340 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 7/7: QEMU CAN bus emulation documentation...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (7 preceding siblings ...)
  2018-01-06 21:10 ` [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) no-reply
@ 2018-01-11 11:45 ` Oleksij Rempel
  2018-01-12 10:43 ` KONRAD Frederic
  9 siblings, 0 replies; 17+ messages in thread
From: Oleksij Rempel @ 2018-01-11 11:45 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Marc Kleine-Budde

Hi,

thank you for your work!

we integrated your patches in our OSALES BSP [1] and did some basic tests:
- communication between host and guest
- communication between real CAN/J1939 device over the host to guest.

J1939(real device) -> candleLight v1.1 -> host (kernel v4.13) -> QEMU
(with your CAN patches) -> kernel (with experimental J1939 support) ->
J1939 App
So far it works without noticeable issues.

We are working on a CAN/J1939/ISObus protocol development for linux
kernel and create some regression testing infrastructure to reduce
possible problems before our patches will go to kernel mainline.
In this case QEMU is really helpful.

I hope your patches will go QEMU mainline soon :)

[1]
https://git.pengutronix.de/cgit/OSELAS.BSP-Pengutronix-J1939/?h=bst/x86-wip

On 06.01.2018 21:47, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Basic emulation of CAN bus controller and interconnection for QEMU.
> 
> Patches version 3:
> Support to connect to host SocketCAN interface has been
> separated from the core bus implementation. Only simple
> statically initialize pointer to the connection function
> is used, no QOM concept for now.
> SJA1000 message filters redone and code unified where
> possible.
> Basic documentation added.
> QEMU_ALIGNED used in definition of CAN frame structure,
> structure and defines still separated from Linux/SocketCAN
> API defined ones to allow to keep QEMU message format
> independed from host system one. Check for correspondence
> to socketcan one added.
> 
> Patches version 2:
> The bus emulation and the SJA1000 chip emulation introduced
> by individual patches as suggested by Frederic Konrad.
> Simple example board to test SJA1000 as single memory-mapped BAR
> has been omitted in a new series because emulation of real
> existing boards can provide same functions now.
> Conditionalized debug printfs changed to be exposed to compiler
> syntax check as suggested in review.
> 
> The work has been started by Jin Yang in the frame of GSoC 2013 slot
> contributed by RTEMS project which has been looking for environment
> to allow develop and test CAN drivers for multiple CPU architectures.
> 
> I have menthored the project and then done substantial code cleanup
> and update to QOM. Deniz Eren then used emulation for SJA1000 base card
> driver development for other operating system and contributed
> PCM-3680I and MIOe-3680 support.
> 
> Some page about the project
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus/wikis/home
> 
> FEE CTU GitLab repository with can-pci branch for 2.3, 2.4, 2.7, 2.8, 2.10 and 2.11
> version if QEMU is available there
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci
> 
> mirror at GitHub
> 
>   https://github.com/CTU-IIG/qemu
> 
> There are many areas for improvement and extension of the code still
> (for example freeze and migration is not implemented. CAN controllers
> use proper QOM model but bus/interconnection emulation uses simple broadcast
> connection which is required for CAN, but it is not based on QEMU bus model).
> I have tried to look into QEMU VLANs implementation but it
> does not map straightforward to CAN and I would need some help/opinion
> from more advanced developers to decide what is their right
> mapping to CAN.
> 
> CAN-FD support would be interesting requires other developers/
> companies contributions or setup of some project to allow invite
> some students and colleagues from my university into project.
> 
> But I believe that (even in its actual state) provided solution
> is great help for embedded systems developers when they can connect
> SocketCAN from one or more embedded systems running in virtual
> environment together or with Linux host SocketCAN virtual
> or real bus interfaces.
> 
> We have even tested our generic CANopen device configured
> for CANopen 401 profile for generic I/O running in the virtual
> system which can control GPIO inputs/outputs through virtual
> industrial I/O card.
> 
> Generally QEMU can be interesting setup which allows
> to test complete industrial and automotive applications
> in virtual environment even before real hardware is availabe.
> 
> Deniz Eren (2):
>   CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
>   CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
> 
> Pavel Pisa (5):
>   CAN bus simple messages transport implementation for QEMU
>   CAN bus support to connect bust to Linux host SocketCAN interface.
>   CAN bus SJA1000 chip register level emulation for QEMU
>   CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
>   QEMU CAN bus emulation documentation
> 
>  default-configs/pci.mak   |   3 +
>  docs/can.txt              |  78 ++++
>  hw/Makefile.objs          |   1 +
>  hw/can/Makefile.objs      |  14 +
>  hw/can/can_core.c         | 129 ++++++
>  hw/can/can_host_stub.c    |  36 ++
>  hw/can/can_kvaser_pci.c   | 375 +++++++++++++++++
>  hw/can/can_mioe3680_pci.c | 335 ++++++++++++++++
>  hw/can/can_pcm3680_pci.c  | 335 ++++++++++++++++
>  hw/can/can_sja1000.c      | 996 ++++++++++++++++++++++++++++++++++++++++++++++
>  hw/can/can_sja1000.h      | 176 ++++++++
>  hw/can/can_socketcan.c    | 294 ++++++++++++++
>  include/can/can_emu.h     | 143 +++++++
>  13 files changed, 2915 insertions(+)
>  create mode 100644 docs/can.txt
>  create mode 100644 hw/can/Makefile.objs
>  create mode 100644 hw/can/can_core.c
>  create mode 100644 hw/can/can_host_stub.c
>  create mode 100644 hw/can/can_kvaser_pci.c
>  create mode 100644 hw/can/can_mioe3680_pci.c
>  create mode 100644 hw/can/can_pcm3680_pci.c
>  create mode 100644 hw/can/can_sja1000.c
>  create mode 100644 hw/can/can_sja1000.h
>  create mode 100644 hw/can/can_socketcan.c
>  create mode 100644 include/can/can_emu.h
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU pisa
@ 2018-01-12 10:07   ` KONRAD Frederic
  0 siblings, 0 replies; 17+ messages in thread
From: KONRAD Frederic @ 2018-01-12 10:07 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Jan Kiszka

Hi Pavel,

On 01/06/2018 09:47 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> The CanBusState state structure is created for each
> emulated CAN channel. Individual clients/emulated
> CAN interfaces or host interface connection registers
> to the bus by CanBusClientState structure.
> 
> The CAN core is prepared to support connection to the
> real host CAN bus network. The commit with such support
> for Linux SocketCAN follows.
> 
> Implementation is as simple as possible, no migration,
> messages prioritization and queuing considered for now.
> But it is intended to be extended when need arises.
> 
> Development repository and more documentation at
> 
> https://gitlab.fel.cvut.cz/canbus/qemu-canbus
> 
> The work is based on Jin Yang GSoC 2013 work funded
> by Google and mentored in frame of RTEMS project GSoC
> slot donated to QEMU.
> 
> Rewritten for QEMU-2.0+ versions and architecture cleanup
> by Pavel Pisa (Czech Technical University in Prague).
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>   default-configs/pci.mak |   1 +
>   hw/Makefile.objs        |   1 +
>   hw/can/Makefile.objs    |   6 ++
>   hw/can/can_core.c       | 129 +++++++++++++++++++++++++++++++++++++++++++
>   hw/can/can_host_stub.c  |  36 ++++++++++++
>   include/can/can_emu.h   | 143 ++++++++++++++++++++++++++++++++++++++++++++++++
>   6 files changed, 316 insertions(+)
>   create mode 100644 hw/can/Makefile.objs
>   create mode 100644 hw/can/can_core.c
>   create mode 100644 hw/can/can_host_stub.c
>   create mode 100644 include/can/can_emu.h
> 
> diff --git a/default-configs/pci.mak b/default-configs/pci.mak
> index e514bdef42..bbe11887a1 100644
> --- a/default-configs/pci.mak
> +++ b/default-configs/pci.mak
> @@ -31,6 +31,7 @@ CONFIG_ESP_PCI=y
>   CONFIG_SERIAL=y
>   CONFIG_SERIAL_ISA=y
>   CONFIG_SERIAL_PCI=y
> +CONFIG_CAN_CORE=y
>   CONFIG_IPACK=y
>   CONFIG_WDT_IB6300ESB=y
>   CONFIG_PCI_TESTDEV=y
> diff --git a/hw/Makefile.objs b/hw/Makefile.objs
> index cf4cb2010b..9d84b8faaa 100644
> --- a/hw/Makefile.objs
> +++ b/hw/Makefile.objs
> @@ -6,6 +6,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += block/
>   devices-dirs-$(CONFIG_SOFTMMU) += bt/
>   devices-dirs-$(CONFIG_SOFTMMU) += char/
>   devices-dirs-$(CONFIG_SOFTMMU) += cpu/
> +devices-dirs-$(CONFIG_SOFTMMU) += can/
>   devices-dirs-$(CONFIG_SOFTMMU) += display/
>   devices-dirs-$(CONFIG_SOFTMMU) += dma/
>   devices-dirs-$(CONFIG_SOFTMMU) += gpio/
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> new file mode 100644
> index 0000000000..1028d7c455
> --- /dev/null
> +++ b/hw/can/Makefile.objs
> @@ -0,0 +1,6 @@
> +# CAN bus interfaces emulation and infrastructure
> +
> +ifeq ($(CONFIG_CAN_CORE),y)
> +common-obj-y += can_core.o
> +common-obj-y += can_host_stub.o
> +endif
> diff --git a/hw/can/can_core.c b/hw/can/can_core.c
> new file mode 100644
> index 0000000000..49ba3c6ef2
> --- /dev/null
> +++ b/hw/can/can_core.c
> @@ -0,0 +1,129 @@
> +/*
> + * 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 "qemu/error-report.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +#ifndef DEBUG_CAN
> +#define DEBUG_CAN 0
> +#endif /*DEBUG_CAN*/

This seems not used?

> +
> +static QTAILQ_HEAD(, CanBusState) can_buses =
> +    QTAILQ_HEAD_INITIALIZER(can_buses);
> +
> +CanBusState *can_bus_find_by_name(const char *name, bool create_missing)
> +{
> +    CanBusState *bus;
> +
> +    if (name == NULL) {
> +        name = "canbus0";
> +    }
> +
> +    QTAILQ_FOREACH(bus, &can_buses, next) {
> +        if (!strcmp(bus->name, name)) {
> +            return bus;
> +        }
> +    }
> +
> +    if (!create_missing) {
> +        return 0;
> +    }
> +
> +    bus = g_malloc0(sizeof(*bus));
> +    if (bus == NULL) {
> +        return NULL;
> +    }
> +
> +    QTAILQ_INIT(&bus->clients);
> +
> +    bus->name = g_strdup(name);
> +
> +    QTAILQ_INSERT_TAIL(&can_buses, bus, next);
> +    return bus;
> +}
> +
> +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_client_set_filters(CanBusClientState *client,
> +             const struct qemu_can_filter *filters, size_t filters_cnt)
> +{
> +    return 0;
> +}
> +
> +int can_bus_connect_to_host_device(CanBusState *bus, const char *name)
> +{
> +    if (can_bus_connect_to_host_variant == NULL) {
> +        error_report("CAN bus connect to host device not supported on this system");
> +        exit(1);
> +    }
> +    return can_bus_connect_to_host_variant(bus, name);
> +}
> diff --git a/hw/can/can_host_stub.c b/hw/can/can_host_stub.c
> new file mode 100644
> index 0000000000..748d25f995
> --- /dev/null
> +++ b/hw/can/can_host_stub.c
> @@ -0,0 +1,36 @@
> +/*
> + * CAN stub to connect to host system CAN interface
> + *
> + * 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 "qemu/error-report.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +
> +int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
> +        NULL;
> diff --git a/include/can/can_emu.h b/include/can/can_emu.h
> new file mode 100644
> index 0000000000..5c149a2ae9
> --- /dev/null
> +++ b/include/can/can_emu.h
> @@ -0,0 +1,143 @@
> +/*
> + * 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.
> + */
> +
> +#ifndef NET_CAN_EMU_H
> +#define NET_CAN_EMU_H
> +
> +#include "qemu/queue.h"
> +
> +/* NOTE: the following two structures is copied from <linux/can.h>. */
> +
> +/*
> + * Controller Area Network Identifier structure
> + *
> + * bit 0-28    : CAN identifier (11/29 bit)
> + * bit 29      : error frame flag (0 = data frame, 1 = error frame)
> + * bit 30      : remote transmission request flag (1 = rtr frame)
> + * bit 31      : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
> + */
> +typedef uint32_t qemu_canid_t;
> +
> +typedef struct qemu_can_frame {
> +    qemu_canid_t    can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
> +    uint8_t         can_dlc; /* data length code: 0 .. 8 */
> +    uint8_t         data[8] QEMU_ALIGNED(8);
> +} qemu_can_frame;
> +
> +/* Keep defines for QEMU separate from Linux ones for now */
> +
> +#define QEMU_CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
> +#define QEMU_CAN_RTR_FLAG 0x40000000U /* remote transmission request */
> +#define QEMU_CAN_ERR_FLAG 0x20000000U /* error message frame */
> +
> +#define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
> +#define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
> +
> +/**
> + * struct qemu_can_filter - CAN ID based filter in can_register().
> + * @can_id:   relevant bits of CAN ID which are not masked out.
> + * @can_mask: CAN mask (see description)
> + *
> + * Description:
> + * A filter matches, when
> + *
> + *          <received_can_id> & mask == can_id & mask
> + *
> + * The filter can be inverted (QEMU_CAN_INV_FILTER bit set in can_id) or it can
> + * filter for error message frames (QEMU_CAN_ERR_FLAG bit set in mask).
> + */
> +typedef struct qemu_can_filter {
> +    qemu_canid_t    can_id;
> +    qemu_canid_t    can_mask;
> +} qemu_can_filter;
> +
> +#define QEMU_CAN_INV_FILTER 0x20000000U /* to be set in qemu_can_filter.can_id */
> +
> +typedef struct CanBusClientState CanBusClientState;
> +typedef struct CanBusState CanBusState;
> +
> +typedef struct CanBusClientInfo {
> +    /*CanBusClientOptionsKind type;*/

You can drop it.

> +    size_t size;
> +    int (*can_receive)(CanBusClientState *);
> +    ssize_t (*receive)(CanBusClientState *,
> +        const struct qemu_can_frame *frames, size_t frames_cnt);
> +    void (*cleanup) (CanBusClientState *);
> +    void (*poll)(CanBusClientState *, bool enable);
> +} CanBusClientInfo;
> +
> +struct CanBusClientState {
> +    CanBusClientInfo *info;
> +    CanBusState *bus;
> +    int link_down;
> +    QTAILQ_ENTRY(CanBusClientState) next;
> +    CanBusClientState *peer;
> +    /*CanBusQueue *incoming_queue;*/
> +    char *model;
> +    char *name;
> +    /*unsigned receive_disabled : 1;*/
> +    void (*destructor)(CanBusClientState *);
> +    /*unsigned int queue_index;*/
> +    /*unsigned rxfilter_notify_enabled:1;*/

Same here.

> +};
> +
> +struct CanBusState {
> +    char *name;
> +    QTAILQ_HEAD(, CanBusClientState) clients;
> +    QTAILQ_ENTRY(CanBusState) next;
> +};
> +
> +extern int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name);
> +
> +static inline
> +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;
> +}

Is it really required to inline this?

Fred

> +
> +CanBusState *can_bus_find_by_name(const char *name, bool create_missing);
> +
> +int can_bus_insert_client(CanBusState *bus, CanBusClientState *client);
> +
> +int can_bus_remove_client(CanBusClientState *client);
> +
> +ssize_t can_bus_client_send(CanBusClientState *,
> +                            const struct qemu_can_frame *frames,
> +                            size_t frames_cnt);
> +
> +int can_bus_client_set_filters(CanBusClientState *,
> +                               const struct qemu_can_filter *filters,
> +                               size_t filters_cnt);
> +
> +int can_bus_connect_to_host_device(CanBusState *bus, const char *host_dev_name);
> +
> +#endif
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 3/7] CAN bus SJA1000 chip register level emulation for QEMU
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
@ 2018-01-12 10:23   ` KONRAD Frederic
  0 siblings, 0 replies; 17+ messages in thread
From: KONRAD Frederic @ 2018-01-12 10:23 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Jan Kiszka



On 01/06/2018 09:47 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> The core SJA1000 support is independent of following
> patches which map SJA1000 chip to PCI boards.
> 
> The work is based on Jin Yang GSoC 2013 work funded
> by Google and mentored in frame of RTEMS project GSoC
> slot donated to QEMU.
> 
> Rewritten for QEMU-2.0+ versions and architecture cleanup
> by Pavel Pisa (Czech Technical University in Prague).
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>   default-configs/pci.mak |   1 +
>   hw/can/Makefile.objs    |   1 +
>   hw/can/can_sja1000.c    | 996 ++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/can/can_sja1000.h    | 176 +++++++++
>   4 files changed, 1174 insertions(+)
>   create mode 100644 hw/can/can_sja1000.c
>   create mode 100644 hw/can/can_sja1000.h
> 
> diff --git a/default-configs/pci.mak b/default-configs/pci.mak
> index bbe11887a1..979b649fe5 100644
> --- a/default-configs/pci.mak
> +++ b/default-configs/pci.mak
> @@ -32,6 +32,7 @@ CONFIG_SERIAL=y
>   CONFIG_SERIAL_ISA=y
>   CONFIG_SERIAL_PCI=y
>   CONFIG_CAN_CORE=y
> +CONFIG_CAN_SJA1000=y
>   CONFIG_IPACK=y
>   CONFIG_WDT_IB6300ESB=y
>   CONFIG_PCI_TESTDEV=y
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index f999085f7a..3c4bf3bfc1 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -7,4 +7,5 @@ common-obj-y += can_socketcan.o
>   else
>   common-obj-y += can_host_stub.o
>   endif
> +common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>   endif
> diff --git a/hw/can/can_sja1000.c b/hw/can/can_sja1000.c
> new file mode 100644
> index 0000000000..17e5b46f07
> --- /dev/null
> +++ b/hw/can/can_sja1000.c
> @@ -0,0 +1,996 @@
> +/*
> + * CAN device - SJA1000 chip emulation for QEMU
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2017 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 "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#ifndef DEBUG_FILTER
> +#define DEBUG_FILTER 0
> +#endif /*DEBUG_FILTER*/
> +
> +static void can_sja_software_reset(CanSJA1000State *s)
> +{
> +    s->mode        &= ~0x31;
> +    s->mode        |= 0x01;
> +    s->status_pel  &= ~0x37;
> +    s->status_pel  |= 0x34;
> +
> +    s->rxbuf_start = 0x00;
> +    s->rxmsg_cnt   = 0x00;
> +    s->rx_cnt      = 0x00;
> +}
> +
> +void can_sja_hardware_reset(CanSJA1000State *s)

Is something able to reset the chip outside?

> +{
> +    /* Reset by hardware, p10 */
> +    s->mode        = 0x01;
> +    s->status_pel  = 0x3c;
> +    s->interrupt_pel = 0x00;
> +    s->clock       = 0x00;
> +    s->rxbuf_start = 0x00;
> +    s->rxmsg_cnt   = 0x00;
> +    s->rx_cnt      = 0x00;
> +
> +    s->control     = 0x01;
> +    s->status_bas  = 0x0c;
> +    s->interrupt_bas = 0x00;
> +
> +    s->irq_lower(s->irq_opaque);
> +}
> +
> +static
> +void can_sja_single_filter(struct qemu_can_filter *filter,
> +            const uint8_t *acr,  const uint8_t *amr, int extended)
> +{
> +    if (extended) {
> +        filter->can_id = (uint32_t)acr[0] << 21;
> +        filter->can_id |= (uint32_t)acr[1] << 13;
> +        filter->can_id |= (uint32_t)acr[2] << 5;
> +        filter->can_id |= (uint32_t)acr[3] >> 3;
> +        if (acr[3] & 4) {
> +            filter->can_id |= QEMU_CAN_RTR_FLAG;
> +        }
> +
> +        filter->can_mask = (uint32_t)amr[0] << 21;
> +        filter->can_mask |= (uint32_t)amr[1] << 13;
> +        filter->can_mask |= (uint32_t)amr[2] << 5;
> +        filter->can_mask |= (uint32_t)amr[3] >> 3;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK;
> +        if (!(amr[3] & 4)) {
> +            filter->can_mask |= QEMU_CAN_RTR_FLAG;
> +        }
> +    } else {
> +        filter->can_id = (uint32_t)acr[0] << 3;
> +        filter->can_id |= (uint32_t)acr[1] >> 5;
> +        if (acr[1] & 0x10) {
> +            filter->can_id |= QEMU_CAN_RTR_FLAG;
> +        }
> +
> +        filter->can_mask = (uint32_t)amr[0] << 3;
> +        filter->can_mask |= (uint32_t)amr[1] << 5;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
> +        if (!(amr[1] & 4)) {
> +            filter->can_mask |= QEMU_CAN_RTR_FLAG;
> +        }
> +    }
> +}
> +
> +static
> +void can_sja_dual_filter(struct qemu_can_filter *filter,
> +            const uint8_t *acr,  const uint8_t *amr, int extended)
> +{
> +    if (extended) {
> +        filter->can_id = (uint32_t)acr[0] << 21;
> +        filter->can_id |= (uint32_t)acr[1] << 13;
> +
> +        filter->can_mask = (uint32_t)amr[0] << 21;
> +        filter->can_mask |= (uint32_t)amr[1] << 13;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK & ~0x1fff;
> +    } else {
> +        filter->can_id = (uint32_t)acr[0] << 3;
> +        filter->can_id |= (uint32_t)acr[1] >> 5;
> +        if (acr[1] & 0x10) {
> +            filter->can_id |= QEMU_CAN_RTR_FLAG;
> +        }
> +
> +        filter->can_mask = (uint32_t)amr[0] << 3;
> +        filter->can_mask |= (uint32_t)amr[1] >> 5;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
> +        if (!(amr[1] & 0x10)) {
> +            filter->can_mask |= QEMU_CAN_RTR_FLAG;
> +        }
> +    }
> +}
> +
> +/* Details in DS-p22, what we need to do here is to test the data. */
> +static
> +int can_sja_accept_filter(CanSJA1000State *s,
> +                                 const qemu_can_frame *frame)
> +{
> +
> +    struct qemu_can_filter filter;
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        if (s->mode & (1 << 3)) { /* Single mode. */
> +            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
> +                can_sja_single_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                if (!can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 0;
> +                }
> +            } else { /* SFF */
> +                can_sja_single_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                if (!can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 0;
> +                }
> +
> +                if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
> +                    return 1;
> +                }
> +
> +                if (frame->can_dlc == 0) {
> +                    return 1;
> +                }
> +
> +                if ((frame->data[0] & ~(s->code_mask[6])) !=
> +                   (s->code_mask[2] & ~(s->code_mask[6]))) {
> +                    return 0;
> +                }
> +
> +                if (frame->can_dlc < 2) {
> +                    return 1;
> +                }
> +
> +                if ((frame->data[1] & ~(s->code_mask[7])) ==
> +                    (s->code_mask[3] & ~(s->code_mask[7]))) {
> +                    return 1;
> +                }
> +
> +                return 0;
> +            }
> +        } else { /* Dual mode */
> +            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 1;
> +                }
> +
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 2, s->code_mask + 6, 1);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 1;
> +                }
> +
> +                return 0;
> +            } else {
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    uint8_t expect;
> +                    uint8_t mask;
> +                    expect = s->code_mask[1] << 4;
> +                    expect |= s->code_mask[3] & 0x0f;
> +
> +                    mask = s->code_mask[5] << 4;
> +                    mask |= s->code_mask[7] & 0x0f;
> +                        mask = ~mask & 0xff;
> +
> +                    if ((frame->data[0] & mask) ==
> +                        (expect & mask)) {
> +                        return 1;
> +                    }
> +                }
> +
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 2, s->code_mask + 6, 0);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 1;
> +                }
> +
> +                return 0;
> +            }
> +        }
> +    }
> +
> +    return 1;
> +}
> +
> +static void can_display_msg(const qemu_can_frame *msg)
> +{
> +    int i;
> +
> +    fprintf(stderr, "%03X [%01d] -", (msg->can_id & QEMU_CAN_EFF_MASK),
> +            msg->can_dlc);
> +
> +    if (msg->can_id & QEMU_CAN_EFF_FLAG) {
> +        fprintf(stderr, "EFF ");
> +    } else {
> +        fprintf(stderr, "SFF ");
> +    }
> +    if (msg->can_id & QEMU_CAN_RTR_FLAG) {
> +        fprintf(stderr, "RTR-");
> +    } else {
> +        fprintf(stderr, "DAT-");
> +    }
> +    for (i = 0; i < msg->can_dlc; i++) {
> +        fprintf(stderr, "  %02X", msg->data[i]);
> +    }
> +    for (; i < 8; i++) {
> +        fprintf(stderr, "    ");
> +    }
> +    fflush(stdout);
> +}

I would use qemu_log instead of fprintf.

> +
> +static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame)
> +{
> +    uint8_t i;
> +
> +    frame->can_id = 0;
> +    if (buff[0] & 0x40) { /* RTR */
> +        frame->can_id = QEMU_CAN_RTR_FLAG;
> +    }
> +    frame->can_dlc = buff[0] & 0x0f;
> +
> +    if (buff[0] & 0x80) { /* Extended */
> +        frame->can_id |= QEMU_CAN_EFF_FLAG;
> +        frame->can_id |= buff[1] << 21; /* ID.28~ID.21 */
> +        frame->can_id |= buff[2] << 13; /* ID.20~ID.13 */
> +        frame->can_id |= buff[3] <<  5;
> +        frame->can_id |= buff[4] >>  3;
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            frame->data[i] = buff[5 + i];
> +        }
> +        for (; i < 8; i++) {
> +            frame->data[i] = 0;
> +        }
> +    } else {
> +        frame->can_id |= buff[1] <<  3;
> +        frame->can_id |= buff[2] >>  5;
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            frame->data[i] = buff[3 + i];
> +        }
> +        for (; i < 8; i++) {
> +            frame->data[i] = 0;
> +        }
> +    }
> +}
> +
> +
> +static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame)
> +{
> +    uint8_t i;
> +
> +    frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07);
> +    if (buff[1] & 0x10) { /* RTR */
> +        frame->can_id = QEMU_CAN_RTR_FLAG;
> +    }
> +    frame->can_dlc = buff[1] & 0x0f;
> +
> +    for (i = 0; i < frame->can_dlc; i++) {
> +        frame->data[i] = buff[2 + i];
> +    }
> +    for (; i < 8; i++) {
> +        frame->data[i] = 0;
> +    }
> +}
> +
> +
> +static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
> +{
> +    int i;
> +
> +    if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */
> +        return -1;
> +    }
> +
> +    buff[0] = 0x0f & frame->can_dlc; /* DLC */
> +    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
> +        buff[0] |= (1 << 6);
> +    }
> +    if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
> +        buff[0] |= (1 << 7);
> +        buff[1] = extract32(frame->can_id, 21, 8); /* ID.28~ID.21 */
> +        buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */
> +        buff[3] = extract32(frame->can_id, 5, 8);  /* ID.12~ID.05 */
> +        buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,x,x,x */
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            buff[5 + i] = frame->data[i];
> +        }
> +        return frame->can_dlc + 5;
> +    } else { /* SFF */
> +        buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
> +        buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,x,x,x,x,x */
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            buff[3 + i] = frame->data[i];
> +        }
> +
> +        return frame->can_dlc + 3;
> +    }
> +
> +    return -1;
> +}
> +
> +static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff)
> +{
> +    int i;
> +
> +    if ((frame->can_id & QEMU_CAN_EFF_FLAG) || /* EFF, not support for BasicMode. */
> +       (frame->can_id & QEMU_CAN_ERR_FLAG)) {  /* or Error frame, NOT support now. */
> +        return -1;
> +    }
> +
> +    buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
> +    buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,x,x,x,x,x */
> +    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
> +        buff[1] |= (1 << 4);
> +    }
> +    buff[1] |= frame->can_dlc & 0x0f;
> +    for (i = 0; i < frame->can_dlc; i++) {
> +        buff[2 + i] = frame->data[i];
> +    }
> +
> +    return frame->can_dlc + 2;
> +}
> +
> +void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
> +                       unsigned size)
> +{
> +    qemu_can_frame   frame;
> +    uint32_t         tmp;
> +    uint8_t          tmp8, count;
> +
> +
> +    DPRINTF("write 0x%02llx addr 0x%02x\n",
> +            (unsigned long long)val, (unsigned int)addr);
> +
> +    if (addr > CAN_SJA_MEM_SIZE) {
> +        return ;
> +    }
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        switch (addr) {
> +        case SJA_MOD: /* Mode register */
> +            s->mode = 0x1f & val;
> +            if ((s->mode & 0x01) && ((val & 0x01) == 0)) {
> +                /* Go to operation mode from reset mode. */
> +                if (s->mode & (1 << 3)) { /* Single mode. */
> +                    /* For EFF */
> +                    can_sja_single_filter(&s->filter[0],
> +                        s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                    /* For SFF */
> +                    can_sja_single_filter(&s->filter[1],
> +                        s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                    can_bus_client_set_filters(&s->bus_client, s->filter, 2);
> +                } else { /* Dual mode */
> +                    /* For EFF */
> +                    can_sja_dual_filter(&s->filter[0],
> +                        s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                    can_sja_dual_filter(&s->filter[1],
> +                        s->code_mask + 2, s->code_mask + 6, 1);
> +
> +                    /* For SFF */
> +                    can_sja_dual_filter(&s->filter[2],
> +                        s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                    can_sja_dual_filter(&s->filter[3],
> +                        s->code_mask + 2, s->code_mask + 6, 0);
> +
> +                    can_bus_client_set_filters(&s->bus_client, s->filter, 4);
> +                }
> +
> +                s->rxmsg_cnt = 0;
> +                s->rx_cnt = 0;
> +            }
> +            break;
> +
> +        case SJA_CMR: /* Command register. */
> +            if (0x01 & val) { /* Send transmission request. */
> +                buff2frame_pel(s->tx_buff, &frame);
> +                if (DEBUG_FILTER) {
> +                    can_display_msg(&frame);
> +                    fprintf(stderr, "\n");
> +                }
> +
> +                /*
> +                 * Clear transmission complete status,
> +                 * and Transmit Buffer Status.
> +                 * write to the backends.
> +                 */
> +                s->status_pel &= ~(3 << 2);
> +
> +                can_bus_client_send(&s->bus_client, &frame, 1);
> +                s->status_pel |= (3 << 2); /* Set transmission complete status, */
> +                                       /* and Transmit Buffer Status. */
> +                s->status_pel &= ~(1 << 5); /* Clear transmit status. */
> +                s->interrupt_pel |= 0x02;
> +                if (s->interrupt_en & 0x02) {
> +                    s->irq_raise(s->irq_opaque);
> +                }
> +            } else if (0x04 & val) { /* Release Receive Buffer */
> +                if (s->rxmsg_cnt <= 0) {
> +                    break;
> +                }
> +
> +                tmp8 = s->rx_buff[s->rxbuf_start]; count = 0;
> +                if (tmp8 & (1 << 7)) { /* EFF */
> +                    count += 2;
> +                }
> +                count += 3;
> +                if (!(tmp8 & (1 << 6))) { /* DATA */
> +                    count += (tmp8 & 0x0f);
> +                }
> +                s->rxbuf_start += count;
> +                s->rxbuf_start %= SJA_RCV_BUF_LEN;
> +
> +                s->rx_cnt -= count;
> +                s->rxmsg_cnt--;
> +                if (s->rxmsg_cnt == 0) {
> +                    s->status_pel &= ~(1 << 0);
> +                    s->interrupt_pel &= ~(1 << 0);
> +                }
> +                if ((s->interrupt_en & 0x01) && (s->interrupt_pel == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            } else if (0x08 & val) { /* Clear data overrun */
> +                s->status_pel &= ~(1 << 1);
> +                s->interrupt_pel &= ~(1 << 3);
> +                if ((s->interrupt_en & 0x80) && (s->interrupt_pel == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            }
> +            break;
> +        case SJA_SR: /* Status register */
> +        case SJA_IR: /* Interrupt register */
> +            break; /* Do nothing */
> +        case SJA_IER: /* Interrupt enable register */
> +            s->interrupt_en = val;
> +            break;
> +        case 16: /* RX frame information addr16-28. */
> +            s->status_pel |= (1 << 5); /* Set transmit status. */
> +        case 17:
> +        case 18:
> +        case 19:
> +        case 20:
> +        case 21:
> +        case 22:
> +        case 23:
> +        case 24:
> +        case 25:
> +        case 26:
> +        case 27:
> +        case 28:
> +            if (s->mode & 0x01) { /* Reset mode */
> +                if (addr < 24) {
> +                    s->code_mask[addr - 16] = val;
> +                }
> +            } else { /* Operation mode */
> +                s->tx_buff[addr - 16] = val; /* Store to TX buffer directly. */
> +            }
> +            break;
> +        case SJA_CDR:
> +            s->clock = val;
> +            break;
> +        }
> +    } else { /* Basic Mode */
> +        switch (addr) {
> +        case SJA_BCAN_CTR: /* Control register, addr 0 */
> +            if ((s->control & 0x01) && ((val & 0x01) == 0)) {
> +                /* Go to operation mode from reset mode. */
> +                s->filter[0].can_id = (s->code << 3) & (0xff << 3);
> +                tmp = (~(s->mask << 3)) & (0xff << 3);
> +                tmp |= QEMU_CAN_EFF_FLAG; /* Only Basic CAN Frame. */
> +                s->filter[0].can_mask = tmp;
> +                can_bus_client_set_filters(&s->bus_client, s->filter, 1);
> +
> +                s->rxmsg_cnt = 0;
> +                s->rx_cnt = 0;
> +            } else if (!(s->control & 0x01) && !(val & 0x01)) {
> +                can_sja_software_reset(s);
> +            }
> +
> +            s->control = 0x1f & val;
> +            break;
> +        case SJA_BCAN_CMR: /* Command register, addr 1 */
> +            if (0x01 & val) { /* Send transmission request. */
> +                buff2frame_bas(s->tx_buff, &frame);
> +                if (DEBUG_FILTER) {
> +                    can_display_msg(&frame);
> +                    fprintf(stderr, "\n");
> +                }
> +
> +                /*
> +                 * Clear transmission complete status,
> +                 * and Transmit Buffer Status.
> +                 */
> +                s->status_bas &= ~(3 << 2);
> +
> +                /* write to the backends. */
> +                can_bus_client_send(&s->bus_client, &frame, 1);
> +                s->status_bas |= (3 << 2); /* Set transmission complete status, */
> +                                       /* and Transmit Buffer Status. */
> +                s->status_bas &= ~(1 << 5); /* Clear transmit status. */
> +                s->interrupt_bas |= 0x02;
> +                if (s->control & 0x04) {
> +                    s->irq_raise(s->irq_opaque);
> +                }
> +            } else if (0x04 & val) { /* Release Receive Buffer */
> +                if (s->rxmsg_cnt <= 0) {
> +                    break;
> +                }
> +
> +                qemu_mutex_lock(&s->rx_lock);
> +                tmp8 = s->rx_buff[(s->rxbuf_start + 1) % SJA_RCV_BUF_LEN];
> +                count = 2 + (tmp8 & 0x0f);
> +
> +                if (DEBUG_FILTER) {
> +                    int i;
> +                    fprintf(stderr, "\nRelease");
> +                    for (i = 0; i < count; i++) {
> +                        fprintf(stderr, " %02X", s->rx_buff[(s->rxbuf_start + i) %
> +                                        SJA_RCV_BUF_LEN]);
> +                    }
> +                    for (; i < 11; i++) {
> +                        fprintf(stderr, "   ");
> +                    }
> +                    fprintf(stderr, "==== cnt=%d, count=%d\n",
> +                            s->rx_cnt, count);
> +                }
> +
> +                s->rxbuf_start += count;
> +                s->rxbuf_start %= SJA_RCV_BUF_LEN;
> +                s->rx_cnt -= count;
> +                s->rxmsg_cnt--;
> +                qemu_mutex_unlock(&s->rx_lock);
> +
> +                if (s->rxmsg_cnt == 0) {
> +                    s->status_bas &= ~(1 << 0);
> +                    s->interrupt_bas &= ~(1 << 0);
> +                }
> +                if ((s->control & 0x02) && (s->interrupt_bas == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            } else if (0x08 & val) { /* Clear data overrun */
> +                s->status_bas &= ~(1 << 1);
> +                s->interrupt_bas &= ~(1 << 3);
> +                if ((s->control & 0x10) && (s->interrupt_bas == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            }
> +            break;
> +        case 4:
> +            s->code = val;
> +            break;
> +        case 5:
> +            s->mask = val;
> +            break;
> +        case 10:
> +            s->status_bas |= (1 << 5); /* Set transmit status. */
> +        case 11:
> +        case 12:
> +        case 13:
> +        case 14:
> +        case 15:
> +        case 16:
> +        case 17:
> +        case 18:
> +        case 19:
> +            if ((s->control & 0x01) == 0) { /* Operation mode */
> +                s->tx_buff[addr - 10] = val; /* Store to TX buffer directly. */
> +            }
> +            break;
> +        case SJA_CDR:
> +            s->clock = val;
> +            break;
> +        }
> +    }
> +}
> +
> +uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size)
> +{
> +    uint64_t temp = 0;
> +
> +    DPRINTF("read addr 0x%x", (unsigned int)addr);
> +
> +    if (addr > CAN_SJA_MEM_SIZE) {
> +        return 0;
> +    }
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        switch (addr) {
> +        case SJA_MOD: /* Mode register, addr 0 */
> +            temp = s->mode;
> +            break;
> +        case SJA_CMR: /* Command register, addr 1 */
> +            temp = 0x00; /* Command register, cannot be read. */
> +            break;
> +        case SJA_SR: /* Status register, addr 2 */
> +            temp = s->status_pel;
> +            break;
> +        case SJA_IR: /* Interrupt register, addr 3 */
> +            temp = s->interrupt_pel;
> +            s->interrupt_pel = 0;
> +            if (s->rxmsg_cnt) {
> +                s->interrupt_pel |= (1 << 0); /* Receive interrupt. */
> +                break;
> +            }
> +            s->irq_lower(s->irq_opaque);
> +            break;
> +        case SJA_IER: /* Interrupt enable register, addr 4 */
> +            temp = s->interrupt_en;
> +            break;
> +        case 5: /* Reserved */
> +        case 6: /* Bus timing 0, hardware related, not support now. */
> +        case 7: /* Bus timing 1, hardware related, not support now. */
> +        case 8: /*
> +                 * Output control register, hardware related,
> +                 * not supported for now.
> +                 */
> +        case 9: /* Test. */
> +        case 10: /* Reserved */
> +        case 11:
> +        case 12:
> +        case 13:
> +        case 14:
> +        case 15:
> +            temp = 0x00;
> +            break;
> +
> +        case 16:
> +        case 17:
> +        case 18:
> +        case 19:
> +        case 20:
> +        case 21:
> +        case 22:
> +        case 23:
> +        case 24:
> +        case 25:
> +        case 26:
> +        case 27:
> +        case 28:
> +            if (s->mode & 0x01) { /* Reset mode */
> +                if (addr < 24) {
> +                    temp = s->code_mask[addr - 16];
> +                } else {
> +                    temp = 0x00;
> +                }
> +            } else { /* Operation mode */
> +                temp = s->rx_buff[(s->rxbuf_start + addr - 16) %
> +                       SJA_RCV_BUF_LEN];
> +            }
> +            break;
> +        case SJA_CDR:
> +            temp = s->clock;
> +            break;
> +        default:
> +            temp = 0xff;
> +        }
> +    } else { /* Basic Mode */
> +        switch (addr) {
> +        case SJA_BCAN_CTR: /* Control register, addr 0 */
> +            temp = s->control;
> +            break;
> +        case SJA_BCAN_SR: /* Status register, addr 2 */
> +            temp = s->status_bas;
> +            break;
> +        case SJA_BCAN_IR: /* Interrupt register, addr 3 */
> +            temp = s->interrupt_bas;
> +            s->interrupt_bas = 0;
> +            if (s->rxmsg_cnt) {
> +                s->interrupt_bas |= (1 << 0); /* Receive interrupt. */
> +                break;
> +            }
> +            s->irq_lower(s->irq_opaque);
> +            break;
> +        case 4:
> +            temp = s->code;
> +            break;
> +        case 5:
> +            temp = s->mask;
> +            break;
> +        case 20:
> +            if (DEBUG_FILTER) {
> +                printf("Read   ");
> +            }
> +        case 21:
> +        case 22:
> +        case 23:
> +        case 24:
> +        case 25:
> +        case 26:
> +        case 27:
> +        case 28:
> +        case 29:
> +            temp = s->rx_buff[(s->rxbuf_start + addr - 20) % SJA_RCV_BUF_LEN];
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, " %02X", (unsigned int)(temp & 0xff));
> +            }
> +            break;
> +        case 31:
> +            temp = s->clock;
> +            break;
> +        default:
> +            temp = 0xff;
> +            break;
> +        }
> +    }
> +    DPRINTF("     %d bytes of 0x%lx from addr %d\n",
> +            size, (long unsigned int)temp, (int)addr);
> +
> +    return temp;
> +}
> +
> +int can_sja_can_receive(CanBusClientState *client)
> +{
> +    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        if (s->mode & 0x01) { /* reset mode. */
> +            return 0;
> +        }
> +    } else { /* BasicCAN mode */
> +        if (s->control & 0x01) {
> +            return 0;
> +        }
> +    }
> +
> +    return 1; /* always return 1, when operation mode */
> +}
> +
> +ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,
> +                        size_t frames_cnt)
> +{
> +    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
> +    static uint8_t rcv[SJA_MSG_MAX_LEN];
> +    int i;
> +    int ret = -1;
> +    const qemu_can_frame *frame = frames;
> +
> +    if (frames_cnt <= 0) {
> +        return 0;
> +    }
> +    if (DEBUG_FILTER) {
> +        fprintf(stderr, "#################################################\n");
> +        can_display_msg(frame);
> +    }
> +
> +    qemu_mutex_lock(&s->rx_lock); /* Just do it quickly :) */
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        s->status_pel |= (1 << 4); /* the CAN controller is receiving a message */
> +
> +        if (can_sja_accept_filter(s, frame) == 0) {
> +            s->status_pel &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, "     NOT\n");
> +            }
> +            goto fail;
> +        }
> +
> +        ret = frame2buff_pel(frame, rcv);
> +        if (ret < 0) {
> +            s->status_pel &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, "     ERR\n");
> +            }
> +            goto fail; /* maybe not support now. */
> +        }
> +
> +        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
> +            s->status_pel |= (1 << 1); /* Overrun status */
> +            s->interrupt_pel |= (1 << 3);
> +            if (s->interrupt_en & (1 << 3)) { /* Overrun interrupt enable */
> +                s->irq_raise(s->irq_opaque);
> +            }
> +            s->status_pel &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, "     OVER\n");
> +            }
> +            goto fail;
> +        }
> +        s->rx_cnt += ret;
> +        s->rxmsg_cnt++;
> +        if (DEBUG_FILTER) {
> +            fprintf(stderr, "     OK\n");
> +        }
> +
> +        for (i = 0; i < ret; i++) {
> +            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
> +        }
> +        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
> +
> +        s->status_pel |= 0x01; /* Set the Receive Buffer Status. DS-p23 */
> +        s->interrupt_pel |= 0x01;
> +        s->status_pel &= ~(1 << 4);
> +        s->status_pel |= (1 << 0);
> +        if (s->interrupt_en & 0x01) { /* Receive Interrupt enable. */
> +            s->irq_raise(s->irq_opaque);
> +        }
> +    } else { /* BasicCAN mode */
> +        s->status_bas |= (1 << 4); /* the CAN controller is receiving a message */
> +
> +        ret = frame2buff_bas(frame, rcv);
> +        if (ret < 0) {
> +            s->status_bas &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, "     NOT\n");
> +            }
> +            goto fail; /* maybe not support now. */
> +        }
> +
> +        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
> +            s->status_bas |= (1 << 1); /* Overrun status */
> +            s->status_bas &= ~(1 << 4);
> +            s->interrupt_bas |= (1 << 3);
> +            if (s->control & (1 << 4)) { /* Overrun interrupt enable */
> +                s->irq_raise(s->irq_opaque);
> +            }
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, "     OVER\n");
> +            }
> +            goto fail;
> +        }
> +        s->rx_cnt += ret;
> +        s->rxmsg_cnt++;
> +
> +        if (DEBUG_FILTER) {
> +            fprintf(stderr, "     OK\n");
> +            fprintf(stderr, "RCV B ret=%2d, ptr=%2d cnt=%2d msg=%2d\n",
> +                   ret, s->rx_ptr, s->rx_cnt, s->rxmsg_cnt);
> +        }
> +
> +        for (i = 0; i < ret; i++) {
> +            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
> +        }
> +        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
> +
> +        s->status_bas |= 0x01; /* Set the Receive Buffer Status. DS-p15 */
> +        s->status_bas &= ~(1 << 4);
> +        s->interrupt_bas |= 0x01;
> +        if (s->control & 0x02) { /* Receive Interrupt enable. */
> +            s->irq_raise(s->irq_opaque);
> +        }
> +    }
> +    ret = 1;
> +fail:
> +    qemu_mutex_unlock(&s->rx_lock);
> +
> +    return ret;
> +}
> +
> +static CanBusClientInfo can_sja_bus_client_info = {
> +    .can_receive = can_sja_can_receive,
> +    .receive = can_sja_receive,
> +    .cleanup = NULL,
> +    .poll = NULL
> +};
> +
> +
> +int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus)
> +{
> +    s->bus_client.info = &can_sja_bus_client_info;
> +
> +    if (can_bus_insert_client(bus, &s->bus_client) < 0) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +void can_sja_disconnect(CanSJA1000State *s)
> +{
> +    can_bus_remove_client(&s->bus_client);
> +}
> +
> +int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
> +                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque)
> +{
> +    qemu_mutex_init(&s->rx_lock);
> +
> +    s->irq_raise = irq_raise;
> +    s->irq_lower = irq_lower;
> +    s->irq_opaque = irq_opaque;
> +
> +    s->irq_lower(s->irq_opaque);
> +
> +    can_sja_hardware_reset(s);
> +
> +    return 0;
> +}
> +
> +void can_sja_exit(CanSJA1000State *s)
> +{
> +    qemu_mutex_destroy(&s->rx_lock);
> +}
> +
> +const VMStateDescription vmstate_qemu_can_filter = {
> +    .name = "qemu_can_filter",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(can_id, qemu_can_filter),
> +        VMSTATE_UINT32(can_mask, qemu_can_filter),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +/* VMState is needed for live migration of QEMU images */
> +const VMStateDescription vmstate_can_sja = {
> +    .name = "can_sja",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mode, CanSJA1000State),
> +
> +        VMSTATE_UINT8(status_pel, CanSJA1000State),
> +        VMSTATE_UINT8(interrupt_pel, CanSJA1000State),
> +        VMSTATE_UINT8(interrupt_en, CanSJA1000State),
> +        VMSTATE_UINT8(rxmsg_cnt, CanSJA1000State),
> +        VMSTATE_UINT8(rxbuf_start, CanSJA1000State),
> +        VMSTATE_UINT8(clock, CanSJA1000State),
> +
> +        VMSTATE_BUFFER(code_mask, CanSJA1000State),
> +        VMSTATE_BUFFER(tx_buff, CanSJA1000State),
> +
> +        VMSTATE_BUFFER(rx_buff, CanSJA1000State),
> +
> +        VMSTATE_UINT32(rx_ptr, CanSJA1000State),
> +        VMSTATE_UINT32(rx_cnt, CanSJA1000State),
> +
> +        VMSTATE_UINT8(control, CanSJA1000State),
> +
> +        VMSTATE_UINT8(status_bas, CanSJA1000State),
> +        VMSTATE_UINT8(interrupt_bas, CanSJA1000State),
> +        VMSTATE_UINT8(code, CanSJA1000State),
> +        VMSTATE_UINT8(mask, CanSJA1000State),
> +
> +        VMSTATE_STRUCT_ARRAY(filter, CanSJA1000State, 4, 0,
> +                             vmstate_qemu_can_filter, qemu_can_filter),
> +
> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> diff --git a/hw/can/can_sja1000.h b/hw/can/can_sja1000.h
> new file mode 100644
> index 0000000000..0830e78456
> --- /dev/null
> +++ b/hw/can/can_sja1000.h
> @@ -0,0 +1,176 @@
> +/*
> + * CAN device - SJA1000 chip emulation for QEMU
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2017 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.
> + */
> +#ifndef HW_CAN_SJA1000_H
> +#define HW_CAN_SJA1000_H
> +
> +#include "can/can_emu.h"
> +
> +#define CAN_SJA_MEM_SIZE      128
> +
> +/* The max size for a message buffer, EFF and DLC=8, DS-p39 */
> +#define SJA_MSG_MAX_LEN       13
> +/* The receive buffer size. */
> +#define SJA_RCV_BUF_LEN       64
> +
> +//#define DEBUG_CAN
> +
> +#ifndef DEBUG_CAN
> +#define DEBUG_CAN 0
> +#endif /*DEBUG_CAN*/
> +
> +#define DPRINTF(fmt, ...) \
> +    do { \
> +        if (DEBUG_CAN) { \
> +            fprintf(stderr, "[cansja]: " fmt , ## __VA_ARGS__); \
> +        } \
> +    } while (0)

You should put DPRINTF in the C file and use qemu_log instead.

> +
> +typedef void (CanSJAIrqRaiseLower)(void *opaque);
> +
> +typedef struct CanSJA1000State {
> +    /* Some registers ... */
> +    uint8_t         mode;          /* PeliCAN, addr 0, Mode register, DS-p26 */
> +                                   /* PeliCAN, addr 1, Command register */
> +    uint8_t         status_pel;    /* PeliCAN, addr 2, Status register, p15 */
> +    uint8_t         interrupt_pel; /* PeliCAN, addr 3, Interrupt register */
> +    uint8_t         interrupt_en;  /* PeliCAN, addr 4, Interrupt Enable register */
> +    uint8_t         rxmsg_cnt;     /* PeliCAN, addr 29, RX message counter. DS-p49 */
> +    uint8_t         rxbuf_start;   /* PeliCAN, addr 30, RX buffer start address, DS-p49 */
> +    uint8_t         clock;         /* PeliCAN, addr 31, Clock Divider register, DS-p55 */
> +
> +    uint8_t         code_mask[8];  /* PeliCAN, addr 16~23 */
> +    uint8_t         tx_buff[13];   /* PeliCAN, addr 96~108, transmit buffer */
> +                                   /* BasicCAN, addr 10~19, transmit buffer */
> +
> +    uint8_t         rx_buff[SJA_RCV_BUF_LEN];  /* 32~95, 64bytes */
> +    uint32_t        rx_ptr;        /* Count by bytes. */
> +    uint32_t        rx_cnt;        /* Count by bytes. */
> +
> +    uint8_t         control;       /* BasicCAN, addr 0, Control register */
> +                                   /* BasicCAN, addr 1, Command register */
> +    uint8_t         status_bas;    /* BasicCAN, addr 2, Status register */
> +    uint8_t         interrupt_bas; /* BasicCAN, addr 3, Interrupt register */
> +    uint8_t         code;          /* BasicCAN, addr 4, Acceptance code register */
> +    uint8_t         mask;          /* BasicCAN, addr 5, Acceptance mask register */
> +
> +    qemu_can_filter filter[4];
> +
> +    QemuMutex       rx_lock;
> +    CanSJAIrqRaiseLower *irq_raise;
> +    CanSJAIrqRaiseLower *irq_lower;
> +    void            *irq_opaque;
> +    CanBusClientState bus_client;
> +} CanSJA1000State;
> +
> +/* PeliCAN mode */
> +enum SJA1000_PeliCAN_regs {
> +        SJA_MOD      = 0x00,
> +/* Command register */
> +        SJA_CMR      = 0x01,
> +/* Status register */
> +        SJA_SR       = 0x02,
> +/* Interrupt register */
> +        SJA_IR       = 0x03,
> +/* Interrupt Enable */
> +        SJA_IER      = 0x04,
> +/* Bus Timing register 0 */
> +        SJA_BTR0     = 0x06,
> +/* Bus Timing register 1 */
> +        SJA_BTR1     = 0x07,
> +/* Output Control register */
> +        SJA_OCR      = 0x08,
> +/* Arbitration Lost Capture */
> +        SJA_ALC      = 0x0b,
> +/* Error Code Capture */
> +        SJA_ECC      = 0x0c,
> +/* Error Warning Limit */
> +        SJA_EWLR     = 0x0d,
> +/* RX Error Counter */
> +        SJA_RXERR    = 0x0e,
> +/* TX Error Counter */
> +        SJA_TXERR0   = 0x0e,
> +        SJA_TXERR1   = 0x0f,
> +/* Rx Message Counter (number of msgs. in RX FIFO */
> +        SJA_RMC      = 0x1d,
> +/* Rx Buffer Start Addr. (address of current MSG) */
> +        SJA_RBSA     = 0x1e,
> +/* Transmit Buffer (write) Receive Buffer (read) Frame Information */
> +        SJA_FRM      = 0x10,
> +/* ID bytes (11 bits in 0 and 1 or 16 bits in 0,1 and 13 bits in 2,3 (extended)) */
> +        SJA_ID0      = 0x11, SJA_ID1 = 0x12,
> +/* ID cont. for extended frames */
> +        SJA_ID2      = 0x13, SJA_ID3 = 0x14,
> +/* Data start standard frame */
> +        SJA_DATS     = 0x13,
> +/* Data start extended frame */
> +        SJA_DATE     = 0x15,
> +/* Acceptance Code (4 bytes) in RESET mode */
> +        SJA_ACR0     = 0x10,
> +/* Acceptance Mask (4 bytes) in RESET mode */
> +        SJA_AMR0     = 0x14,
> +/* 4 bytes */
> +        SJA_PeliCAN_AC_LEN = 4,
> +/* Clock Divider */
> +        SJA_CDR      = 0x1f
> +};
> +
> +
> +/* PeliCAN mode */
> +enum SJA1000_BasicCAN_regs {
> +        SJA_BCAN_CTR = 0x00,
> +/* Command register */
> +        SJA_BCAN_CMR = 0x01,
> +/* Status register */
> +        SJA_BCAN_SR  = 0x02,
> +/* Interrupt register */
> +        SJA_BCAN_IR  = 0x03
> +};
> +
> +void can_sja_hardware_reset(CanSJA1000State *s);
> +
> +void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
> +                       unsigned size);
> +
> +uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size);
> +
> +int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus);
> +
> +void can_sja_disconnect(CanSJA1000State *s);
> +
> +int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
> +                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque);
> +
> +void can_sja_exit(CanSJA1000State *s);
> +
> +int can_sja_can_receive(CanBusClientState *client);
> +
> +ssize_t can_sja_receive(CanBusClientState *client,
> +                        const qemu_can_frame *frames, size_t frames_cnt);
> +
> +extern const VMStateDescription vmstate_can_sja;
> +
> +#endif
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual " pisa
@ 2018-01-12 10:34   ` KONRAD Frederic
  2018-01-14  0:02   ` Deniz Eren
  1 sibling, 0 replies; 17+ messages in thread
From: KONRAD Frederic @ 2018-01-12 10:34 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Jan Kiszka



On 01/06/2018 09:47 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Deniz Eren <deniz.eren@icloud.com>

I guess Deniz is the author of this patch?
If so I think this will requires Deniz and your Signed-off-by
line.
The same apply for the other devices.

Fred

> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>   hw/can/Makefile.objs     |   1 +
>   hw/can/can_pcm3680_pci.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 336 insertions(+)
>   create mode 100644 hw/can/can_pcm3680_pci.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index c9d07b9b16..6a328f0c3a 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -9,4 +9,5 @@ common-obj-y += can_host_stub.o
>   endif
>   common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>   common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
> +common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
>   endif
> diff --git a/hw/can/can_pcm3680_pci.c b/hw/can/can_pcm3680_pci.c
> new file mode 100644
> index 0000000000..692aab6ab8
> --- /dev/null
> +++ b/hw/can/can_pcm3680_pci.c
> @@ -0,0 +1,335 @@
> +/*
> + * PCM-3680i PCI CAN device (SJA1000 based) emulation
> + *
> + * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
> + *
> + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
> + * Jin Yang and Pavel Pisa
> + *
> + * 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 "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "pcm3680_pci"
> +
> +#define PCM3680i_PCI_DEV(obj) \
> +    OBJECT_CHECK(Pcm3680iPCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +#ifndef PCM3680i_PCI_VENDOR_ID1
> +#define PCM3680i_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */
> +#endif
> +
> +#ifndef PCM3680i_PCI_DEVICE_ID1
> +#define PCM3680i_PCI_DEVICE_ID1     0xc002
> +#endif
> +
> +#define PCM3680i_PCI_SJA_RANGE     0x200
> +
> +#define PCM3680i_PCI_BYTES_PER_SJA 0x20
> +
> +typedef struct Pcm3680iPCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    sja_io[2];
> +
> +    CanSJA1000State sja_state[2];
> +    qemu_irq        irq;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus[2];
> +    char            *host[2];
> +} Pcm3680iPCIState;
> +
> +static void pcm3680i_pci_irq_raise(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_raise(d->irq);
> +}
> +
> +static void pcm3680i_pci_irq_lower(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +pcm3680i_pci_reset(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_hardware_reset(s1);
> +    can_sja_hardware_reset(s2);
> +}
> +
> +static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
> +                                       uint64_t data, unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
> +    .read = pcm3680i_pci_sja1_io_read,
> +    .write = pcm3680i_pci_sja1_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
> +    .read = pcm3680i_pci_sja2_io_read,
> +    .write = pcm3680i_pci_sja2_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static int pcm3680i_pci_init(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus1;
> +    CanBusState *can_bus2;
> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
> +    if (can_bus1 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #1");
> +        exit(1);
> +    }
> +
> +    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
> +    if (can_bus2 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #2");
> +        exit(1);
> +    }
> +
> +    if (d->host[0] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
> +            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
> +                         d->host[0]);
> +            exit(1);
> +        }
> +    }
> +
> +    if (d->host[1] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
> +            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
> +                         d->host[1]);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s1, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +    can_sja_init(s2, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +
> +    qemu_register_reset(pcm3680i_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
> +                          d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE / 2);
> +    memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
> +                          d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE / 2);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[0]);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[1]);
> +
> +    return 0;
> +}
> +
> +static void pcm3680i_pci_exit(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_disconnect(s1);
> +    can_sja_disconnect(s2);
> +
> +    qemu_unregister_reset(pcm3680i_pci_reset, d);
> +
> +    /*
> +     * region d->sja_io is destroyed by QOM now
> +     */
> +    /* memory_region_destroy(&d->sja_io[0]); */
> +    /* memory_region_destroy(&d->sja_io[1]); */
> +
> +    can_sja_exit(s1);
> +    can_sja_exit(s2);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_pcm3680i_pci = {
> +    .name = "pcm3680i_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
> +        VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_pcm3680i_pci_reset(DeviceState *dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
> +    pcm3680i_pci_reset(d);
> +}
> +
> +static Property pcm3680i_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus1",   Pcm3680iPCIState, canbus[0]),
> +    DEFINE_PROP_STRING("canbus2",   Pcm3680iPCIState, canbus[1]),
> +    DEFINE_PROP_STRING("host1",  Pcm3680iPCIState, host[0]),
> +    DEFINE_PROP_STRING("host2",  Pcm3680iPCIState, host[1]),
> +    DEFINE_PROP_STRING("model", Pcm3680iPCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = pcm3680i_pci_init;
> +    k->exit = pcm3680i_pci_exit;
> +    k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->device_id = PCM3680i_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x000c09;
> +    k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
> +    dc->desc = "Pcm3680i PCICANx";
> +    dc->props = pcm3680i_pci_properties;
> +    dc->vmsd = &vmstate_pcm3680i_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_pcm3680i_pci_reset;
> +}
> +
> +static const TypeInfo pcm3680i_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(Pcm3680iPCIState),
> +    .class_init    = pcm3680i_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void pcm3680i_pci_register_types(void)
> +{
> +    type_register_static(&pcm3680i_pci_info);
> +}
> +
> +type_init(pcm3680i_pci_register_types)
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (8 preceding siblings ...)
  2018-01-11 11:45 ` Oleksij Rempel
@ 2018-01-12 10:43 ` KONRAD Frederic
  2018-01-13 11:21   ` Pavel Pisa
  9 siblings, 1 reply; 17+ messages in thread
From: KONRAD Frederic @ 2018-01-12 10:43 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Jan Kiszka

Hi Pavel,

On 01/06/2018 09:47 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Basic emulation of CAN bus controller and interconnection for QEMU.
> 
> Patches version 3:
> Support to connect to host SocketCAN interface has been
> separated from the core bus implementation. Only simple
> statically initialize pointer to the connection function
> is used, no QOM concept for now.
> SJA1000 message filters redone and code unified where
> possible.
> Basic documentation added.
> QEMU_ALIGNED used in definition of CAN frame structure,
> structure and defines still separated from Linux/SocketCAN
> API defined ones to allow to keep QEMU message format
> independed from host system one. Check for correspondence
> to socketcan one added.

You should add that to the title as well:

git format-patch ... --subject-prefix="PATCH V3" ...

to avoid any confusion.

You need to run the ./scripts/checkpatch.pl on your patches to
check the coding-style before submitting.

In any case really nice :)!

Thanks,
Fred

> 
> Patches version 2:
> The bus emulation and the SJA1000 chip emulation introduced
> by individual patches as suggested by Frederic Konrad.
> Simple example board to test SJA1000 as single memory-mapped BAR
> has been omitted in a new series because emulation of real
> existing boards can provide same functions now.
> Conditionalized debug printfs changed to be exposed to compiler
> syntax check as suggested in review.
> 
> The work has been started by Jin Yang in the frame of GSoC 2013 slot
> contributed by RTEMS project which has been looking for environment
> to allow develop and test CAN drivers for multiple CPU architectures.
> 
> I have menthored the project and then done substantial code cleanup
> and update to QOM. Deniz Eren then used emulation for SJA1000 base card
> driver development for other operating system and contributed
> PCM-3680I and MIOe-3680 support.
> 
> Some page about the project
> 
>    https://gitlab.fel.cvut.cz/canbus/qemu-canbus/wikis/home
> 
> FEE CTU GitLab repository with can-pci branch for 2.3, 2.4, 2.7, 2.8, 2.10 and 2.11
> version if QEMU is available there
> 
>    https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci
> 
> mirror at GitHub
> 
>    https://github.com/CTU-IIG/qemu
> 
> There are many areas for improvement and extension of the code still
> (for example freeze and migration is not implemented. CAN controllers
> use proper QOM model but bus/interconnection emulation uses simple broadcast
> connection which is required for CAN, but it is not based on QEMU bus model).
> I have tried to look into QEMU VLANs implementation but it
> does not map straightforward to CAN and I would need some help/opinion
> from more advanced developers to decide what is their right
> mapping to CAN.
> 
> CAN-FD support would be interesting requires other developers/
> companies contributions or setup of some project to allow invite
> some students and colleagues from my university into project.
> 
> But I believe that (even in its actual state) provided solution
> is great help for embedded systems developers when they can connect
> SocketCAN from one or more embedded systems running in virtual
> environment together or with Linux host SocketCAN virtual
> or real bus interfaces.
> 
> We have even tested our generic CANopen device configured
> for CANopen 401 profile for generic I/O running in the virtual
> system which can control GPIO inputs/outputs through virtual
> industrial I/O card.
> 
> Generally QEMU can be interesting setup which allows
> to test complete industrial and automotive applications
> in virtual environment even before real hardware is availabe.
> 
> Deniz Eren (2):
>    CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
>    CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
> 
> Pavel Pisa (5):
>    CAN bus simple messages transport implementation for QEMU
>    CAN bus support to connect bust to Linux host SocketCAN interface.
>    CAN bus SJA1000 chip register level emulation for QEMU
>    CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
>    QEMU CAN bus emulation documentation
> 
>   default-configs/pci.mak   |   3 +
>   docs/can.txt              |  78 ++++
>   hw/Makefile.objs          |   1 +
>   hw/can/Makefile.objs      |  14 +
>   hw/can/can_core.c         | 129 ++++++
>   hw/can/can_host_stub.c    |  36 ++
>   hw/can/can_kvaser_pci.c   | 375 +++++++++++++++++
>   hw/can/can_mioe3680_pci.c | 335 ++++++++++++++++
>   hw/can/can_pcm3680_pci.c  | 335 ++++++++++++++++
>   hw/can/can_sja1000.c      | 996 ++++++++++++++++++++++++++++++++++++++++++++++
>   hw/can/can_sja1000.h      | 176 ++++++++
>   hw/can/can_socketcan.c    | 294 ++++++++++++++
>   include/can/can_emu.h     | 143 +++++++
>   13 files changed, 2915 insertions(+)
>   create mode 100644 docs/can.txt
>   create mode 100644 hw/can/Makefile.objs
>   create mode 100644 hw/can/can_core.c
>   create mode 100644 hw/can/can_host_stub.c
>   create mode 100644 hw/can/can_kvaser_pci.c
>   create mode 100644 hw/can/can_mioe3680_pci.c
>   create mode 100644 hw/can/can_pcm3680_pci.c
>   create mode 100644 hw/can/can_sja1000.c
>   create mode 100644 hw/can/can_sja1000.h
>   create mode 100644 hw/can/can_socketcan.c
>   create mode 100644 include/can/can_emu.h
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-12 10:43 ` KONRAD Frederic
@ 2018-01-13 11:21   ` Pavel Pisa
  0 siblings, 0 replies; 17+ messages in thread
From: Pavel Pisa @ 2018-01-13 11:21 UTC (permalink / raw)
  To: KONRAD Frederic
  Cc: qemu-devel, Marek Vasut, Oliver Hartkopp, Deniz Eren,
	Oleksij Rempel, Jan Kiszka

Hello Konrad,

thanks for review.

On Friday 12 of January 2018 11:43:18 KONRAD Frederic wrote:
> You should add that to the title as well:
>
> git format-patch ... --subject-prefix="PATCH V3" ...
>
> to avoid any confusion.

OK, I add V4.

> You need to run the ./scripts/checkpatch.pl on your patches to
> check the coding-style before submitting.

I have run ./scripts/checkpatch.pl on patches but I have
ignored warnings for comments overflowing column 80,
because of better readability, same for

//#define DEBUG_CAN

which seems to be used quite often in the rest of the QEMU
code. But I (try hard) switch to the strict mode for next
version.

I follow all your comments. I have send e-mail to Deniz Eren
to provide his signed-off. I have received plain patches
from him without this line. I trust that they have been
intended to be integrated/released under GPL but
I am not sure if rules allows to add the line myself.

As for the inline can_bus_filter_match

> > +static inline
> > +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;
> > +}

> Is it really required to inline this?

I agree that it size is on upper size for inline.
My initial version has next form which would be better
to be inlined

int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id)
{
    return (can_id & filter->can_mask) == (filter->can_id & filter->can_mask);
}

but I decided then to add more SocketCAN like behavior
to can use it for CAN bus clients filters list in the future.
Function call cost is not so high today.
The function can be sometimes optimized to basic form when
it is inlined and actual masks computation eliminates
some cases, but again branch predictor should take care
about that.

> > +void can_sja_hardware_reset(CanSJA1000State *s)

> Is something able to reset the chip outside?

I have found and supported more SJA1000 based
CAN cards with reset option during my LinCAN driver
development in the past. The card have special
register or address which allows to activate
RESET pin of SJA1000. So even that reset cannot
be activated externally on currently supported cards,
I would keep that function available for future
boards emulation if there is no objection.

Best wishes,

Pavel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual " pisa
  2018-01-12 10:34   ` KONRAD Frederic
@ 2018-01-14  0:02   ` Deniz Eren
  1 sibling, 0 replies; 17+ messages in thread
From: Deniz Eren @ 2018-01-14  0:02 UTC (permalink / raw)
  To: pisa
  Cc: qemu-devel, Stefan Hajnoczi, Konrad Frederic, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel

Signed-off-by: Deniz Eren <deniz.eren@icloud.com>

I’ve tested and used this work actively at for developing driverless Straddle and AGV embedded software with QNX and Linux hosts with Advantech CAN-bus cards.

Sent from my iPhone

Deniz Eren
+61 400 307 762

> On 7 Jan 2018, at 7:47 am, pisa@cmp.felk.cvut.cz wrote:
> 
> From: Deniz Eren <deniz.eren@icloud.com>
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
> hw/can/Makefile.objs     |   1 +
> hw/can/can_pcm3680_pci.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 336 insertions(+)
> create mode 100644 hw/can/can_pcm3680_pci.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index c9d07b9b16..6a328f0c3a 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -9,4 +9,5 @@ common-obj-y += can_host_stub.o
> endif
> common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
> common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
> +common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
> endif
> diff --git a/hw/can/can_pcm3680_pci.c b/hw/can/can_pcm3680_pci.c
> new file mode 100644
> index 0000000000..692aab6ab8
> --- /dev/null
> +++ b/hw/can/can_pcm3680_pci.c
> @@ -0,0 +1,335 @@
> +/*
> + * PCM-3680i PCI CAN device (SJA1000 based) emulation
> + *
> + * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
> + *
> + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
> + * Jin Yang and Pavel Pisa
> + *
> + * 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 "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "pcm3680_pci"
> +
> +#define PCM3680i_PCI_DEV(obj) \
> +    OBJECT_CHECK(Pcm3680iPCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +#ifndef PCM3680i_PCI_VENDOR_ID1
> +#define PCM3680i_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */
> +#endif
> +
> +#ifndef PCM3680i_PCI_DEVICE_ID1
> +#define PCM3680i_PCI_DEVICE_ID1     0xc002
> +#endif
> +
> +#define PCM3680i_PCI_SJA_RANGE     0x200
> +
> +#define PCM3680i_PCI_BYTES_PER_SJA 0x20
> +
> +typedef struct Pcm3680iPCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    sja_io[2];
> +
> +    CanSJA1000State sja_state[2];
> +    qemu_irq        irq;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus[2];
> +    char            *host[2];
> +} Pcm3680iPCIState;
> +
> +static void pcm3680i_pci_irq_raise(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_raise(d->irq);
> +}
> +
> +static void pcm3680i_pci_irq_lower(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +pcm3680i_pci_reset(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_hardware_reset(s1);
> +    can_sja_hardware_reset(s2);
> +}
> +
> +static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
> +                                       uint64_t data, unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
> +    .read = pcm3680i_pci_sja1_io_read,
> +    .write = pcm3680i_pci_sja1_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
> +    .read = pcm3680i_pci_sja2_io_read,
> +    .write = pcm3680i_pci_sja2_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static int pcm3680i_pci_init(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus1;
> +    CanBusState *can_bus2;
> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
> +    if (can_bus1 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #1");
> +        exit(1);
> +    }
> +
> +    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
> +    if (can_bus2 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #2");
> +        exit(1);
> +    }
> +
> +    if (d->host[0] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
> +            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
> +                         d->host[0]);
> +            exit(1);
> +        }
> +    }
> +
> +    if (d->host[1] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
> +            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
> +                         d->host[1]);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s1, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +    can_sja_init(s2, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +
> +    qemu_register_reset(pcm3680i_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
> +                          d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE / 2);
> +    memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
> +                          d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE / 2);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[0]);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[1]);
> +
> +    return 0;
> +}
> +
> +static void pcm3680i_pci_exit(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_disconnect(s1);
> +    can_sja_disconnect(s2);
> +
> +    qemu_unregister_reset(pcm3680i_pci_reset, d);
> +
> +    /*
> +     * region d->sja_io is destroyed by QOM now
> +     */
> +    /* memory_region_destroy(&d->sja_io[0]); */
> +    /* memory_region_destroy(&d->sja_io[1]); */
> +
> +    can_sja_exit(s1);
> +    can_sja_exit(s2);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_pcm3680i_pci = {
> +    .name = "pcm3680i_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
> +        VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_pcm3680i_pci_reset(DeviceState *dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
> +    pcm3680i_pci_reset(d);
> +}
> +
> +static Property pcm3680i_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus1",   Pcm3680iPCIState, canbus[0]),
> +    DEFINE_PROP_STRING("canbus2",   Pcm3680iPCIState, canbus[1]),
> +    DEFINE_PROP_STRING("host1",  Pcm3680iPCIState, host[0]),
> +    DEFINE_PROP_STRING("host2",  Pcm3680iPCIState, host[1]),
> +    DEFINE_PROP_STRING("model", Pcm3680iPCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = pcm3680i_pci_init;
> +    k->exit = pcm3680i_pci_exit;
> +    k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->device_id = PCM3680i_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x000c09;
> +    k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
> +    dc->desc = "Pcm3680i PCICANx";
> +    dc->props = pcm3680i_pci_properties;
> +    dc->vmsd = &vmstate_pcm3680i_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_pcm3680i_pci_reset;
> +}
> +
> +static const TypeInfo pcm3680i_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(Pcm3680iPCIState),
> +    .class_init    = pcm3680i_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void pcm3680i_pci_register_types(void)
> +{
> +    type_register_static(&pcm3680i_pci_info);
> +}
> +
> +type_init(pcm3680i_pci_register_types)
> -- 
> 2.11.0
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 6/7] CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
  2018-01-06 20:47 ` [Qemu-devel] [PATCH 6/7] CAN bus MIOe-3680 " pisa
@ 2018-01-14  0:03   ` Deniz Eren
  0 siblings, 0 replies; 17+ messages in thread
From: Deniz Eren @ 2018-01-14  0:03 UTC (permalink / raw)
  To: pisa
  Cc: qemu-devel, Stefan Hajnoczi, Konrad Frederic, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel

Signed-off-by: Deniz Eren <deniz.eren@icloud.com>


Sent from my iPhone

Deniz Eren
+61 400 307 762

> On 7 Jan 2018, at 7:47 am, pisa@cmp.felk.cvut.cz wrote:
> 
> From: Deniz Eren <deniz.eren@icloud.com>
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
> hw/can/Makefile.objs      |   1 +
> hw/can/can_mioe3680_pci.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 336 insertions(+)
> create mode 100644 hw/can/can_mioe3680_pci.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index 6a328f0c3a..8fcc455800 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -10,4 +10,5 @@ endif
> common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
> common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
> common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
> +common-obj-$(CONFIG_CAN_PCI) += can_mioe3680_pci.o
> endif
> diff --git a/hw/can/can_mioe3680_pci.c b/hw/can/can_mioe3680_pci.c
> new file mode 100644
> index 0000000000..799e74a7ac
> --- /dev/null
> +++ b/hw/can/can_mioe3680_pci.c
> @@ -0,0 +1,335 @@
> +/*
> + * MIOe-3680 PCI CAN device (SJA1000 based) emulation
> + *
> + * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
> + *
> + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
> + * Jin Yang and Pavel Pisa
> + *
> + * 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 "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "mioe3680_pci"
> +
> +#define MIOe3680_PCI_DEV(obj) \
> +    OBJECT_CHECK(Mioe3680PCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +#ifndef MIOe3680_PCI_VENDOR_ID1
> +#define MIOe3680_PCI_VENDOR_ID1     0x13fe    /* the PCI device and vendor IDs */
> +#endif
> +
> +#ifndef MIOe3680_PCI_DEVICE_ID1
> +#define MIOe3680_PCI_DEVICE_ID1     0xc302
> +#endif
> +
> +#define MIOe3680_PCI_SJA_RANGE     0x800
> +
> +#define MIOe3680_PCI_BYTES_PER_SJA 0x80
> +
> +typedef struct Mioe3680PCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    sja_io[2];
> +
> +    CanSJA1000State sja_state[2];
> +    qemu_irq        irq;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus[2];
> +    char            *host[2];
> +} Mioe3680PCIState;
> +
> +static void mioe3680_pci_irq_raise(void *opaque)
> +{
> +    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
> +
> +    qemu_irq_raise(d->irq);
> +}
> +
> +static void mioe3680_pci_irq_lower(void *opaque)
> +{
> +    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
> +
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +mioe3680_pci_reset(void *opaque)
> +{
> +    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_hardware_reset(s1);
> +    can_sja_hardware_reset(s2);
> +}
> +
> +static uint64_t mioe3680_pci_sja1_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr >> 2, size);
> +}
> +
> +static void mioe3680_pci_sja1_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr >> 2, data, size);
> +}
> +
> +static uint64_t mioe3680_pci_sja2_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr >> 2, size);
> +}
> +
> +static void mioe3680_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr >> 2, data, size);
> +}
> +
> +static const MemoryRegionOps mioe3680_pci_sja1_io_ops = {
> +    .read = mioe3680_pci_sja1_io_read,
> +    .write = mioe3680_pci_sja1_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps mioe3680_pci_sja2_io_ops = {
> +    .read = mioe3680_pci_sja2_io_read,
> +    .write = mioe3680_pci_sja2_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static int mioe3680_pci_init(PCIDevice *pci_dev)
> +{
> +    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus1;
> +    CanBusState *can_bus2;
> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
> +    if (can_bus1 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #1");
> +        exit(1);
> +    }
> +
> +    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
> +    if (can_bus2 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #2");
> +        exit(1);
> +    }
> +
> +    if (d->host[0] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
> +            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
> +                         d->host[0]);
> +            exit(1);
> +        }
> +    }
> +
> +    if (d->host[1] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
> +            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
> +                         d->host[1]);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s1, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
> +    can_sja_init(s2, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
> +
> +    qemu_register_reset(mioe3680_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->sja_io[0], OBJECT(d), &mioe3680_pci_sja1_io_ops,
> +                          d, "mioe3680_pci-sja1", MIOe3680_PCI_SJA_RANGE / 2);
> +    memory_region_init_io(&d->sja_io[1], OBJECT(d), &mioe3680_pci_sja2_io_ops,
> +                          d, "mioe3680_pci-sja2", MIOe3680_PCI_SJA_RANGE / 2);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->sja_io[0]);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->sja_io[1]);
> +
> +    return 0;
> +}
> +
> +static void mioe3680_pci_exit(PCIDevice *pci_dev)
> +{
> +    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_disconnect(s1);
> +    can_sja_disconnect(s2);
> +
> +    qemu_unregister_reset(mioe3680_pci_reset, d);
> +
> +    /*
> +     * region d->sja_io is destroyed by QOM now
> +     */
> +    /* memory_region_destroy(&d->sja_io[0]); */
> +    /* memory_region_destroy(&d->sja_io[1]); */
> +
> +    can_sja_exit(s1);
> +    can_sja_exit(s2);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_mioe3680_pci = {
> +    .name = "mioe3680_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState),
> +        VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja,
> +                       CanSJA1000State),
> +        VMSTATE_STRUCT(sja_state[1], Mioe3680PCIState, 0, vmstate_can_sja,
> +                       CanSJA1000State),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_mioe3680_pci_reset(DeviceState *dev)
> +{
> +    Mioe3680PCIState *d = MIOe3680_PCI_DEV(dev);
> +    mioe3680_pci_reset(d);
> +}
> +
> +static Property mioe3680_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus1",   Mioe3680PCIState, canbus[0]),
> +    DEFINE_PROP_STRING("canbus2",   Mioe3680PCIState, canbus[1]),
> +    DEFINE_PROP_STRING("host1",  Mioe3680PCIState, host[0]),
> +    DEFINE_PROP_STRING("host2",  Mioe3680PCIState, host[1]),
> +    DEFINE_PROP_STRING("model", Mioe3680PCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = mioe3680_pci_init;
> +    k->exit = mioe3680_pci_exit;
> +    k->vendor_id = MIOe3680_PCI_VENDOR_ID1;
> +    k->device_id = MIOe3680_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x000c09;
> +    k->subsystem_vendor_id = MIOe3680_PCI_VENDOR_ID1;
> +    k->subsystem_id = MIOe3680_PCI_DEVICE_ID1;
> +    dc->desc = "Mioe3680 PCICANx";
> +    dc->props = mioe3680_pci_properties;
> +    dc->vmsd = &vmstate_mioe3680_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_mioe3680_pci_reset;
> +}
> +
> +static const TypeInfo mioe3680_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(Mioe3680PCIState),
> +    .class_init    = mioe3680_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void mioe3680_pci_register_types(void)
> +{
> +    type_register_static(&mioe3680_pci_info);
> +}
> +
> +type_init(mioe3680_pci_register_types)
> -- 
> 2.11.0
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2018-01-14  0:03 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-06 20:47 [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
2018-01-06 20:47 ` [Qemu-devel] [PATCH 1/7] CAN bus simple messages transport implementation for QEMU pisa
2018-01-12 10:07   ` KONRAD Frederic
2018-01-06 20:47 ` [Qemu-devel] [PATCH 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
2018-01-06 20:47 ` [Qemu-devel] [PATCH 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
2018-01-12 10:23   ` KONRAD Frederic
2018-01-06 20:47 ` [Qemu-devel] [PATCH 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
2018-01-06 20:47 ` [Qemu-devel] [PATCH 5/7] CAN bus PCM-3680I PCI (dual " pisa
2018-01-12 10:34   ` KONRAD Frederic
2018-01-14  0:02   ` Deniz Eren
2018-01-06 20:47 ` [Qemu-devel] [PATCH 6/7] CAN bus MIOe-3680 " pisa
2018-01-14  0:03   ` Deniz Eren
2018-01-06 20:47 ` [Qemu-devel] [PATCH 7/7] QEMU CAN bus emulation documentation pisa
2018-01-06 21:10 ` [Qemu-devel] [PATCH 0/7] CAN bus support for QEMU (SJA1000 PCI so far) no-reply
2018-01-11 11:45 ` Oleksij Rempel
2018-01-12 10:43 ` KONRAD Frederic
2018-01-13 11:21   ` Pavel Pisa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.