qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/5] CAN bus SJA1000 chip register level emulati


From: Philippe Mathieu-Daudé
Subject: Re: [Qemu-devel] [PATCH 2/5] CAN bus SJA1000 chip register level emulation for QEMU
Date: Wed, 1 Nov 2017 23:40:22 -0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0

Hi Pavel,

On 11/01/2017 10:00 PM, address@hidden wrote:
> From: Pavel Pisa <address@hidden>
> 
> 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 <address@hidden>
> ---
>  default-configs/pci.mak |   1 +
>  hw/can/Makefile.objs    |   1 +
>  hw/can/can_sja1000.c    | 973 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/can/can_sja1000.h    | 176 +++++++++
>  4 files changed, 1151 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 9afb45679f..1442f11e64 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -1,3 +1,4 @@
>  # CAN bus interfaces emulation and infrastructure
>  
>  common-obj-$(CONFIG_CAN_CORE) += can_core.o
> +common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
> diff --git a/hw/can/can_sja1000.c b/hw/can/can_sja1000.c
> new file mode 100644
> index 0000000000..1f6ae88ffc
> --- /dev/null
> +++ b/hw/can/can_sja1000.c
> @@ -0,0 +1,973 @@
> +/*
> + * CAN device - SJA1000 chip emulation for QEMU
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014 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->statusP     &= ~0x37;
> +    s->statusP     |= 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->statusP     = 0x3c;
> +    s->interruptP  = 0x00;
> +    s->clock       = 0x00;
> +    s->rxbuf_start = 0x00;
> +    s->rxmsg_cnt   = 0x00;
> +    s->rx_cnt      = 0x00;
> +
> +    s->control     = 0x01;
> +    s->statusB     = 0x0c;
> +    s->interruptB  = 0x00;
> +
> +    s->irq_lower(s->irq_opaque);
> +}
> +
> +
> +/* 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)
> +{
> +    uint8_t tmp1, tmp2;
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        if (s->mode & (1 << 3)) { /* Single mode. */
> +            if (!(frame->can_id & (1 << 31))) { /* SFF */

CAN_EFF_FLAG

> +                if (frame->can_id & (1 << 30)) { /* RTR */

CAN_RTR_FLAG

> +                    return 1;
> +                }
> +                if (frame->can_dlc == 0) {
> +                    return 1;
> +                }
> +                if (frame->can_dlc == 1) {
> +                    if ((frame->data[0] & ~(s->code_mask[6])) ==
> +                       (s->code_mask[2] & ~(s->code_mask[6]))) {
> +                        return 1;
> +                    }
> +                }
> +                if (frame->can_dlc >= 2) {
> +                    if (((frame->data[0] & ~(s->code_mask[6])) ==
> +                       (s->code_mask[2] & ~(s->code_mask[6]))) &&
> +                       ((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 & (1 << 31))) { /* SFF */

CAN_EFF_FLAG

> +                if (((s->code_mask[0] & ~s->code_mask[4]) ==
> +                    (((frame->can_id >> 3) & 0xff) & ~s->code_mask[4])) &&
> +                    (((s->code_mask[1] & ~s->code_mask[5]) & 0xe0) ==
> +                    (((frame->can_id << 5) & ~s->code_mask[5]) & 0xe0))) {
> +                    if (frame->can_dlc == 0) {
> +                        return 1;
> +                    } else {
> +                        tmp1 = ((s->code_mask[1] << 4) & 0xf0) |
> +                              (s->code_mask[2] & 0x0f);
> +                        tmp2 = ((s->code_mask[5] << 4) & 0xf0) |
> +                              (s->code_mask[6] & 0x0f);
> +                        tmp2 = ~tmp2;
> +                        if ((tmp1 & tmp2) == (frame->data[0] & tmp2)) {
> +                            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 & 0x1fffffff), 
> msg->can_dlc);

CAN_ERR_MASK

> +    if (msg->can_id & (1 << 31)) {
> +        fprintf(stderr, "EFF ");
> +    } else {
> +        fprintf(stderr, "SFF ");
> +    }
> +    if (msg->can_id & (1 << 30)) {
> +        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 buff2frameP(const uint8_t *buff, qemu_can_frame *frame)
> +{
> +    uint8_t i;
> +
> +    frame->can_id = 0;
> +    if (buff[0] & 0x40) { /* RTR */
> +        frame->can_id = 0x01 << 30;
> +    }
> +    frame->can_dlc = buff[0] & 0x0f;
> +
> +    if (buff[0] & 0x80) { /* Extended */
> +        frame->can_id |= 0x01 << 31;
> +        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] << 05;
> +        frame->can_id |= buff[4] >> 03;

octal?

> +        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] << 03;
> +        frame->can_id |= buff[2] >> 05;
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            frame->data[i] = buff[3 + i];
> +        }
> +        for (; i < 8; i++) {
> +            frame->data[i] = 0;
> +        }
> +    }
> +}
> +
> +
> +static void buff2frameB(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 = 0x01 << 30;
> +    }
> +    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 frame2buffP(const qemu_can_frame *frame, uint8_t *buff)
> +{
> +    int i, count = 0;
> +
> +    if (frame->can_id & (1 << 29)) { /* error frame, NOT support now. */

CAN_ERR_FLAG

> +        return -1;
> +    }
> +
> +    buff[count] = 0x0f & frame->can_dlc; /* DLC */
> +    if (frame->can_id & (1 << 30)) { /* RTR */
> +        buff[count] |= (1 << 6);
> +    }
> +    if (frame->can_id & (1 << 31)) { /* EFF */
> +        buff[count] |= (1 << 7);
> +        buff[++count] = (frame->can_id >> 21) & 0xff; /* ID.28~ID.21 */
> +        buff[++count] = (frame->can_id >> 13) & 0xff; /* ID.20~ID.13 */
> +        buff[++count] = (frame->can_id >> 05) & 0xff; /* ID.12~ID.05 */
> +        buff[++count] = (frame->can_id << 03) & 0xf8; /* ID.04~ID.00,x,x,x */
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            buff[++count] = frame->data[i];
> +        }
> +
> +        return count + 1;

IMHO easier to read:

           buff[count + 0] |= (1 << 7);
           buff[count + 1] = extract32(frame->can_id, 21, 8);
           buff[count + 2] = extract32(frame->can_id, 13, 8);
           buff[count + 3] = extract32(frame->can_id, 5, 8);
           buff[count + 4] = extract32(frame->can_id, 0, 5) << 3;
           for (i = 0; i < frame->can_dlc; i++) {
               buff[count + 5 + i] = frame->data[i];
           }
           return frame->can_dlc + 6;

> +    } else { /* SFF */
> +        buff[++count] = (frame->can_id >> 03) & 0xff; /* ID.10~ID.03 */
> +        buff[++count] = (frame->can_id << 05) & 0xe0; /* 
> ID.02~ID.00,x,x,x,x,x */
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            buff[++count] = frame->data[i];
> +        }
> +
> +        return count + 1;
> +    }
> +
> +    return -1;
> +}
> +
> +static int frame2buffB(const qemu_can_frame *frame, uint8_t *buff)
> +{
> +    int i, count = 0;
> +
> +    if ((frame->can_id & (1 << 31)) || /* EFF, not support for BasicMode. */
> +       (frame->can_id & (1 << 29))) {  /* or Error frame, NOT support now. */
> +        return -1;
> +    }
> +
> +
> +    buff[count++] = 0xff & (frame->can_id >> 3);
> +    buff[count] = 0xe0 & (frame->can_id << 5);
> +    if (frame->can_id & (1 << 30)) { /* RTR */
> +        buff[count] |= (1 << 4);
> +    }
> +    buff[count++] |= frame->can_dlc & 0x0f;
> +    for (i = 0; i < frame->can_dlc; i++) {
> +        buff[count++] = frame->data[i];
> +    }
> +
> +    if (DEBUG_FILTER) {
> +        fprintf(stderr, " ==2==");
> +        for (i = 0; i < count; i++) {
> +            fprintf(stderr, " %02X", buff[i]);
> +        }
> +        for (; i < 10; i++) {
> +            fprintf(stderr, "   ");
> +        }
> +    }
> +
> +    return count;
> +}
> +
> +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 */
> +                    tmp = ((s->code_mask[0] << 21) & (0xff << 21)) |
> +                          ((s->code_mask[1] << 13) & (0xff << 13)) |
> +                          ((s->code_mask[2] <<  5) & (0xff <<  5)) |
> +                          ((s->code_mask[3] >>  3) & 0x1f) |
> +                          (1 << 31);
> +                    s->filter[0].can_id = tmp;
> +
> +                    tmp = ((s->code_mask[4] << 21) & (0xff << 21)) |
> +                          ((s->code_mask[5] << 13) & (0xff << 13)) |
> +                          ((s->code_mask[6] <<  5) & (0xff <<  5)) |
> +                          ((s->code_mask[7] >>  3) & 0x1f) |
> +                          (7 << 29);
> +                    s->filter[0].can_mask = ~tmp | (1 << 31);
> +
> +                    if (s->code_mask[3] & (1 << 2)) { /* RTR */
> +                        s->filter[0].can_id |= (1 << 30);
> +                    }
> +                    if (!(s->code_mask[7] & (1 << 2))) {
> +                        s->filter[0].can_mask |= (1 << 30);
> +                    }
> +
> +                    /* For SFF */
> +                    tmp = ((s->code_mask[0] <<  3) & (0xff <<  3)) |
> +                          ((s->code_mask[1] >>  5) & 0x07);
> +                    s->filter[1].can_id = tmp;
> +
> +                    tmp = ((s->code_mask[4] <<  3) & (0xff <<  3)) |
> +                          ((s->code_mask[5] >>  5) & 0x07) |
> +                          (0xff << 11) | (0xff << 19) | (0x0f << 27);
> +                    s->filter[1].can_mask = ~tmp | (1 << 31);
> +
> +                    if (s->code_mask[1] & (1 << 4)) { /* RTR */
> +                        s->filter[1].can_id |= (1 << 30);
> +                    }
> +                    if (!(s->code_mask[5] & (1 << 4))) {
> +                        s->filter[1].can_mask |= (1 << 30);
> +                    }
> +
> +                    can_bus_client_set_filters(&s->bus_client, s->filter, 2);
> +                } else { /* Dual mode */
> +                    /* For EFF */
> +                    tmp = ((s->code_mask[0] << 21) & (0xff << 21)) |
> +                          ((s->code_mask[1] << 13) & (0xff << 13)) |
> +                          (1 << 31);
> +                    s->filter[0].can_id = tmp;
> +
> +                    tmp = ((s->code_mask[4] << 21) & (0xff << 21)) |
> +                          ((s->code_mask[5] << 13) & (0xff << 13)) |
> +                          (0xff << 5) | (0xff >> 3) |
> +                          (7 << 29);
> +                    s->filter[0].can_mask = ~tmp | (1 << 31);
> +
> +
> +                    tmp = ((s->code_mask[2] << 21) & (0xff << 21)) |
> +                          ((s->code_mask[3] << 13) & (0xff << 13)) |
> +                          (1 << 31);
> +                    s->filter[1].can_id = tmp;
> +
> +                    tmp = ((s->code_mask[6] << 21) & (0xff << 21)) |
> +                          ((s->code_mask[7] << 13) & (0xff << 13)) |
> +                          (0xff << 5) | (0xff >> 3) |
> +                          (7 << 29);
> +                    s->filter[1].can_mask = ~tmp | (1 << 31);
> +
> +                    /* For SFF */
> +                    tmp = ((s->code_mask[0] <<  3) & (0xff <<  3)) |
> +                          ((s->code_mask[1] >>  5) & 0x07);
> +                    s->filter[2].can_id = tmp;
> +
> +                    tmp = ((s->code_mask[4] <<  3) & (0xff <<  3)) |
> +                          ((s->code_mask[5] >>  5) & 0x07) |
> +                          (0xff << 11) | (0xff << 19) | (0x0f << 27);
> +                    s->filter[2].can_mask = ~tmp | (1 << 31);
> +
> +                    if (s->code_mask[1] & (1 << 4)) { /* RTR */
> +                        s->filter[2].can_id |= (1 << 30);
> +                    }
> +                    if (!(s->code_mask[5] & (1 << 4))) {
> +                        s->filter[2].can_mask |= (1 << 30);
> +                    }
> +
> +                    tmp = ((s->code_mask[2] <<  3) & (0xff <<  3)) |
> +                          ((s->code_mask[3] >>  5) & 0x07);
> +                    s->filter[3].can_id = tmp;
> +
> +                    tmp = ((s->code_mask[6] <<  3) & (0xff <<  3)) |
> +                          ((s->code_mask[7] >>  5) & 0x07) |
> +                          (0xff << 11) | (0xff << 19) | (0x0f << 27);
> +                    s->filter[3].can_mask = ~tmp | (1 << 31);
> +
> +                    if (s->code_mask[3] & (1 << 4)) { /* RTR */
> +                        s->filter[3].can_id |= (1 << 30);
> +                    }
> +                    if (!(s->code_mask[7] & (1 << 4))) {
> +                        s->filter[3].can_mask |= (1 << 30);
> +                    }
> +
> +                    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. */
> +                buff2frameP(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->statusP &= ~(3 << 2);
> +
> +                can_bus_client_send(&s->bus_client, &frame, 1);
> +                s->statusP |= (3 << 2); /* Set transmission complete status, 
> */
> +                                       /* and Transmit Buffer Status. */
> +                s->statusP &= ~(1 << 5); /* Clear transmit status. */
> +                s->interruptP |= 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->statusP &= ~(1 << 0);
> +                    s->interruptP &= ~(1 << 0);
> +                }
> +                if ((s->interrupt_en & 0x01) && (s->interruptP == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            } else if (0x08 & val) { /* Clear data overrun */
> +                s->statusP &= ~(1 << 1);
> +                s->interruptP &= ~(1 << 3);
> +                if ((s->interrupt_en & 0x80) && (s->interruptP == 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->statusP |= (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 |= (1 << 31);/* 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. */
> +                buff2frameB(s->tx_buff, &frame);
> +                if (DEBUG_FILTER) {
> +                    can_display_msg(&frame);
> +                    fprintf(stderr, "\n");
> +                }
> +
> +                /*
> +                 * Clear transmission complete status,
> +                 * and Transmit Buffer Status.
> +                 */
> +                s->statusB &= ~(3 << 2);
> +
> +                /* write to the backends. */
> +                can_bus_client_send(&s->bus_client, &frame, 1);
> +                s->statusB |= (3 << 2); /* Set transmission complete status, 
> */
> +                                       /* and Transmit Buffer Status. */
> +                s->statusB &= ~(1 << 5); /* Clear transmit status. */
> +                s->interruptB |= 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->statusB &= ~(1 << 0);
> +                    s->interruptB &= ~(1 << 0);
> +                }
> +                if ((s->control & 0x02) && (s->interruptB == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            } else if (0x08 & val) { /* Clear data overrun */
> +                s->statusB &= ~(1 << 1);
> +                s->interruptB &= ~(1 << 3);
> +                if ((s->control & 0x10) && (s->interruptB == 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->statusB |= (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;

this shouldn't happen... maybe assert() instead?

> +    }
> +
> +    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->statusP;
> +            break;
> +        case SJA_IR: /* Interrupt register, addr 3 */
> +            temp = s->interruptP;
> +            s->interruptP = 0;
> +            if (s->rxmsg_cnt) {
> +                s->interruptP |= (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->statusB;
> +            break;
> +        case SJA_BCAN_IR: /* Interrupt register, addr 3 */
> +            temp = s->interruptB;
> +            s->interruptB = 0;
> +            if (s->rxmsg_cnt) {
> +                s->interruptB |= (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->statusP |= (1 << 4); /* the CAN controller is receiving a message 
> */
> +
> +        if (can_sja_accept_filter(s, frame) == 0) {
> +            s->statusP &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                fprintf(stderr, "     NOT\n");
> +            }
> +            goto fail;
> +        }
> +
> +        ret = frame2buffP(frame, rcv);
> +        if (ret < 0) {
> +            s->statusP &= ~(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->statusP |= (1 << 1); /* Overrun status */
> +            s->interruptP |= (1 << 3);
> +            if (s->interrupt_en & (1 << 3)) { /* Overrun interrupt enable */
> +                s->irq_raise(s->irq_opaque);
> +            }
> +            s->statusP &= ~(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->statusP |= 0x01; /* Set the Receive Buffer Status. DS-p23 */
> +        s->interruptP |= 0x01;
> +        s->statusP &= ~(1 << 4);
> +        s->statusP |= (1 << 0);
> +        if (s->interrupt_en & 0x01) { /* Receive Interrupt enable. */
> +            s->irq_raise(s->irq_opaque);
> +        }
> +    } else { /* BasicCAN mode */
> +        s->statusB |= (1 << 4); /* the CAN controller is receiving a message 
> */
> +
> +        ret = frame2buffB(frame, rcv);
> +        if (ret < 0) {
> +            s->statusB &= ~(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->statusB |= (1 << 1); /* Overrun status */
> +            s->statusB &= ~(1 << 4);
> +            s->interruptB |= (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->statusB |= 0x01; /* Set the Receive Buffer Status. DS-p15 */
> +        s->statusB &= ~(1 << 4);
> +        s->interruptB |= 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(statusP, CanSJA1000State),
> +        VMSTATE_UINT8(interruptP, 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(statusB, CanSJA1000State),
> +        VMSTATE_UINT8(interruptB, 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..93fe1aa7aa
> --- /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 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         statusP;       /* PeliCAN, addr 2, Status register, p15 
> */
> +    uint8_t         interruptP;    /* 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         statusB;       /* BasicCAN, addr 2, Status register */
> +    uint8_t         interruptB;    /* 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
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]