Annotation of qemu/hw/serial.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * QEMU 16450 UART emulation
                      3:  * 
                      4:  * Copyright (c) 2003-2004 Fabrice Bellard
                      5:  * 
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include "vl.h"
                     25: 
                     26: //#define DEBUG_SERIAL
                     27: 
                     28: #define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
                     29: 
                     30: #define UART_IER_MSI   0x08    /* Enable Modem status interrupt */
                     31: #define UART_IER_RLSI  0x04    /* Enable receiver line status interrupt */
                     32: #define UART_IER_THRI  0x02    /* Enable Transmitter holding register int. */
                     33: #define UART_IER_RDI   0x01    /* Enable receiver data interrupt */
                     34: 
                     35: #define UART_IIR_NO_INT        0x01    /* No interrupts pending */
                     36: #define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
                     37: 
                     38: #define UART_IIR_MSI   0x00    /* Modem status interrupt */
                     39: #define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
                     40: #define UART_IIR_RDI   0x04    /* Receiver data interrupt */
                     41: #define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
                     42: 
                     43: /*
                     44:  * These are the definitions for the Modem Control Register
                     45:  */
                     46: #define UART_MCR_LOOP  0x10    /* Enable loopback test mode */
                     47: #define UART_MCR_OUT2  0x08    /* Out2 complement */
                     48: #define UART_MCR_OUT1  0x04    /* Out1 complement */
                     49: #define UART_MCR_RTS   0x02    /* RTS complement */
                     50: #define UART_MCR_DTR   0x01    /* DTR complement */
                     51: 
                     52: /*
                     53:  * These are the definitions for the Modem Status Register
                     54:  */
                     55: #define UART_MSR_DCD   0x80    /* Data Carrier Detect */
                     56: #define UART_MSR_RI    0x40    /* Ring Indicator */
                     57: #define UART_MSR_DSR   0x20    /* Data Set Ready */
                     58: #define UART_MSR_CTS   0x10    /* Clear to Send */
                     59: #define UART_MSR_DDCD  0x08    /* Delta DCD */
                     60: #define UART_MSR_TERI  0x04    /* Trailing edge ring indicator */
                     61: #define UART_MSR_DDSR  0x02    /* Delta DSR */
                     62: #define UART_MSR_DCTS  0x01    /* Delta CTS */
                     63: #define UART_MSR_ANY_DELTA 0x0F        /* Any of the delta bits! */
                     64: 
                     65: #define UART_LSR_TEMT  0x40    /* Transmitter empty */
                     66: #define UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
                     67: #define UART_LSR_BI    0x10    /* Break interrupt indicator */
                     68: #define UART_LSR_FE    0x08    /* Frame error indicator */
                     69: #define UART_LSR_PE    0x04    /* Parity error indicator */
                     70: #define UART_LSR_OE    0x02    /* Overrun error indicator */
                     71: #define UART_LSR_DR    0x01    /* Receiver data ready */
                     72: 
                     73: struct SerialState {
                     74:     uint8_t divider;
                     75:     uint8_t rbr; /* receive register */
                     76:     uint8_t ier;
                     77:     uint8_t iir; /* read only */
                     78:     uint8_t lcr;
                     79:     uint8_t mcr;
                     80:     uint8_t lsr; /* read only */
1.1.1.3 ! root       81:     uint8_t msr; /* read only */
1.1       root       82:     uint8_t scr;
                     83:     /* NOTE: this hidden state is necessary for tx irq generation as
                     84:        it can be reset while reading iir */
                     85:     int thr_ipending;
1.1.1.2   root       86:     SetIRQFunc *set_irq;
                     87:     void *irq_opaque;
1.1       root       88:     int irq;
                     89:     CharDriverState *chr;
1.1.1.2   root       90:     int last_break_enable;
                     91:     target_ulong base;
                     92:     int it_shift;
1.1       root       93: };
                     94: 
                     95: static void serial_update_irq(SerialState *s)
                     96: {
                     97:     if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
                     98:         s->iir = UART_IIR_RDI;
                     99:     } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
                    100:         s->iir = UART_IIR_THRI;
                    101:     } else {
                    102:         s->iir = UART_IIR_NO_INT;
                    103:     }
                    104:     if (s->iir != UART_IIR_NO_INT) {
1.1.1.2   root      105:         s->set_irq(s->irq_opaque, s->irq, 1);
1.1       root      106:     } else {
1.1.1.2   root      107:         s->set_irq(s->irq_opaque, s->irq, 0);
1.1       root      108:     }
                    109: }
                    110: 
