123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959 |
- /*
- * CAN device - SJA1000 chip emulation for QEMU
- *
- * 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 "qemu/log.h"
- #include "chardev/char.h"
- #include "hw/irq.h"
- #include "migration/vmstate.h"
- #include "net/can_emu.h"
- #include "can_sja1000.h"
- #ifndef DEBUG_FILTER
- #define DEBUG_FILTER 0
- #endif /*DEBUG_FILTER*/
- #ifndef DEBUG_CAN
- #define DEBUG_CAN 0
- #endif /*DEBUG_CAN*/
- #define DPRINTF(fmt, ...) \
- do { \
- if (DEBUG_CAN) { \
- qemu_log("[cansja]: " fmt , ## __VA_ARGS__); \
- } \
- } while (0)
- 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;
- qemu_irq_lower(s->irq);
- }
- 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] & 0x10)) {
- 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 char *prefix, const qemu_can_frame *msg)
- {
- int i;
- qemu_log_lock();
- qemu_log("%s%03X [%01d] %s %s",
- prefix,
- msg->can_id & QEMU_CAN_EFF_MASK,
- msg->can_dlc,
- msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
- msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
- for (i = 0; i < msg->can_dlc; i++) {
- qemu_log(" %02X", msg->data[i]);
- }
- qemu_log("\n");
- qemu_log_flush();
- qemu_log_unlock();
- }
- 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,xxx */
- 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,xxxxx */
- 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;
- /*
- * EFF, no support for BasicMode
- * No use for Error frames now,
- * they could be used in future to update SJA1000 error state
- */
- if ((frame->can_id & QEMU_CAN_EFF_FLAG) ||
- (frame->can_id & QEMU_CAN_ERR_FLAG)) {
- 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,xxxxx */
- 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;
- }
- static void can_sja_update_pel_irq(CanSJA1000State *s)
- {
- if (s->interrupt_en & s->interrupt_pel) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
- }
- static void can_sja_update_bas_irq(CanSJA1000State *s)
- {
- if ((s->control >> 1) & s->interrupt_bas) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
- }
- 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("[cansja]: Tx request " , &frame);
- }
- /*
- * 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);
- /*
- * Set transmission complete status
- * and Transmit Buffer Status.
- */
- s->status_pel |= (3 << 2);
- /* Clear transmit status. */
- s->status_pel &= ~(1 << 5);
- s->interrupt_pel |= 0x02;
- can_sja_update_pel_irq(s);
- }
- 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);
- }
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: message released from "
- "Rx FIFO 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--;
- if (s->rxmsg_cnt == 0) {
- s->status_pel &= ~(1 << 0);
- s->interrupt_pel &= ~(1 << 0);
- can_sja_update_pel_irq(s);
- }
- }
- if (0x08 & val) { /* Clear data overrun */
- s->status_pel &= ~(1 << 1);
- s->interrupt_pel &= ~(1 << 3);
- can_sja_update_pel_irq(s);
- }
- 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 ... 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("[cansja]: Tx request " , &frame);
- }
- /*
- * 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);
- /*
- * Set transmission complete status,
- * and Transmit Buffer Status.
- */
- s->status_bas |= (3 << 2);
- /* Clear transmit status. */
- s->status_bas &= ~(1 << 5);
- s->interrupt_bas |= 0x02;
- can_sja_update_bas_irq(s);
- }
- if (0x04 & val) { /* Release Receive Buffer */
- if (s->rxmsg_cnt <= 0) {
- break;
- }
- tmp8 = s->rx_buff[(s->rxbuf_start + 1) % SJA_RCV_BUF_LEN];
- count = 2 + (tmp8 & 0x0f);
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: message released from "
- "Rx FIFO 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--;
- if (s->rxmsg_cnt == 0) {
- s->status_bas &= ~(1 << 0);
- s->interrupt_bas &= ~(1 << 0);
- can_sja_update_bas_irq(s);
- }
- }
- if (0x08 & val) { /* Clear data overrun */
- s->status_bas &= ~(1 << 1);
- s->interrupt_bas &= ~(1 << 3);
- can_sja_update_bas_irq(s);
- }
- 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 ... 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%02x ...\n", (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. */
- }
- can_sja_update_pel_irq(s);
- 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 ... 15: /* Reserved */
- temp = 0x00;
- break;
- case 16 ... 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. */
- }
- can_sja_update_bas_irq(s);
- break;
- case 4:
- temp = s->code;
- break;
- case 5:
- temp = s->mask;
- break;
- case 20 ... 29:
- temp = s->rx_buff[(s->rxbuf_start + addr - 20) % SJA_RCV_BUF_LEN];
- break;
- case 31:
- temp = s->clock;
- break;
- default:
- temp = 0xff;
- break;
- }
- }
- DPRINTF("read addr 0x%02x, %d bytes, content 0x%02lx\n",
- (int)addr, size, (long unsigned int)temp);
- 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) {
- can_display_msg("[cansja]: receive ", frame);
- }
- if (s->clock & 0x80) { /* PeliCAN Mode */
- /* the CAN controller is receiving a message */
- s->status_pel |= (1 << 4);
- if (can_sja_accept_filter(s, frame) == 0) {
- s->status_pel &= ~(1 << 4);
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: filter rejects message\n");
- }
- return ret;
- }
- ret = frame2buff_pel(frame, rcv);
- if (ret < 0) {
- s->status_pel &= ~(1 << 4);
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: message store failed\n");
- }
- return ret; /* 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);
- s->status_pel &= ~(1 << 4);
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: receive FIFO overrun\n");
- }
- can_sja_update_pel_irq(s);
- return ret;
- }
- s->rx_cnt += ret;
- s->rxmsg_cnt++;
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: message stored in receive FIFO\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);
- can_sja_update_pel_irq(s);
- } else { /* BasicCAN mode */
- /* the CAN controller is receiving a message */
- s->status_bas |= (1 << 4);
- ret = frame2buff_bas(frame, rcv);
- if (ret < 0) {
- s->status_bas &= ~(1 << 4);
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: message store failed\n");
- }
- return ret; /* 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);
- can_sja_update_bas_irq(s);
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: receive FIFO overrun\n");
- }
- return ret;
- }
- s->rx_cnt += ret;
- s->rxmsg_cnt++;
- if (DEBUG_FILTER) {
- qemu_log("[cansja]: message stored\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_bas |= 0x01; /* Set the Receive Buffer Status. DS-p15 */
- s->status_bas &= ~(1 << 4);
- s->interrupt_bas |= (1 << 0);
- can_sja_update_bas_irq(s);
- }
- return 1;
- }
- static CanBusClientInfo can_sja_bus_client_info = {
- .can_receive = can_sja_can_receive,
- .receive = can_sja_receive,
- };
- int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus)
- {
- s->bus_client.info = &can_sja_bus_client_info;
- if (!bus) {
- return -EINVAL;
- }
- 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, qemu_irq irq)
- {
- s->irq = irq;
- qemu_irq_lower(s->irq);
- can_sja_hardware_reset(s);
- return 0;
- }
- 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()
- }
- };
- static int can_sja_post_load(void *opaque, int version_id)
- {
- CanSJA1000State *s = opaque;
- if (s->clock & 0x80) { /* PeliCAN Mode */
- can_sja_update_pel_irq(s);
- } else {
- can_sja_update_bas_irq(s);
- }
- return 0;
- }
- /* 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,
- .post_load = can_sja_post_load,
- .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()
- }
- };
|