serial.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 921 行 · 第 1/2 页
C
921 行
serial_update_irq(s); } } break; case 2: val = val & 0xFF; if ( s->fcr == val) break; /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */ if ( (val ^ s->fcr) & UART_FCR_FE ) val |= UART_FCR_XFR | UART_FCR_RFR; /* FIFO clear */ if ( val & UART_FCR_RFR ) { qemu_del_timer(s->fifo_timeout_timer); s->timeout_ipending=0; fifo_clear(s,RECV_FIFO); } if ( val & UART_FCR_XFR ) { fifo_clear(s,XMIT_FIFO); } if ( val & UART_FCR_FE ) { s->iir |= UART_IIR_FE; /* Set RECV_FIFO trigger Level */ switch ( val & 0xC0 ) { case UART_FCR_ITL_1: s->recv_fifo.itl = 1; break; case UART_FCR_ITL_2: s->recv_fifo.itl = 4; break; case UART_FCR_ITL_3: s->recv_fifo.itl = 8; break; case UART_FCR_ITL_4: s->recv_fifo.itl = 14; break; } } else s->iir &= ~UART_IIR_FE; /* Set fcr - or at least the bits in it that are supposed to "stick" */ s->fcr = val & 0xC9; serial_update_irq(s); break; case 3: { int break_enable; s->lcr = val; serial_update_parameters(s); break_enable = (val >> 6) & 1; if (break_enable != s->last_break_enable) { s->last_break_enable = break_enable; qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enable); } } break; case 4: { int flags; int old_mcr = s->mcr; s->mcr = val & 0x1f; if ( val & UART_MCR_LOOP ) break; if ( s->poll_msl >= 0 && old_mcr != s->mcr ) { qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); flags &= ~( TIOCM_RTS | TIOCM_DTR ); if ( val & UART_MCR_RTS ) flags |= TIOCM_RTS; if ( val & UART_MCR_DTR ) flags |= TIOCM_DTR; qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); /* Update the modem status after a one-character-send wait-time, since there may be a response from the device/computer at the other end of the serial line */ qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + s->char_transmit_time ); } } break; case 5: break; case 6: break; case 7: s->scr = val; break; }}static uint32_t serial_ioport_read(void *opaque, uint32_t addr){ SerialState *s = opaque; uint32_t ret; addr &= 7; switch(addr) { default: case 0: if (s->lcr & UART_LCR_DLAB) { ret = s->divider & 0xff; } else { if(s->fcr & UART_FCR_FE) { ret = fifo_get(s,RECV_FIFO); if ( s->recv_fifo.count == 0 ) s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); else qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4 ); s->timeout_ipending = 0; } else { ret = s->rbr; s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); } serial_update_irq(s); if (!(s->mcr & UART_MCR_LOOP)) { /* in loopback mode, don't receive any data */ qemu_chr_accept_input(s->chr); } } break; case 1: if (s->lcr & UART_LCR_DLAB) { ret = (s->divider >> 8) & 0xff; } else { ret = s->ier; } break; case 2: ret = s->iir; s->thr_ipending = 0; serial_update_irq(s); break; case 3: ret = s->lcr; break; case 4: ret = s->mcr; break; case 5: serial_get_token(); ret = s->lsr; /* Clear break interrupt */ if ( s->lsr & UART_LSR_BI ) { s->lsr &= ~UART_LSR_BI; serial_update_irq(s); } break; case 6: serial_get_token(); if (s->mcr & UART_MCR_LOOP) { /* in loopback, the modem output pins are connected to the inputs */ ret = (s->mcr & 0x0c) << 4; ret |= (s->mcr & 0x02) << 3; ret |= (s->mcr & 0x01) << 5; } else { if ( s->poll_msl >= 0 ) serial_update_msl(s); ret = s->msr; /* Clear delta bits & msr int after read, if they were set */ if ( s->msr & UART_MSR_ANY_DELTA ) { s->msr &= 0xF0; serial_update_irq(s); } } break; case 7: ret = s->scr; break; }#ifdef DEBUG_SERIAL printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);#endif return ret;}static int serial_can_receive(SerialState *s){ if(s->fcr & UART_FCR_FE) { if(s->recv_fifo.count < UART_FIFO_LENGTH) /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond, effectively overriding the ITL that the guest has set. */ return ( s->recv_fifo.count <= s->recv_fifo.itl ) ? s->recv_fifo.itl - s->recv_fifo.count : 1; else return 0; } else { return !(s->lsr & UART_LSR_DR); }}static void serial_receive_break(SerialState *s){ s->rbr = 0; s->lsr |= UART_LSR_BI | UART_LSR_DR; serial_update_irq(s);} /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */static void fifo_timeout_int (void *opaque) { SerialState *s = opaque; if ( s->recv_fifo.count ) { s->timeout_ipending = 1; serial_update_irq(s); }}static int serial_can_receive1(void *opaque){ SerialState *s = opaque; return serial_can_receive(s);}static void serial_receive1(void *opaque, const uint8_t *buf, int size){ SerialState *s = opaque; tokens_avail = TOKENS_MAX; if(s->fcr & UART_FCR_FE) { int i; for (i = 0; i < size; i++) { fifo_put(s, RECV_FIFO, buf[i]); } s->lsr |= UART_LSR_DR; /* call the timeout receive callback in 4 char transmit time */ qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4); } else { s->rbr = buf[0]; s->lsr |= UART_LSR_DR; } serial_update_irq(s);}static void serial_event(void *opaque, int event){ SerialState *s = opaque; tokens_avail = TOKENS_MAX; if (event == CHR_EVENT_BREAK) serial_receive_break(s);}static void serial_save(QEMUFile *f, void *opaque){ SerialState *s = opaque; qemu_put_be16s(f,&s->divider); qemu_put_8s(f,&s->rbr); qemu_put_8s(f,&s->ier); qemu_put_8s(f,&s->iir); qemu_put_8s(f,&s->lcr); qemu_put_8s(f,&s->mcr); qemu_put_8s(f,&s->lsr); qemu_put_8s(f,&s->msr); qemu_put_8s(f,&s->scr); qemu_put_8s(f,&s->fcr);}static int serial_load(QEMUFile *f, void *opaque, int version_id){ SerialState *s = opaque; uint8_t fcr = 0; if(version_id > 2) return -EINVAL; if (version_id >= 2) qemu_get_be16s(f, &s->divider); else s->divider = qemu_get_byte(f); qemu_get_8s(f,&s->rbr); qemu_get_8s(f,&s->ier); qemu_get_8s(f,&s->iir); qemu_get_8s(f,&s->lcr); qemu_get_8s(f,&s->mcr); qemu_get_8s(f,&s->lsr); qemu_get_8s(f,&s->msr); qemu_get_8s(f,&s->scr); if (version_id >= 2) qemu_get_8s(f,&fcr); /* Initialize fcr via setter to perform essential side-effects */ serial_ioport_write(s, 0x02, fcr); return 0;}static void serial_reset(void *opaque){ SerialState *s = opaque; s->rbr = 0; s->ier = 0; s->iir = UART_IIR_NO_INT; s->lcr = 0; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; /* Default to 9600 baud, no parity, one stop bit */ s->divider = 0x0C; s->mcr = UART_MCR_OUT2; s->scr = 0; s->tsr_retry = 0; s->char_transmit_time = ( ticks_per_sec / 9600 ) * 9; s->poll_msl = 0; fifo_clear(s,RECV_FIFO); fifo_clear(s,XMIT_FIFO); s->last_xmit_ts = qemu_get_clock(vm_clock); s->thr_ipending = 0; s->last_break_enable = 0; qemu_irq_lower(s->irq);}static void serial_init_core(SerialState *s, qemu_irq irq, int baudbase, CharDriverState *chr){ s->irq = irq; s->baudbase = baudbase; s->chr = chr; s->modem_status_poll = qemu_new_timer(vm_clock, ( QEMUTimerCB *) serial_update_msl, s); s->fifo_timeout_timer = qemu_new_timer(vm_clock, ( QEMUTimerCB *) fifo_timeout_int, s); s->transmit_timer = qemu_new_timer(vm_clock, ( QEMUTimerCB *) serial_xmit, s); qemu_register_reset(serial_reset, s); serial_reset(s);}/* If fd is zero, it means that the serial device uses the console */SerialState *serial_init(int base, qemu_irq irq, int baudbase, CharDriverState *chr){ SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; serial_init_core(s, irq, baudbase, chr); register_savevm("serial", base, 2, serial_save, serial_load, s); register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, serial_event, s); return s;}/* Memory mapped interface */uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr){ SerialState *s = opaque; return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;}void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value){ SerialState *s = opaque; serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);}uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr){ SerialState *s = opaque; uint32_t val; val = serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;#ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val);#endif return val;}void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value){ SerialState *s = opaque;#ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value);#endif serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);}uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr){ SerialState *s = opaque; uint32_t val; val = serial_ioport_read(s, (addr - s->base) >> s->it_shift);#ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val);#endif return val;}void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value){ SerialState *s = opaque;#ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value);#endif serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);}static CPUReadMemoryFunc *serial_mm_read[] = { &serial_mm_readb, &serial_mm_readw, &serial_mm_readl,};static CPUWriteMemoryFunc *serial_mm_write[] = { &serial_mm_writeb, &serial_mm_writew, &serial_mm_writel,};SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, qemu_irq irq, int baudbase, CharDriverState *chr, int ioregister){ SerialState *s; int s_io_memory; s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; s->base = base; s->it_shift = it_shift; serial_init_core(s, irq, baudbase, chr); register_savevm("serial", base, 2, serial_save, serial_load, s); if (ioregister) { s_io_memory = cpu_register_io_memory(0, serial_mm_read, serial_mm_write, s); cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); } qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, serial_event, s); serial_update_msl(s); return s;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?