1.1.1.2   root      111: static void serial_update_parameters(SerialState *s)
                    112: {
                    113:     int speed, parity, data_bits, stop_bits;
                    114:     QEMUSerialSetParams ssp;
                    115: 
                    116:     if (s->lcr & 0x08) {
                    117:         if (s->lcr & 0x10)
                    118:             parity = 'E';
                    119:         else
                    120:             parity = 'O';
                    121:     } else {
                    122:             parity = 'N';
                    123:     }
                    124:     if (s->lcr & 0x04) 
                    125:         stop_bits = 2;
                    126:     else
                    127:         stop_bits = 1;
                    128:     data_bits = (s->lcr & 0x03) + 5;
                    129:     if (s->divider == 0)
                    130:         return;
                    131:     speed = 115200 / s->divider;
                    132:     ssp.speed = speed;
                    133:     ssp.parity = parity;
                    134:     ssp.data_bits = data_bits;
                    135:     ssp.stop_bits = stop_bits;
                    136:     qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
                    137: #if 0
                    138:     printf("speed=%d parity=%c data=%d stop=%d\n", 
                    139:            speed, parity, data_bits, stop_bits);
                    140: #endif
                    141: }
                    142: 
1.1       root      143: static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                    144: {
                    145:     SerialState *s = opaque;
                    146:     unsigned char ch;
                    147:     
                    148:     addr &= 7;
                    149: #ifdef DEBUG_SERIAL
                    150:     printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
                    151: #endif
                    152:     switch(addr) {
                    153:     default:
                    154:     case 0:
                    155:         if (s->lcr & UART_LCR_DLAB) {
                    156:             s->divider = (s->divider & 0xff00) | val;
1.1.1.2   root      157:             serial_update_parameters(s);
1.1       root      158:         } else {
                    159:             s->thr_ipending = 0;
                    160:             s->lsr &= ~UART_LSR_THRE;
                    161:             serial_update_irq(s);
                    162:             ch = val;
                    163:             qemu_chr_write(s->chr, &ch, 1);
                    164:             s->thr_ipending = 1;
                    165:             s->lsr |= UART_LSR_THRE;
                    166:             s->lsr |= UART_LSR_TEMT;
                    167:             serial_update_irq(s);
                    168:         }
                    169:         break;
                    170:     case 1:
                    171:         if (s->lcr & UART_LCR_DLAB) {
                    172:             s->divider = (s->divider & 0x00ff) | (val << 8);
1.1.1.2   root      173:             serial_update_parameters(s);
1.1       root      174:         } else {
                    175:             s->ier = val & 0x0f;
                    176:             if (s->lsr & UART_LSR_THRE) {
                    177:                 s->thr_ipending = 1;
                    178:             }
                    179:             serial_update_irq(s);
                    180:         }
                    181:         break;
                    182:     case 2:
                    183:         break;
                    184:     case 3:
1.1.1.2   root      185:         {
                    186:             int break_enable;
                    187:             s->lcr = val;
                    188:             serial_update_parameters(s);
                    189:             break_enable = (val >> 6) & 1;
                    190:             if (break_enable != s->last_break_enable) {
                    191:                 s->last_break_enable = break_enable;
                    192:                 qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, 
                    193:                                &break_enable);
                    194:             }
                    195:         }
1.1       root      196:         break;
                    197:     case 4:
                    198:         s->mcr = val & 0x1f;
                    199:         break;
                    200:     case 5:
                    201:         break;
                    202:     case 6:
                    203:         break;
                    204:     case 7:
                    205:         s->scr = val;
                    206:         break;
                    207:     }
                    208: }
                    209: 
                    210: static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
                    211: {
                    212:     SerialState *s = opaque;
                    213:     uint32_t ret;
                    214: 
                    215:     addr &= 7;
                    216:     switch(addr) {
                    217:     default:
                    218:     case 0:
                    219:         if (s->lcr & UART_LCR_DLAB) {
                    220:             ret = s->divider & 0xff; 
                    221:         } else {
                    222:             ret = s->rbr;
                    223:             s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
                    224:             serial_update_irq(s);
                    225:         }
                    226:         break;
                    227:     case 1:
                    228:         if (s->lcr & UART_LCR_DLAB) {
                    229:             ret = (s->divider >> 8) & 0xff;
                    230:         } else {
                    231:             ret = s->ier;
                    232:         }
                    233:         break;
                    234:     case 2:
                    235:         ret = s->iir;
                    236:         /* reset THR pending bit */
                    237:         if ((ret & 0x7) == UART_IIR_THRI)
                    238:             s->thr_ipending = 0;
                    239:         serial_update_irq(s);
                    240:         break;
                    241:     case 3:
                    242:         ret = s->lcr;
                    243:         break;
                    244:     case 4:
                    245:         ret = s->mcr;
                    246:         break;
                    247:     case 5:
                    248:         ret = s->lsr;
                    249:         break;
                    250:     case 6:
                    251:         if (s->mcr & UART_MCR_LOOP) {
                    252:             /* in loopback, the modem output pins are connected to the
                    253:                inputs */
                    254:             ret = (s->mcr & 0x0c) << 4;
                    255:             ret |= (s->mcr & 0x02) << 3;
                    256:             ret |= (s->mcr & 0x01) << 5;
                    257:         } else {
                    258:             ret = s->msr;
                    259:         }
                    260:         break;
                    261:     case 7:
                    262:         ret = s->scr;
                    263:         break;
                    264:     }
                    265: #ifdef DEBUG_SERIAL
                    266:     printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
                    267: #endif
                    268:     return ret;
                    269: }
                    270: 
                    271: static int serial_can_receive(SerialState *s)
                    272: {
                    273:     return !(s->lsr & UART_LSR_DR);
                    274: }
                    275: 
                    276: static void serial_receive_byte(SerialState *s, int ch)
                    277: {
                    278:     s->rbr = ch;
                    279:     s->lsr |= UART_LSR_DR;
                    280:     serial_update_irq(s);
                    281: }
                    282: 
                    283: static void serial_receive_break(SerialState *s)
                    284: {
                    285:     s->rbr = 0;
                    286:     s->lsr |= UART_LSR_BI | UART_LSR_DR;
                    287:     serial_update_irq(s);
                    288: }
                    289: 
                    290: static int serial_can_receive1(void *opaque)
                    291: {
                    292:     SerialState *s = opaque;
                    293:     return serial_can_receive(s);
                    294: }
                    295: 
                    296: static void serial_receive1(void *opaque, const uint8_t *buf, int size)
                    297: {
                    298:     SerialState *s = opaque;
                    299:     serial_receive_byte(s, buf[0]);
                    300: }
                    301: 
                    302: static void serial_event(void *opaque, int event)
                    303: {
                    304:     SerialState *s = opaque;
                    305:     if (event == CHR_EVENT_BREAK)
                    306:         serial_receive_break(s);
                    307: }
                    308: 
