/* Input on VTTY */ static void mv64460_sdma_vtty_input(vtty_t *vtty) { struct mv64460_data *d = vtty->priv_data; struct sdma_channel *chan = &d->sdma[vtty->user_arg]; u_char c; c = vtty_get_char(vtty); mv64460_sdma_handle_rxqueue(d,chan,&c,1); }
void *dev_pic32_uart_access (cpu_mips_t * cpu, struct vdevice *dev, m_uint32_t offset, u_int op_size, u_int op_type, m_reg_t * data, m_uint8_t * has_set_value) { struct pic32_uart_data *d = dev->priv_data; unsigned newval; if (offset >= UART_REG_SIZE) { *data = 0; return NULL; } if (op_type == MTS_READ) { /* * Reading UART registers. */ switch (offset) { case PIC32_U1RXREG & 0xff: /* Receive data */ *data = vtty_get_char (d->vtty); if (vtty_is_char_avail (d->vtty)) { d->sta |= PIC32_USTA_URXDA; } else { d->sta &= ~PIC32_USTA_URXDA; d->vm->clear_irq (d->vm, d->irq + IRQ_RX); } break; case PIC32_U1BRG & 0xff: /* Baud rate */ *data = d->brg; break; case PIC32_U1MODE & 0xff: /* Mode */ *data = d->mode; break; case PIC32_U1STA & 0xff: /* Status and control */ d->sta |= PIC32_USTA_RIDLE | /* Receiver is idle */ PIC32_USTA_TRMT; /* Transmit shift register is empty */ if (vtty_is_char_avail (d->vtty)) d->sta |= PIC32_USTA_URXDA; *data = d->sta; #if 0 printf ("<%x>", d->sta); fflush (stdout); #endif break; case PIC32_U1TXREG & 0xff: /* Transmit */ case PIC32_U1MODECLR & 0xff: case PIC32_U1MODESET & 0xff: case PIC32_U1MODEINV & 0xff: case PIC32_U1STACLR & 0xff: case PIC32_U1STASET & 0xff: case PIC32_U1STAINV & 0xff: case PIC32_U1BRGCLR & 0xff: case PIC32_U1BRGSET & 0xff: case PIC32_U1BRGINV & 0xff: *data = 0; break; default: ASSERT (0, "reading unknown uart offset %x\n", offset); } *has_set_value = TRUE; #if 0 printf ("--- uart: read %02x -> %08x\n", offset, *data); fflush (stdout); #endif } else { /* * Writing UART registers. */ #if 0 printf ("--- uart: write %02x := %08x\n", offset, *data); fflush (stdout); #endif switch (offset) { case PIC32_U1TXREG & 0xff: /* Transmit */ /* Skip ^M. */ if ((char) (*data) != '\r') vtty_put_char (d->vtty, (char) (*data)); if ((d->mode & PIC32_UMODE_ON) && (d->sta & PIC32_USTA_UTXEN) && (d->output == 0)) { /* * yajin. * * In order to put the next data more quickly, * just set irq not waiting for * host_alarm_handler to set irq. Sorry uart, * too much work for you. * * Sometimes, linux kernel prints "serial8250: * too much work for irq9" if we print large * data on screen. Please patch the kernel. * comment "printk(KERN_ERR "serial8250: too * much work for " "irq%d\n", irq);" qemu has * some question. * http://lkml.org/lkml/2008/1/12/135 * http://kerneltrap.org/mailarchive/linux-ker * nel/2008/2/7/769924 * * If jit is used in future, we may not need to * set irq here because simulation is quick * enough. Then we have no "too much work for * irq9" problem. */ d->output = TRUE; d->vm->set_irq (d->vm, d->irq + IRQ_TX); } break; case PIC32_U1MODE & 0xff: /* Mode */ newval = *data; write_mode: d->mode = newval; if (!(d->mode & PIC32_UMODE_ON)) { d->vm->clear_irq (d->vm, d->irq + IRQ_RX); d->vm->clear_irq (d->vm, d->irq + IRQ_TX); d->sta &= ~PIC32_USTA_URXDA; d->sta &= ~(PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | PIC32_USTA_UTXBF); d->sta |= PIC32_USTA_RIDLE | PIC32_USTA_TRMT; } break; case PIC32_U1MODECLR & 0xff: newval = d->mode & ~*data; goto write_mode; case PIC32_U1MODESET & 0xff: newval = d->mode | *data; goto write_mode; case PIC32_U1MODEINV & 0xff: newval = d->mode ^ *data; goto write_mode; case PIC32_U1STA & 0xff: /* Status and control */ newval = *data; write_sta: d->sta &= PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF; d->sta |= newval & ~(PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR | PIC32_USTA_RIDLE | PIC32_USTA_TRMT | PIC32_USTA_UTXBF); if (!(d->sta & PIC32_USTA_URXEN)) { d->vm->clear_irq (d->vm, d->irq + IRQ_RX); d->sta &= ~(PIC32_USTA_URXDA | PIC32_USTA_FERR | PIC32_USTA_PERR); } if (!(d->sta & PIC32_USTA_UTXEN)) { d->vm->clear_irq (d->vm, d->irq + IRQ_TX); d->sta &= ~PIC32_USTA_UTXBF; d->sta |= PIC32_USTA_TRMT; } break; case PIC32_U1STACLR & 0xff: newval = d->sta & ~*data; goto write_sta; case PIC32_U1STASET & 0xff: newval = d->sta | *data; goto write_sta; case PIC32_U1STAINV & 0xff: newval = d->sta ^ *data; goto write_sta; case PIC32_U1BRG & 0xff: /* Baud rate */ newval = *data; write_brg: d->brg = newval; break; case PIC32_U1BRGCLR & 0xff: newval = d->brg & ~*data; goto write_brg; case PIC32_U1BRGSET & 0xff: newval = d->brg | *data; goto write_brg; case PIC32_U1BRGINV & 0xff: newval = d->brg ^ *data; goto write_brg; case PIC32_U1RXREG & 0xff: /* Receive */ /* Ignore */ break; default: ASSERT (0, "writing unknown uart offset %x\n", offset); } *has_set_value = TRUE; } return NULL; }
/* * dev_ns16552_access() */ void *dev_ns16552_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset, u_int op_size,u_int op_type,m_uint64_t *data) { struct ns16552_data *d = dev->priv_data; int channel = 0; u_char odata; if (op_type == MTS_READ) *data = 0; #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,"NS16552","read from 0x%x, pc=0x%llx\n", offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,"NS16552","write to 0x%x, value=0x%llx, pc=0x%llx\n", offset,*data,cpu_get_pc(cpu)); } #endif offset >>= d->reg_div; if (offset >= 0x08) channel = 1; // From the NS16552V datasheet, the following is known about the registers // Bit 4 is channel // Value 0 Receive or transmit buffer // Value 1 Interrupt enable // Value 2 Interrupt identification (READ), FIFO Config (Write) // Value 3 Line Control (Appears in IOS) // 0x1 - Word Length Selector bit 0 // 0x2 - Word Length Selector bit 1 // 0x4 - Num stop bits // 0x8 - Parity Enable // 0x16 - Parity even // 0x32 - Stick Parity // 0x64 - Set Break // 0x128 - Division Latch // Value 4 Modem Control (Appears in IOS) // Value 5 Line status // Value 6 Modem Status // Value 7 Scratch switch(offset) { /* Receiver Buffer Reg. (RBR) / Transmitting Holding Reg. (THR) */ case 0x00: case 0x08: if (d->div_latch == 0) { if (op_type == MTS_WRITE) { vtty_put_char(d->channel[channel].vtty,(char)*data); if (d->channel[channel].ier & IER_ETXRDY) vm_set_irq(d->vm,d->irq); d->channel[channel].output = TRUE; } else *data = vtty_get_char(d->channel[channel].vtty); } else { if (op_type == MTS_WRITE) d->baud_divisor = ((*data) & 0x00ff) | (d->baud_divisor & 0xff00); } break; /* Interrupt Enable Register (IER) */ case 0x01: case 0x09: if (d->div_latch == 0) { if (op_type == MTS_READ) { *data = d->channel[channel].ier; } else { d->channel[channel].ier = *data & 0xFF; if ((*data & 0x02) == 0) { /* transmit holding register */ d->channel[channel].vtty->managed_flush = TRUE; vtty_flush(d->channel[channel].vtty); } } } else { if (op_type == MTS_WRITE) d->baud_divisor = (((*data) & 0xff)<<8)|(d->baud_divisor & 0xff); } break; /* Interrupt Ident Register (IIR) */ case 0x02: case 0x0A: if (d->div_latch == 0) { vm_clear_irq(d->vm,d->irq); if (op_type == MTS_READ) { odata = IIR_NPENDING; if (vtty_is_char_avail(d->channel[channel].vtty)) { odata = IIR_RXRDY; } else { if (d->channel[channel].output) { odata = IIR_TXRDY; d->channel[channel].output = 0; } } *data = odata; } } break; case 0x03: case 0x0B: if (op_type == MTS_READ) { *data = d->line_control_reg; } else { d->line_control_reg = (uint)*data; uint bits = 5; __maybe_unused char *stop = "1"; __maybe_unused char *parity = "no "; __maybe_unused char *parityeven = "odd"; if (*data & LCR_WRL0) bits+=1; if (*data & LCR_WRL1) bits+=2; if (*data & LCR_NUMSTOP) { if ( bits >= 6) { stop = "2"; } else { stop = "1.5"; } } if (*data & LCR_PARITYON) parity=""; //Parity on if (*data & LCR_PARITYEV) parityeven="even"; // DIV LATCH changes the behavior of 0x0,0x1,and 0x2 if (*data & LCR_DIVLATCH) { d->div_latch = 1; } else { __maybe_unused uint baud; d->div_latch = 0; // 1200 divisor was 192 // 9600 divisor was 24 // 19200 divisor was 12 // Suggests a crystal of 3686400 hz if (d->baud_divisor > 0) { baud = 3686400 / (d->baud_divisor * 16); } else { baud = 0; } } } break; case 0x04: case 0x0C: if (op_type != MTS_READ) { __maybe_unused char *f1 = ""; __maybe_unused char *f2 = ""; __maybe_unused char *f3 = ""; __maybe_unused char *f4 = ""; __maybe_unused char *f5 = ""; if (*data & MCR_DTR) f1 = "DTR "; if (*data & MCR_RTS) f2 = "RTS "; if (*data & MCR_OUT1) f3 = "OUT1 "; if (*data & MCR_OUT2) f4 = "OUT2 "; if (*data & MCR_LOOP) f5 = "LOOP "; } break; /* Line Status Register (LSR) */ case 0x05: case 0x0D: if (op_type == MTS_READ) { odata = 0; if (vtty_is_char_avail(d->channel[channel].vtty)) odata |= LSR_RXRDY; odata |= LSR_TXRDY|LSR_TXEMPTY; *data = odata; } break; #if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"NS16552","read from addr 0x%x, pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu, "NS16552","write to addr 0x%x, value=0x%llx, " "pc=0x%llx (size=%u)\n", offset,*data,cpu_get_pc(cpu),op_size); } #endif } return NULL; }