(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/mcf_uart.c

    1: /*
    2:  * ColdFire UART emulation.
    3:  *
    4:  * Copyright (c) 2007 CodeSourcery.
    5:  *
    6:  * This code is licenced under the GPL
    7:  */
    8: #include "hw.h"
    9: #include "mcf.h"
   10: #include "qemu-char.h"
   11: 
   12: typedef struct {
   13:     uint8_t mr[2];
   14:     uint8_t sr;
   15:     uint8_t isr;
   16:     uint8_t imr;
   17:     uint8_t bg1;
   18:     uint8_t bg2;
   19:     uint8_t fifo[4];
   20:     uint8_t tb;
   21:     int current_mr;
   22:     int fifo_len;
   23:     int tx_enabled;
   24:     int rx_enabled;
   25:     qemu_irq irq;
   26:     CharDriverState *chr;
   27: } mcf_uart_state;
   28: 
   29: /* UART Status Register bits.  */
   30: #define MCF_UART_RxRDY  0x01
   31: #define MCF_UART_FFULL  0x02
   32: #define MCF_UART_TxRDY  0x04
   33: #define MCF_UART_TxEMP  0x08
   34: #define MCF_UART_OE     0x10
   35: #define MCF_UART_PE     0x20
   36: #define MCF_UART_FE     0x40
   37: #define MCF_UART_RB     0x80
   38: 
   39: /* Interrupt flags.  */
   40: #define MCF_UART_TxINT  0x01
   41: #define MCF_UART_RxINT  0x02
   42: #define MCF_UART_DBINT  0x04
   43: #define MCF_UART_COSINT 0x80
   44: 
   45: /* UMR1 flags.  */
   46: #define MCF_UART_BC0    0x01
   47: #define MCF_UART_BC1    0x02
   48: #define MCF_UART_PT     0x04
   49: #define MCF_UART_PM0    0x08
   50: #define MCF_UART_PM1    0x10
   51: #define MCF_UART_ERR    0x20
   52: #define MCF_UART_RxIRQ  0x40
   53: #define MCF_UART_RxRTS  0x80
   54: 
   55: static void mcf_uart_update(mcf_uart_state *s)
   56: {
   57:     s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
   58:     if (s->sr & MCF_UART_TxRDY)
   59:         s->isr |= MCF_UART_TxINT;
   60:     if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
   61:                   ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
   62:         s->isr |= MCF_UART_RxINT;
   63: 
   64:     qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
   65: }
   66: 
   67: uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
   68: {
   69:     mcf_uart_state *s = (mcf_uart_state *)opaque;
   70:     switch (addr & 0x3f) {
   71:     case 0x00:
   72:         return s->mr[s->current_mr];
   73:     case 0x04:
   74:         return s->sr;
   75:     case 0x0c:
   76:         {
   77:             uint8_t val;
   78:             int i;
   79: 
   80:             if (s->fifo_len == 0)
   81:                 return 0;
   82: 
   83:             val = s->fifo[0];
   84:             s->fifo_len--;
   85:             for (i = 0; i < s->fifo_len; i++)
   86:                 s->fifo[i] = s->fifo[i + 1];
   87:             s->sr &= ~MCF_UART_FFULL;
   88:             if (s->fifo_len == 0)
   89:                 s->sr &= ~MCF_UART_RxRDY;
   90:             mcf_uart_update(s);
   91:             qemu_chr_accept_input(s->chr);
   92:             return val;
   93:         }
   94:     case 0x10:
   95:         /* TODO: Implement IPCR.  */
   96:         return 0;
   97:     case 0x14:
   98:         return s->isr;
   99:     case 0x18:
  100:         return s->bg1;
  101:     case 0x1c:
  102:         return s->bg2;
  103:     default:
  104:         return 0;
  105:     }
  106: }
  107: 
  108: /* Update TxRDY flag and set data if present and enabled.  */
  109: static void mcf_uart_do_tx(mcf_uart_state *s)
  110: {
  111:     if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
  112:         if (s->chr)
  113:             qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
  114:         s->sr |= MCF_UART_TxEMP;
  115:     }
  116:     if (s->tx_enabled) {
  117:         s->sr |= MCF_UART_TxRDY;
  118:     } else {
  119:         s->sr &= ~MCF_UART_TxRDY;
  120:     }
  121: }
  122: 
  123: static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
  124: {
  125:     /* Misc command.  */
  126:     switch ((cmd >> 4) & 3) {
  127:     case 0: /* No-op.  */
  128:         break;
  129:     case 1: /* Reset mode register pointer.  */
  130:         s->current_mr = 0;
  131:         break;
  132:     case 2: /* Reset receiver.  */
  133:         s->rx_enabled = 0;
  134:         s->fifo_len = 0;
  135:         s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
  136:         break;
  137:     case 3: /* Reset transmitter.  */
  138:         s->tx_enabled = 0;
  139:         s->sr |= MCF_UART_TxEMP;
  140:         s->sr &= ~MCF_UART_TxRDY;
  141:         break;
  142:     case 4: /* Reset error status.  */
  143:         break;
  144:     case 5: /* Reset break-change interrupt.  */
  145:         s->isr &= ~MCF_UART_DBINT;
  146:         break;
  147:     case 6: /* Start break.  */
  148:     case 7: /* Stop break.  */
  149:         break;
  150:     }
  151: 
  152:     /* Transmitter command.  */
  153:     switch ((cmd >> 2) & 3) {
  154:     case 0: /* No-op.  */
  155:         break;
  156:     case 1: /* Enable.  */
  157:         s->tx_enabled = 1;
  158:         mcf_uart_do_tx(s);
  159:         break;
  160:     case 2: /* Disable.  */
  161:         s->tx_enabled = 0;
  162:         mcf_uart_do_tx(s);
  163:         break;
  164:     case 3: /* Reserved.  */
  165:         fprintf(stderr, "mcf_uart: Bad TX command\n");
  166:         break;
  167:     }
  168: 
  169:     /* Receiver command.  */
  170:     switch (cmd & 3) {
  171:     case 0: /* No-op.  */
  172:         break;
  173:     case 1: /* Enable.  */
  174:         s->rx_enabled = 1;
  175:         break;
  176:     case 2:
  177:         s->rx_enabled = 0;
  178:         break;
  179:     case 3: /* Reserved.  */
  180:         fprintf(stderr, "mcf_uart: Bad RX command\n");
  181:         break;
  182:     }
  183: }
  184: 
  185: void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
  186: {
  187:     mcf_uart_state *s = (mcf_uart_state *)opaque;
  188:     switch (addr & 0x3f) {
  189:     case 0x00:
  190:         s->mr[s->current_mr] = val;
  191:         s->current_mr = 1;
  192:         break;
  193:     case 0x04:
  194:         /* CSR is ignored.  */
  195:         break;
  196:     case 0x08: /* Command Register.  */
  197:         mcf_do_command(s, val);
  198:         break;
  199:     case 0x0c: /* Transmit Buffer.  */
  200:         s->sr &= ~MCF_UART_TxEMP;
  201:         s->tb = val;
  202:         mcf_uart_do_tx(s);
  203:         break;
  204:     case 0x10:
  205:         /* ACR is ignored.  */
  206:         break;
  207:     case 0x14:
  208:         s->imr = val;
  209:         break;
  210:     default:
  211:         break;
  212:     }
  213:     mcf_uart_update(s);
  214: }
  215: 
  216: static void mcf_uart_reset(mcf_uart_state *s)
  217: {
  218:     s->fifo_len = 0;
  219:     s->mr[0] = 0;
  220:     s->mr[1] = 0;
  221:     s->sr = MCF_UART_TxEMP;
  222:     s->tx_enabled = 0;
  223:     s->rx_enabled = 0;
  224:     s->isr = 0;
  225:     s->imr = 0;
  226: }
  227: 
  228: static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
  229: {
  230:     /* Break events overwrite the last byte if the fifo is full.  */
  231:     if (s->fifo_len == 4)
  232:         s->fifo_len--;
  233: 
  234:     s->fifo[s->fifo_len] = data;
  235:     s->fifo_len++;
  236:     s->sr |= MCF_UART_RxRDY;
  237:     if (s->fifo_len == 4)
  238:         s->sr |= MCF_UART_FFULL;
  239: 
  240:     mcf_uart_update(s);
  241: }
  242: 
  243: static void mcf_uart_event(void *opaque, int event)
  244: {
  245:     mcf_uart_state *s = (mcf_uart_state *)opaque;
  246: 
  247:     switch (event) {
  248:     case CHR_EVENT_BREAK:
  249:         s->isr |= MCF_UART_DBINT;
  250:         mcf_uart_push_byte(s, 0);
  251:         break;
  252:     default:
  253:         break;
  254:     }
  255: }
  256: 
  257: static int mcf_uart_can_receive(void *opaque)
  258: {
  259:     mcf_uart_state *s = (mcf_uart_state *)opaque;
  260: 
  261:     return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
  262: }
  263: 
  264: static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
  265: {
  266:     mcf_uart_state *s = (mcf_uart_state *)opaque;
  267: 
  268:     mcf_uart_push_byte(s, buf[0]);
  269: }
  270: 
  271: void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
  272: {
  273:     mcf_uart_state *s;
  274: 
  275:     s = qemu_mallocz(sizeof(mcf_uart_state));
  276:     s->chr = chr;
  277:     s->irq = irq;
  278:     if (chr) {
  279:         qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
  280:                               mcf_uart_event, s);
  281:     }
  282:     mcf_uart_reset(s);
  283:     return s;
  284: }
  285: 
  286: 
  287: static CPUReadMemoryFunc *mcf_uart_readfn[] = {
  288:    mcf_uart_read,
  289:    mcf_uart_read,
  290:    mcf_uart_read
  291: };
  292: 
  293: static CPUWriteMemoryFunc *mcf_uart_writefn[] = {
  294:    mcf_uart_write,
  295:    mcf_uart_write,
  296:    mcf_uart_write
  297: };
  298: 
  299: void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
  300:                       CharDriverState *chr)
  301: {
  302:     mcf_uart_state *s;
  303:     int iomemtype;
  304: 
  305:     s = mcf_uart_init(irq, chr);
  306:     iomemtype = cpu_register_io_memory(0, mcf_uart_readfn,
  307:                                        mcf_uart_writefn, s);
  308:     cpu_register_physical_memory(base, 0x40, iomemtype);
  309: }
Syntax (Markdown)