1.1.1.2   root      309: static void serial_save(QEMUFile *f, void *opaque)
                    310: {
                    311:     SerialState *s = opaque;
                    312: 
                    313:     qemu_put_8s(f,&s->divider);
                    314:     qemu_put_8s(f,&s->rbr);
                    315:     qemu_put_8s(f,&s->ier);
                    316:     qemu_put_8s(f,&s->iir);
                    317:     qemu_put_8s(f,&s->lcr);
                    318:     qemu_put_8s(f,&s->mcr);
                    319:     qemu_put_8s(f,&s->lsr);
                    320:     qemu_put_8s(f,&s->msr);
                    321:     qemu_put_8s(f,&s->scr);
                    322: }
                    323: 
                    324: static int serial_load(QEMUFile *f, void *opaque, int version_id)
                    325: {
                    326:     SerialState *s = opaque;
                    327: 
                    328:     if(version_id != 1)
                    329:         return -EINVAL;
                    330: 
                    331:     qemu_get_8s(f,&s->divider);
                    332:     qemu_get_8s(f,&s->rbr);
                    333:     qemu_get_8s(f,&s->ier);
                    334:     qemu_get_8s(f,&s->iir);
                    335:     qemu_get_8s(f,&s->lcr);
                    336:     qemu_get_8s(f,&s->mcr);
                    337:     qemu_get_8s(f,&s->lsr);
                    338:     qemu_get_8s(f,&s->msr);
                    339:     qemu_get_8s(f,&s->scr);
                    340: 
                    341:     return 0;
                    342: }
                    343: 
