Annotation of qemu/hw/slavio_serial.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU Sparc SLAVIO serial port emulation
        !             3:  * 
        !             4:  * Copyright (c) 2003-2005 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: /* debug serial */
        !            26: //#define DEBUG_SERIAL
        !            27: 
        !            28: /* debug keyboard */
        !            29: //#define DEBUG_KBD
        !            30: 
        !            31: /* debug mouse */
        !            32: //#define DEBUG_MOUSE
        !            33: 
        !            34: /*
        !            35:  * This is the serial port, mouse and keyboard part of chip STP2001
        !            36:  * (Slave I/O), also produced as NCR89C105. See
        !            37:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
        !            38:  * 
        !            39:  * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
        !            40:  * mouse and keyboard ports don't implement all functions and they are
        !            41:  * only asynchronous. There is no DMA.
        !            42:  *
        !            43:  */
        !            44: 
        !            45: #ifdef DEBUG_SERIAL
        !            46: #define SER_DPRINTF(fmt, args...) \
        !            47: do { printf("SER: " fmt , ##args); } while (0)
        !            48: #else
        !            49: #define SER_DPRINTF(fmt, args...)
        !            50: #endif
        !            51: #ifdef DEBUG_KBD
        !            52: #define KBD_DPRINTF(fmt, args...) \
        !            53: do { printf("KBD: " fmt , ##args); } while (0)
        !            54: #else
        !            55: #define KBD_DPRINTF(fmt, args...)
        !            56: #endif
        !            57: #ifdef DEBUG_MOUSE
        !            58: #define MS_DPRINTF(fmt, args...) \
        !            59: do { printf("SER: " fmt , ##args); } while (0)
        !            60: #else
        !            61: #define MS_DPRINTF(fmt, args...)
        !            62: #endif
        !            63: 
        !            64: typedef enum {
        !            65:     chn_a, chn_b,
        !            66: } chn_id_t;
        !            67: 
        !            68: typedef enum {
        !            69:     ser, kbd, mouse,
        !            70: } chn_type_t;
        !            71: 
        !            72: #define KBD_QUEUE_SIZE 256
        !            73: 
        !            74: typedef struct {
        !            75:     uint8_t data[KBD_QUEUE_SIZE];
        !            76:     int rptr, wptr, count;
        !            77: } KBDQueue;
        !            78: 
        !            79: typedef struct ChannelState {
        !            80:     int irq;
        !            81:     int reg;
        !            82:     int rxint, txint;
        !            83:     chn_id_t chn; // this channel, A (base+4) or B (base+0)
        !            84:     chn_type_t type;
        !            85:     struct ChannelState *otherchn;
        !            86:     uint8_t rx, tx, wregs[16], rregs[16];
        !            87:     KBDQueue queue;
        !            88:     CharDriverState *chr;
        !            89: } ChannelState;
        !            90: 
        !            91: struct SerialState {
        !            92:     struct ChannelState chn[2];
        !            93: };
        !            94: 
        !            95: #define SERIAL_MAXADDR 7
        !            96: 
        !            97: static void handle_kbd_command(ChannelState *s, int val);
        !            98: static int serial_can_receive(void *opaque);
        !            99: static void serial_receive_byte(ChannelState *s, int ch);
        !           100: 
        !           101: static void put_queue(void *opaque, int b)
        !           102: {
        !           103:     ChannelState *s = opaque;
        !           104:     KBDQueue *q = &s->queue;
        !           105: 
        !           106:     KBD_DPRINTF("put: 0x%02x\n", b);
        !           107:     if (q->count >= KBD_QUEUE_SIZE)
        !           108:         return;
        !           109:     q->data[q->wptr] = b;
        !           110:     if (++q->wptr == KBD_QUEUE_SIZE)
        !           111:         q->wptr = 0;
        !           112:     q->count++;
        !           113:     serial_receive_byte(s, 0);
        !           114: }
        !           115: 
        !           116: static uint32_t get_queue(void *opaque)
        !           117: {
        !           118:     ChannelState *s = opaque;
        !           119:     KBDQueue *q = &s->queue;
        !           120:     int val;
        !           121:     
        !           122:     if (q->count == 0) {
        !           123:        return 0;
        !           124:     } else {
        !           125:         val = q->data[q->rptr];
        !           126:         if (++q->rptr == KBD_QUEUE_SIZE)
        !           127:             q->rptr = 0;
        !           128:         q->count--;
        !           129:     }
        !           130:     KBD_DPRINTF("get 0x%02x\n", val);
        !           131:     if (q->count > 0)
        !           132:        serial_receive_byte(s, 0);
        !           133:     return val;
        !           134: }
        !           135: 
        !           136: static void slavio_serial_update_irq(ChannelState *s)
        !           137: {
        !           138:     if ((s->wregs[1] & 1) && // interrupts enabled
        !           139:        (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
        !           140:         ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
        !           141:          s->rxint == 1) || // rx ints enabled, pending
        !           142:         ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
        !           143:         pic_set_irq(s->irq, 1);
        !           144:     } else {
        !           145:         pic_set_irq(s->irq, 0);
        !           146:     }
        !           147: }
        !           148: 
        !           149: static void slavio_serial_reset_chn(ChannelState *s)
        !           150: {
        !           151:     int i;
        !           152: 
        !           153:     s->reg = 0;
        !           154:     for (i = 0; i < SERIAL_MAXADDR; i++) {
        !           155:        s->rregs[i] = 0;
        !           156:        s->wregs[i] = 0;
        !           157:     }
        !           158:     s->wregs[4] = 4;
        !           159:     s->wregs[9] = 0xc0;
        !           160:     s->wregs[11] = 8;
        !           161:     s->wregs[14] = 0x30;
        !           162:     s->wregs[15] = 0xf8;
        !           163:     s->rregs[0] = 0x44;
        !           164:     s->rregs[1] = 6;
        !           165: 
        !           166:     s->rx = s->tx = 0;
        !           167:     s->rxint = s->txint = 0;
        !           168: }
        !           169: 
        !           170: static void slavio_serial_reset(void *opaque)
        !           171: {
        !           172:     SerialState *s = opaque;
        !           173:     slavio_serial_reset_chn(&s->chn[0]);
        !           174:     slavio_serial_reset_chn(&s->chn[1]);
        !           175: }
        !           176: 
        !           177: static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
        !           178: {
        !           179:     SerialState *ser = opaque;
        !           180:     ChannelState *s;
        !           181:     uint32_t saddr;
        !           182:     int newreg, channel;
        !           183: 
        !           184:     val &= 0xff;
        !           185:     saddr = (addr & 3) >> 1;
        !           186:     channel = (addr & SERIAL_MAXADDR) >> 2;
        !           187:     s = &ser->chn[channel];
        !           188:     switch (saddr) {
        !           189:     case 0:
        !           190:        SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
        !           191:        newreg = 0;
        !           192:        switch (s->reg) {
        !           193:        case 0:
        !           194:            newreg = val & 7;
        !           195:            val &= 0x38;
        !           196:            switch (val) {
        !           197:            case 8:
        !           198:                s->reg |= 0x8;
        !           199:                break;
        !           200:            case 0x20:
        !           201:                s->rxint = 0;
        !           202:                break;
        !           203:            case 0x28:
        !           204:                s->txint = 0;
        !           205:                break;
        !           206:            default:
        !           207:                break;
        !           208:            }
        !           209:            break;
        !           210:        case 1 ... 8:
        !           211:        case 10 ... 15:
        !           212:            s->wregs[s->reg] = val;
        !           213:            break;
        !           214:        case 9:
        !           215:            switch (val & 0xc0) {
        !           216:            case 0:
        !           217:            default:
        !           218:                break;
        !           219:            case 0x40:
        !           220:                slavio_serial_reset_chn(&ser->chn[1]);
        !           221:                return;
        !           222:            case 0x80:
        !           223:                slavio_serial_reset_chn(&ser->chn[0]);
        !           224:                return;
        !           225:            case 0xc0:
        !           226:                slavio_serial_reset(ser);
        !           227:                return;
        !           228:            }
        !           229:            break;
        !           230:        default:
        !           231:            break;
        !           232:        }
        !           233:        if (s->reg == 0)
        !           234:            s->reg = newreg;
        !           235:        else
        !           236:            s->reg = 0;
        !           237:        break;
        !           238:     case 1:
        !           239:        SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
        !           240:        if (s->wregs[5] & 8) { // tx enabled
        !           241:            s->tx = val;
        !           242:            if (s->chr)
        !           243:                qemu_chr_write(s->chr, &s->tx, 1);
        !           244:            else if (s->type == kbd) {
        !           245:                handle_kbd_command(s, val);
        !           246:            }
        !           247:            s->txint = 1;
        !           248:            s->rregs[0] |= 4;
        !           249:            // Interrupts reported only on channel A
        !           250:            if (s->chn == 0)
        !           251:                s->rregs[3] |= 0x10;
        !           252:            else {
        !           253:                s->otherchn->rregs[3] |= 2;
        !           254:            }
        !           255:            slavio_serial_update_irq(s);
        !           256:        }
        !           257:        break;
        !           258:     default:
        !           259:        break;
        !           260:     }
        !           261: }
        !           262: 
        !           263: static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
        !           264: {
        !           265:     SerialState *ser = opaque;
        !           266:     ChannelState *s;
        !           267:     uint32_t saddr;
        !           268:     uint32_t ret;
        !           269:     int channel;
        !           270: 
        !           271:     saddr = (addr & 3) >> 1;
        !           272:     channel = (addr & SERIAL_MAXADDR) >> 2;
        !           273:     s = &ser->chn[channel];
        !           274:     switch (saddr) {
        !           275:     case 0:
        !           276:        SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
        !           277:        ret = s->rregs[s->reg];
        !           278:        s->reg = 0;
        !           279:        return ret;
        !           280:     case 1:
        !           281:        SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', s->rx);
        !           282:        s->rregs[0] &= ~1;
        !           283:        if (s->type == kbd)
        !           284:            ret = get_queue(s);
        !           285:        else
        !           286:            ret = s->rx;
        !           287:        return ret;
        !           288:     default:
        !           289:        break;
        !           290:     }
        !           291:     return 0;
        !           292: }
        !           293: 
        !           294: static int serial_can_receive(void *opaque)
        !           295: {
        !           296:     ChannelState *s = opaque;
        !           297:     if (((s->wregs[3] & 1) == 0) // Rx not enabled
        !           298:        || ((s->rregs[0] & 1) == 1)) // char already available
        !           299:        return 0;
        !           300:     else
        !           301:        return 1;
        !           302: }
        !           303: 
        !           304: static void serial_receive_byte(ChannelState *s, int ch)
        !           305: {
        !           306:     s->rregs[0] |= 1;
        !           307:     // Interrupts reported only on channel A
        !           308:     if (s->chn == 0)
        !           309:        s->rregs[3] |= 0x20;
        !           310:     else {
        !           311:        s->otherchn->rregs[3] |= 4;
        !           312:     }
        !           313:     s->rx = ch;
        !           314:     s->rxint = 1;
        !           315:     slavio_serial_update_irq(s);
        !           316: }
        !           317: 
        !           318: static void serial_receive_break(ChannelState *s)
        !           319: {
        !           320:     s->rregs[0] |= 0x80;
        !           321:     slavio_serial_update_irq(s);
        !           322: }
        !           323: 
        !           324: static void serial_receive1(void *opaque, const uint8_t *buf, int size)
        !           325: {
        !           326:     ChannelState *s = opaque;
        !           327:     serial_receive_byte(s, buf[0]);
        !           328: }
        !           329: 
        !           330: static void serial_event(void *opaque, int event)
        !           331: {
        !           332:     ChannelState *s = opaque;
        !           333:     if (event == CHR_EVENT_BREAK)
        !           334:         serial_receive_break(s);
        !           335: }
        !           336: 
        !           337: static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
        !           338:     slavio_serial_mem_readb,
        !           339:     slavio_serial_mem_readb,
        !           340:     slavio_serial_mem_readb,
        !           341: };
        !           342: 
        !           343: static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
        !           344:     slavio_serial_mem_writeb,
        !           345:     slavio_serial_mem_writeb,
        !           346:     slavio_serial_mem_writeb,
        !           347: };
        !           348: 
        !           349: static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
        !           350: {
        !           351:     qemu_put_be32s(f, &s->irq);
        !           352:     qemu_put_be32s(f, &s->reg);
        !           353:     qemu_put_be32s(f, &s->rxint);
        !           354:     qemu_put_be32s(f, &s->txint);
        !           355:     qemu_put_8s(f, &s->rx);
        !           356:     qemu_put_8s(f, &s->tx);
        !           357:     qemu_put_buffer(f, s->wregs, 16);
        !           358:     qemu_put_buffer(f, s->rregs, 16);
        !           359: }
        !           360: 
        !           361: static void slavio_serial_save(QEMUFile *f, void *opaque)
        !           362: {
        !           363:     SerialState *s = opaque;
        !           364: 
        !           365:     slavio_serial_save_chn(f, &s->chn[0]);
        !           366:     slavio_serial_save_chn(f, &s->chn[1]);
        !           367: }
        !           368: 
        !           369: static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
        !           370: {
        !           371:     if (version_id != 1)
        !           372:         return -EINVAL;
        !           373: 
        !           374:     qemu_get_be32s(f, &s->irq);
        !           375:     qemu_get_be32s(f, &s->reg);
        !           376:     qemu_get_be32s(f, &s->rxint);
        !           377:     qemu_get_be32s(f, &s->txint);
        !           378:     qemu_get_8s(f, &s->rx);
        !           379:     qemu_get_8s(f, &s->tx);
        !           380:     qemu_get_buffer(f, s->wregs, 16);
        !           381:     qemu_get_buffer(f, s->rregs, 16);
        !           382:     return 0;
        !           383: }
        !           384: 
        !           385: static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
        !           386: {
        !           387:     SerialState *s = opaque;
        !           388:     int ret;
        !           389: 
        !           390:     ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
        !           391:     if (ret != 0)
        !           392:        return ret;
        !           393:     ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
        !           394:     return ret;
        !           395: 
        !           396: }
        !           397: 
        !           398: SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
        !           399: {
        !           400:     int slavio_serial_io_memory, i;
        !           401:     SerialState *s;
        !           402: 
        !           403:     s = qemu_mallocz(sizeof(SerialState));
        !           404:     if (!s)
        !           405:         return NULL;
        !           406: 
        !           407:     slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
        !           408:     cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
        !           409: 
        !           410:     s->chn[0].chr = chr1;
        !           411:     s->chn[1].chr = chr2;
        !           412: 
        !           413:     for (i = 0; i < 2; i++) {
        !           414:        s->chn[i].irq = irq;
        !           415:        s->chn[i].chn = 1 - i;
        !           416:        s->chn[i].type = ser;
        !           417:        if (s->chn[i].chr) {
        !           418:            qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]);
        !           419:            qemu_chr_add_event_handler(s->chn[i].chr, serial_event);
        !           420:        }
        !           421:     }
        !           422:     s->chn[0].otherchn = &s->chn[1];
        !           423:     s->chn[1].otherchn = &s->chn[0];
        !           424:     register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
        !           425:     qemu_register_reset(slavio_serial_reset, s);
        !           426:     slavio_serial_reset(s);
        !           427:     return s;
        !           428: }
        !           429: 
        !           430: static const uint8_t keycodes[128] = {
        !           431:     127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
        !           432:     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
        !           433:     79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
        !           434:     104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
        !           435:     14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
        !           436:     113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
        !           437:     90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
        !           438:     0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
        !           439: };
        !           440: 
        !           441: static void sunkbd_event(void *opaque, int ch)
        !           442: {
        !           443:     ChannelState *s = opaque;
        !           444:     int release = ch & 0x80;
        !           445: 
        !           446:     ch = keycodes[ch & 0x7f];
        !           447:     KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press");
        !           448:     put_queue(s, ch | release);
        !           449: }
        !           450: 
        !           451: static void handle_kbd_command(ChannelState *s, int val)
        !           452: {
        !           453:     KBD_DPRINTF("Command %d\n", val);
        !           454:     switch (val) {
        !           455:     case 1: // Reset, return type code
        !           456:        put_queue(s, 0xff);
        !           457:        put_queue(s, 0xff);
        !           458:        put_queue(s, 5); // Type 5
        !           459:        break;
        !           460:     case 7: // Query layout
        !           461:        put_queue(s, 0xfe);
        !           462:        put_queue(s, 0x20); // XXX, layout?
        !           463:        break;
        !           464:     default:
        !           465:        break;
        !           466:     }
        !           467: }
        !           468: 
        !           469: static void sunmouse_event(void *opaque, 
        !           470:                                int dx, int dy, int dz, int buttons_state)
        !           471: {
        !           472:     ChannelState *s = opaque;
        !           473:     int ch;
        !           474: 
        !           475:     // XXX
        !           476:     ch = 0x42;
        !           477:     serial_receive_byte(s, ch);
        !           478: }
        !           479: 
        !           480: void slavio_serial_ms_kbd_init(int base, int irq)
        !           481: {
        !           482:     int slavio_serial_io_memory, i;
        !           483:     SerialState *s;
        !           484: 
        !           485:     s = qemu_mallocz(sizeof(SerialState));
        !           486:     if (!s)
        !           487:         return;
        !           488:     for (i = 0; i < 2; i++) {
        !           489:        s->chn[i].irq = irq;
        !           490:        s->chn[i].chn = 1 - i;
        !           491:        s->chn[i].chr = NULL;
        !           492:     }
        !           493:     s->chn[0].otherchn = &s->chn[1];
        !           494:     s->chn[1].otherchn = &s->chn[0];
        !           495:     s->chn[0].type = mouse;
        !           496:     s->chn[1].type = kbd;
        !           497: 
        !           498:     slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
        !           499:     cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
        !           500: 
        !           501:     qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0]);
        !           502:     qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
        !           503:     qemu_register_reset(slavio_serial_reset, s);
        !           504:     slavio_serial_reset(s);
        !           505: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.