static int filter_send(CharBackend *chr_out, const struct iovec *iov, int iovcnt) { int ret = 0; ssize_t size = 0; uint32_t len = 0; char *buf; size = iov_size(iov, iovcnt); if (!size) { return 0; } len = htonl(size); ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)&len, sizeof(len)); if (ret != sizeof(len)) { goto err; } buf = g_malloc(size); iov_to_buf(iov, iovcnt, 0, buf, size); ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)buf, size); g_free(buf); if (ret != size) { goto err; } return 0; err: return ret < 0 ? ret : -EIO; }
static void ccid_card_vscard_send_msg(PassthruState *s, VSCMsgType type, uint32_t reader_id, const uint8_t *payload, uint32_t length) { VSCMsgHeader scr_msg_header; scr_msg_header.type = htonl(type); scr_msg_header.reader_id = htonl(reader_id); scr_msg_header.length = htonl(length); /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader)); qemu_chr_fe_write_all(&s->cs, payload, length); }
static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg, size_t msg_len_in, size_t msg_len_out) { CharBackend *dev = &tpm->ctrl_chr; uint32_t cmd_no = cpu_to_be32(cmd); ssize_t n = sizeof(uint32_t) + msg_len_in; uint8_t *buf = NULL; int ret = -1; qemu_mutex_lock(&tpm->mutex); buf = g_alloca(n); memcpy(buf, &cmd_no, sizeof(cmd_no)); memcpy(buf + sizeof(cmd_no), msg, msg_len_in); n = qemu_chr_fe_write_all(dev, buf, n); if (n <= 0) { goto end; } if (msg_len_out != 0) { n = qemu_chr_fe_read_all(dev, msg, msg_len_out); if (n <= 0) { goto end; } } ret = 0; end: qemu_mutex_unlock(&tpm->mutex); return ret; }
static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { DigicUartState *s = opaque; unsigned char ch = value; addr >>= 2; switch (addr) { case R_TX: if (s->chr) { qemu_chr_fe_write_all(s->chr, &ch, 1); } break; case R_ST: /* * Ignore write to R_ST. * * The point is that this register is actively used * during receiving and transmitting symbols, * but we don't know the function of most of bits. * * Ignoring writes to R_ST is only a simplification * of the model. It has no perceptible side effects * for existing guests. */ break; default: qemu_log_mask(LOG_UNIMP, "digic-uart: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); } }
static void uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistUartState *s = opaque; unsigned char ch = value; trace_milkymist_uart_memory_write(addr, value); addr >>= 2; switch (addr) { case R_RXTX: qemu_chr_fe_write_all(&s->chr, &ch, 1); s->regs[R_STAT] |= STAT_TX_EVT; break; case R_DIV: case R_CTRL: case R_DBG: s->regs[addr] = value; break; case R_STAT: /* write one to clear bits */ s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT)); qemu_chr_fe_accept_input(&s->chr); break; default: error_report("milkymist_uart: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } uart_update_irq(s); }
static void uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { LM32UartState *s = opaque; unsigned char ch = value; trace_lm32_uart_memory_write(addr, value); addr >>= 2; switch (addr) { case R_RXTX: /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1); break; case R_IER: case R_LCR: case R_MCR: case R_DIV: s->regs[addr] = value; break; case R_IIR: case R_LSR: case R_MSR: error_report("lm32_uart: write access to read only register 0x" TARGET_FMT_plx, addr << 2); break; default: error_report("lm32_uart: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } uart_update_irq(s); }
static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size) { if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) { return; } qemu_chr_fe_write_all(s->chr, buf, size); }
void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) { LM32JuartState *s = LM32_JUART(d); unsigned char ch = jtx & 0xff; trace_lm32_juart_set_jtx(s->jtx); s->jtx = jtx; if (s->chr) { qemu_chr_fe_write_all(s->chr, &ch, 1); } }
/* * Triggered by SCLP's write_event_data * - write console data to character layer * returns < 0 if an error occurred */ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) { SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); if (!qemu_chr_fe_backend_connected(&scon->chr)) { /* If there's no backend, we can just say we consumed all data. */ return len; } /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ return qemu_chr_fe_write_all(&scon->chr, buf, len); }
static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, int *fds, int fd_num) { CharDriverState *chr = dev->opaque; int size = VHOST_USER_HDR_SIZE + msg->size; if (fd_num) { qemu_chr_fe_set_msgfds(chr, fds, fd_num); } return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ? 0 : -1; }
static int compare_chr_send(CompareState *s, const uint8_t *buf, uint32_t size, uint32_t vnet_hdr_len) { int ret = 0; uint32_t len = htonl(size); if (!size) { return 0; } ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); if (ret != sizeof(len)) { goto err; } if (s->vnet_hdr) { /* * We send vnet header len make other module(like filter-redirector) * know how to parse net packet correctly. */ len = htonl(vnet_hdr_len); ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); if (ret != sizeof(len)) { goto err; } } ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size); if (ret != size) { goto err; } return 0; err: return ret < 0 ? ret : -EIO; }
/* Update TxRDY flag and set data if present and enabled. */ static void mcf_uart_do_tx(mcf_uart_state *s) { if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1); s->sr |= MCF_UART_TxEMP; } if (s->tx_enabled) { s->sr |= MCF_UART_TxRDY; } else { s->sr &= ~MCF_UART_TxRDY; } }
static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr, const char *fmt, ...) { va_list ap; char buffer[1024]; size_t len; va_start(ap, fmt); len = vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); qemu_chr_fe_write_all(chr, (uint8_t *)buffer, len); if (qtest_log_fp && qtest_opened) { fprintf(qtest_log_fp, "%s", buffer); } }
/* Callback function that's called when the guest sends us data */ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, ssize_t len) { VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); ssize_t ret; if (!vcon->chr) { /* If there's no backend, we can just say we consumed all data. */ return len; } if (!virtio_serial_flow_control_enabled(port)) { ret = qemu_chr_fe_write_all(vcon->chr, buf, len); if (ret < 0) { ret = 0; } return ret; } ret = qemu_chr_fe_write(vcon->chr, buf, len); trace_virtio_console_flush_buf(port->id, len, ret); if (ret < len) { VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, vcon->port.dev.info); /* * Ideally we'd get a better error code than just -1, but * that's what the chardev interface gives us right now. If * we had a finer-grained message, like -EPIPE, we could close * this connection. */ if (ret < 0) ret = 0; if (!info->is_console) { virtio_serial_throttle_port(port, true); if (!vcon->watch) { vcon->watch = qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked, vcon); } } } return ret; }
static void grlib_apbuart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { UART *uart = opaque; unsigned char c = 0; addr &= 0xff; /* Unit registers */ switch (addr) { case DATA_OFFSET: case DATA_OFFSET + 3: /* When only one byte write */ /* Transmit when character device available and transmitter enabled */ if (qemu_chr_fe_get_driver(&uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) { c = value & 0xFF; /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&uart->chr, &c, 1); /* Generate interrupt */ if (uart->control & UART_TRANSMIT_INTERRUPT) { qemu_irq_pulse(uart->irq); } } return; case STATUS_OFFSET: /* Read Only */ return; case CONTROL_OFFSET: uart->control = value; return; case SCALER_OFFSET: /* Not supported */ return; default: break; } trace_grlib_apbuart_writel_unknown(addr, value); }
/* Called with chr_write_lock held. */ static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len) { MuxChardev *d = MUX_CHARDEV(chr); int ret; if (!d->timestamps) { ret = qemu_chr_fe_write(&d->chr, buf, len); } else { int i; ret = 0; for (i = 0; i < len; i++) { if (d->linestart) { char buf1[64]; int64_t ti; int secs; ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); if (d->timestamps_start == -1) { d->timestamps_start = ti; } ti -= d->timestamps_start; secs = ti / 1000; snprintf(buf1, sizeof(buf1), "[%02d:%02d:%02d.%03d] ", secs / 3600, (secs / 60) % 60, secs % 60, (int)(ti % 1000)); /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&d->chr, (uint8_t *)buf1, strlen(buf1)); d->linestart = 0; } ret += qemu_chr_fe_write(&d->chr, buf + i, 1); if (buf[i] == '\n') { d->linestart = 1; } } } return ret; }
static void put_buffer(GDBState *s, const uint8_t *buf, int len) { #ifdef CONFIG_USER_ONLY int ret; while (len > 0) { ret = send(s->fd, buf, len, 0); if (ret < 0) { if (errno != EINTR) return; } else { buf += ret; len -= ret; } } #else /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, buf, len); #endif }
/* most non-init callers ignore the error */ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, int *fds, int fd_num) { CharDriverState *chr = dev->opaque; int size = VHOST_USER_HDR_SIZE + msg->size; /* * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, * we just need send it once in the first time. For later such * request, we just ignore it. */ if (vhost_user_one_time_request(msg->request) && dev->vq_index != 0) { return 0; } if (fd_num) { qemu_chr_fe_set_msgfds(chr, fds, fd_num); } return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ? 0 : -1; }
static void parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) { ParallelState *s = opaque; pdebug("write addr=0x%02x val=0x%02x\n", addr, val); addr &= 7; switch(addr) { case PARA_REG_DATA: s->dataw = val; parallel_update_irq(s); break; case PARA_REG_CTR: val |= 0xc0; if ((val & PARA_CTR_INIT) == 0 ) { s->status = PARA_STS_BUSY; s->status |= PARA_STS_ACK; s->status |= PARA_STS_ONLINE; s->status |= PARA_STS_ERROR; } else if (val & PARA_CTR_SELECT) { if (val & PARA_CTR_STROBE) { s->status &= ~PARA_STS_BUSY; if ((s->control & PARA_CTR_STROBE) == 0) /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &s->dataw, 1); } else { if (s->control & PARA_CTR_INTEN) { s->irq_pending = 1; } } } parallel_update_irq(s); s->control = val; break; } }
static void juart_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { AlteraJUARTState *s = opaque; uint32_t value = val64; unsigned char c; addr >>= 2; switch (addr) { case R_DATA: if (1 /*&& (s->control & UART_TRANSMIT_ENABLE)*/) { c = value & 0xFF; /* We do not decrement the write fifo, * we "tranmsmit" instanteniously, CONTROL_WI always asserted */ s->jcontrol |= CONTROL_WI; s->jdata = c; /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &c, 1); juart_update_irq(s); } break; case R_CONTROL: /* Only RE and WE are writable */ value &= CONTROL_WMASK; s->jcontrol &= ~(CONTROL_WMASK); s->jcontrol |= value; /* Writing 1 to AC clears it to 0 */ if (value & CONTROL_AC) { s->jcontrol &= ~CONTROL_AC; } juart_update_irq(s); break; } }
static void chr_read(void *opaque, const uint8_t *buf, int size) { SCLPConsoleLM *scon = opaque; assert(size == 1); if (*buf == '\r' || *buf == '\n') { scon->event.event_pending = true; sclp_service_interrupt(0); return; } if (scon->length == SIZE_CONSOLE_BUFFER) { /* Eat the character, but still process CR and LF. */ return; } scon->buf[scon->length] = *buf; scon->length += 1; if (scon->echo) { /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&scon->chr, buf, size); } }
static void ser_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { ETRAXSerial *s = opaque; uint32_t value = val64; unsigned char ch = val64; D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, value)); addr >>= 2; switch (addr) { case RW_DOUT: /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(s->chr, &ch, 1); s->regs[R_INTR] |= 3; s->pending_tx = 1; s->regs[addr] = value; break; case RW_ACK_INTR: if (s->pending_tx) { value &= ~1; s->pending_tx = 0; D(qemu_log("fixedup value=%x r_intr=%x\n", value, s->regs[R_INTR])); } s->regs[addr] = value; s->regs[R_INTR] &= ~value; D(printf("r_intr=%x\n", s->regs[R_INTR])); break; default: s->regs[addr] = value; break; } ser_update_irq(s); }
static void usb_serial_handle_data(USBDevice *dev, USBPacket *p) { USBSerialState *s = (USBSerialState *)dev; uint8_t devep = p->ep->nr; struct iovec *iov; uint8_t header[2]; int i, first_len, len; switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) goto fail; for (i = 0; i < p->iov.niov; i++) { iov = p->iov.iov + i; /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(s->cs, iov->iov_base, iov->iov_len); } p->actual_length = p->iov.size; break; case USB_TOKEN_IN: if (devep != 1) goto fail; first_len = RECV_BUF - s->recv_ptr; len = p->iov.size; if (len <= 2) { p->status = USB_RET_NAK; break; } header[0] = usb_get_modem_lines(s) | 1; /* We do not have the uart details */ /* handle serial break */ if (s->event_trigger && s->event_trigger & FTDI_BI) { s->event_trigger &= ~FTDI_BI; header[1] = FTDI_BI; usb_packet_copy(p, header, 2); break; } else { header[1] = 0; } len -= 2; if (len > s->recv_used) len = s->recv_used; if (!len) { p->status = USB_RET_NAK; break; } if (first_len > len) first_len = len; usb_packet_copy(p, header, 2); usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len); if (len > first_len) usb_packet_copy(p, s->recv_buf, len - first_len); s->recv_used -= len; s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; break; default: DPRINTF("Bad token\n"); fail: p->status = USB_RET_STALL; break; } }
static void chr_read(void *opaque, const uint8_t *buf, int size) { CharDriverState *chr = opaque; VhostUserMsg msg; uint8_t *p = (uint8_t *) &msg; int fd; if (size != VHOST_USER_HDR_SIZE) { g_test_message("Wrong message size received %d\n", size); return; } g_mutex_lock(data_mutex); memcpy(p, buf, VHOST_USER_HDR_SIZE); if (msg.size) { p += VHOST_USER_HDR_SIZE; qemu_chr_fe_read_all(chr, p, msg.size); } switch (msg.request) { case VHOST_USER_GET_FEATURES: /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.u64); msg.u64 = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_GET_VRING_BASE: /* send back vring base to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.state); msg.state.num = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_SET_MEM_TABLE: /* received the mem table */ memcpy(&memory, &msg.memory, sizeof(msg.memory)); fds_num = qemu_chr_fe_get_msgfds(chr, fds, sizeof(fds) / sizeof(int)); /* signal the test that it can continue */ g_cond_signal(data_cond); break; case VHOST_USER_SET_VRING_KICK: case VHOST_USER_SET_VRING_CALL: /* consume the fd */ qemu_chr_fe_get_msgfds(chr, &fd, 1); /* * This is a non-blocking eventfd. * The receive function forces it to be blocking, * so revert it back to non-blocking. */ qemu_set_nonblock(fd); break; default: break; } g_mutex_unlock(data_mutex); }
static void chr_read(void *opaque, const uint8_t *buf, int size) { TestServer *s = opaque; CharBackend *chr = &s->chr; VhostUserMsg msg; uint8_t *p = (uint8_t *) &msg; int fd = -1; if (s->test_fail) { qemu_chr_fe_disconnect(chr); /* now switch to non-failure */ s->test_fail = false; } if (size != VHOST_USER_HDR_SIZE) { g_test_message("Wrong message size received %d", size); return; } g_mutex_lock(&s->data_mutex); memcpy(p, buf, VHOST_USER_HDR_SIZE); if (msg.size) { p += VHOST_USER_HDR_SIZE; size = qemu_chr_fe_read_all(chr, p, msg.size); if (size != msg.size) { g_test_message("Wrong message size received %d != %d", size, msg.size); return; } } switch (msg.request) { case VHOST_USER_GET_FEATURES: /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL | 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; if (s->queues > 1) { msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ; } if (s->test_flags >= TEST_FLAGS_BAD) { msg.payload.u64 = 0; s->test_flags = TEST_FLAGS_END; } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_SET_FEATURES: g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL); if (s->test_flags == TEST_FLAGS_DISCONNECT) { qemu_chr_fe_disconnect(chr); s->test_flags = TEST_FLAGS_BAD; } break; case VHOST_USER_GET_PROTOCOL_FEATURES: /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD; msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN; if (s->queues > 1) { msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ; } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_GET_VRING_BASE: /* send back vring base to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.state); msg.payload.state.num = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); assert(msg.payload.state.index < s->queues * 2); s->rings &= ~(0x1ULL << msg.payload.state.index); g_cond_broadcast(&s->data_cond); break; case VHOST_USER_SET_MEM_TABLE: /* received the mem table */ memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory)); s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds)); /* signal the test that it can continue */ g_cond_broadcast(&s->data_cond); break; case VHOST_USER_SET_VRING_KICK: case VHOST_USER_SET_VRING_CALL: /* consume the fd */ qemu_chr_fe_get_msgfds(chr, &fd, 1); /* * This is a non-blocking eventfd. * The receive function forces it to be blocking, * so revert it back to non-blocking. */ qemu_set_nonblock(fd); break; case VHOST_USER_SET_LOG_BASE: if (s->log_fd != -1) { close(s->log_fd); s->log_fd = -1; } qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1); msg.flags |= VHOST_USER_REPLY_MASK; msg.size = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE); g_cond_broadcast(&s->data_cond); break; case VHOST_USER_SET_VRING_BASE: assert(msg.payload.state.index < s->queues * 2); s->rings |= 0x1ULL << msg.payload.state.index; g_cond_broadcast(&s->data_cond); break; case VHOST_USER_GET_QUEUE_NUM: msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = s->queues; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; default: break; } g_mutex_unlock(&s->data_mutex); }
static void sh_serial_write(void *opaque, hwaddr offs, uint64_t val, unsigned size) { sh_serial_state *s = opaque; unsigned char ch; #ifdef DEBUG_SERIAL printf("sh_serial: write offs=0x%02x val=0x%02x\n", offs, val); #endif switch(offs) { case 0x00: /* SMR */ s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); return; case 0x04: /* BRR */ s->brr = val; return; case 0x08: /* SCR */ /* TODO : For SH7751, SCIF mask should be 0xfb. */ s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); if (!(val & (1 << 5))) s->flags |= SH_SERIAL_FLAG_TEND; if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { qemu_set_irq(s->txi, val & (1 << 7)); } if (!(val & (1 << 6))) { qemu_set_irq(s->rxi, 0); } return; case 0x0c: /* FTDR / TDR */ if (qemu_chr_fe_backend_connected(&s->chr)) { ch = val; /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1); } s->dr = val; s->flags &= ~SH_SERIAL_FLAG_TDE; return; #if 0 case 0x14: /* FRDR / RDR */ ret = 0; break; #endif } if (s->feat & SH_SERIAL_FEAT_SCIF) { switch(offs) { case 0x10: /* FSR */ if (!(val & (1 << 6))) s->flags &= ~SH_SERIAL_FLAG_TEND; if (!(val & (1 << 5))) s->flags &= ~SH_SERIAL_FLAG_TDE; if (!(val & (1 << 4))) s->flags &= ~SH_SERIAL_FLAG_BRK; if (!(val & (1 << 1))) s->flags &= ~SH_SERIAL_FLAG_RDF; if (!(val & (1 << 0))) s->flags &= ~SH_SERIAL_FLAG_DR; if (!(val & (1 << 1)) || !(val & (1 << 0))) { if (s->rxi) { qemu_set_irq(s->rxi, 0); } } return; case 0x18: /* FCR */ s->fcr = val; switch ((val >> 6) & 3) { case 0: s->rtrg = 1; break; case 1: s->rtrg = 4; break; case 2: s->rtrg = 8; break; case 3: s->rtrg = 14; break; } if (val & (1 << 1)) { sh_serial_clear_fifo(s); s->sr &= ~(1 << 1); } return; case 0x20: /* SPTR */ s->sptr = val & 0xf3; return; case 0x24: /* LSR */ return; } } else { switch(offs) {