1.1       root      344: /* If fd is zero, it means that the serial device uses the console */
1.1.1.2   root      345: SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
                    346:                          int base, int irq, CharDriverState *chr)
1.1       root      347: {
                    348:     SerialState *s;
                    349: 
                    350:     s = qemu_mallocz(sizeof(SerialState));
                    351:     if (!s)
                    352:         return NULL;
1.1.1.2   root      353:     s->set_irq = set_irq;
                    354:     s->irq_opaque = opaque;
1.1       root      355:     s->irq = irq;
                    356:     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
                    357:     s->iir = UART_IIR_NO_INT;
1.1.1.3 ! root      358:     s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
1.1       root      359: 
1.1.1.2   root      360:     register_savevm("serial", base, 1, serial_save, serial_load, s);
                    361: 
1.1       root      362:     register_ioport_write(base, 8, 1, serial_ioport_write, s);
                    363:     register_ioport_read(base, 8, 1, serial_ioport_read, s);
                    364:     s->chr = chr;
                    365:     qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
                    366:     qemu_chr_add_event_handler(chr, serial_event);
                    367:     return s;
                    368: }
1.1.1.2   root      369: 
                    370: /* Memory mapped interface */
                    371: static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
                    372: {
                    373:     SerialState *s = opaque;
                    374: 
                    375:     return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
                    376: }
                    377: 
                    378: static void serial_mm_writeb (void *opaque,
                    379:                               target_phys_addr_t addr, uint32_t value)
                    380: {
                    381:     SerialState *s = opaque;
                    382: 
                    383:     serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
                    384: }
                    385: 
                    386: static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
                    387: {
                    388:     SerialState *s = opaque;
                    389: 
                    390:     return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
                    391: }
                    392: 
                    393: static void serial_mm_writew (void *opaque,
                    394:                               target_phys_addr_t addr, uint32_t value)
                    395: {
                    396:     SerialState *s = opaque;
                    397: 
                    398:     serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
                    399: }
                    400: 
                    401: static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
                    402: {
                    403:     SerialState *s = opaque;
                    404: 
                    405:     return serial_ioport_read(s, (addr - s->base) >> s->it_shift);
                    406: }
                    407: 
                    408: static void serial_mm_writel (void *opaque,
                    409:                               target_phys_addr_t addr, uint32_t value)
                    410: {
                    411:     SerialState *s = opaque;
                    412: 
                    413:     serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
                    414: }
                    415: 
                    416: static CPUReadMemoryFunc *serial_mm_read[] = {
                    417:     &serial_mm_readb,
                    418:     &serial_mm_readw,
                    419:     &serial_mm_readl,
                    420: };
                    421: 
                    422: static CPUWriteMemoryFunc *serial_mm_write[] = {
                    423:     &serial_mm_writeb,
                    424:     &serial_mm_writew,
                    425:     &serial_mm_writel,
                    426: };
                    427: 
                    428: SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
                    429:                              target_ulong base, int it_shift,
                    430:                              int irq, CharDriverState *chr)
                    431: {
                    432:     SerialState *s;
                    433:     int s_io_memory;
                    434: 
                    435:     s = qemu_mallocz(sizeof(SerialState));
                    436:     if (!s)
                    437:         return NULL;
                    438:     s->set_irq = set_irq;
                    439:     s->irq_opaque = opaque;
                    440:     s->irq = irq;
                    441:     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
                    442:     s->iir = UART_IIR_NO_INT;
1.1.1.3 ! root      443:     s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
1.1.1.2   root      444:     s->base = base;
                    445:     s->it_shift = it_shift;
                    446: 
                    447:     register_savevm("serial", base, 1, serial_save, serial_load, s);
                    448: 
                    449:     s_io_memory = cpu_register_io_memory(0, serial_mm_read,
                    450:                                          serial_mm_write, s);
                    451:     cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
                    452:     s->chr = chr;
                    453:     qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
                    454:     qemu_chr_add_event_handler(chr, serial_event);
                    455:     return s;
                    456: }

unix.superglobalmegacorp.com