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 + -
显示快捷键?