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

1.1       root        1: /*
                      2:  * QEMU Sparc SLAVIO serial port emulation
1.1.1.5 ! root        3:  *
1.1       root        4:  * Copyright (c) 2003-2005 Fabrice Bellard
1.1.1.5 ! root        5:  *
1.1       root        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:  */
1.1.1.5 ! root       24: #include "hw.h"
        !            25: #include "sun4m.h"
        !            26: #include "qemu-char.h"
        !            27: #include "console.h"
        !            28: 
1.1       root       29: /* debug serial */
                     30: //#define DEBUG_SERIAL
                     31: 
                     32: /* debug keyboard */
                     33: //#define DEBUG_KBD
                     34: 
                     35: /* debug mouse */
                     36: //#define DEBUG_MOUSE
                     37: 
                     38: /*
                     39:  * This is the serial port, mouse and keyboard part of chip STP2001
                     40:  * (Slave I/O), also produced as NCR89C105. See
                     41:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
1.1.1.5 ! root       42:  *
1.1       root       43:  * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
                     44:  * mouse and keyboard ports don't implement all functions and they are
                     45:  * only asynchronous. There is no DMA.
                     46:  *
                     47:  */
                     48: 
1.1.1.4   root       49: /*
                     50:  * Modifications:
                     51:  *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
                     52:  *                                  serial mouse queue.
                     53:  *                                  Implemented serial mouse protocol.
                     54:  */
                     55: 
1.1       root       56: #ifdef DEBUG_SERIAL
                     57: #define SER_DPRINTF(fmt, args...) \
                     58: do { printf("SER: " fmt , ##args); } while (0)
                     59: #else
                     60: #define SER_DPRINTF(fmt, args...)
                     61: #endif
                     62: #ifdef DEBUG_KBD
                     63: #define KBD_DPRINTF(fmt, args...) \
                     64: do { printf("KBD: " fmt , ##args); } while (0)
                     65: #else
                     66: #define KBD_DPRINTF(fmt, args...)
                     67: #endif
                     68: #ifdef DEBUG_MOUSE
                     69: #define MS_DPRINTF(fmt, args...) \
1.1.1.4   root       70: do { printf("MSC: " fmt , ##args); } while (0)
1.1       root       71: #else
                     72: #define MS_DPRINTF(fmt, args...)
                     73: #endif
                     74: 
                     75: typedef enum {
                     76:     chn_a, chn_b,
                     77: } chn_id_t;
                     78: 
1.1.1.4   root       79: #define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
                     80: 
1.1       root       81: typedef enum {
                     82:     ser, kbd, mouse,
                     83: } chn_type_t;
                     84: 
1.1.1.4   root       85: #define SERIO_QUEUE_SIZE 256
1.1       root       86: 
                     87: typedef struct {
1.1.1.4   root       88:     uint8_t data[SERIO_QUEUE_SIZE];
1.1       root       89:     int rptr, wptr, count;
1.1.1.4   root       90: } SERIOQueue;
1.1       root       91: 
1.1.1.5 ! root       92: #define SERIAL_REGS 16
1.1       root       93: typedef struct ChannelState {
1.1.1.5 ! root       94:     qemu_irq irq;
1.1       root       95:     int reg;
1.1.1.4   root       96:     int rxint, txint, rxint_under_svc, txint_under_svc;
1.1       root       97:     chn_id_t chn; // this channel, A (base+4) or B (base+0)
                     98:     chn_type_t type;
                     99:     struct ChannelState *otherchn;
1.1.1.5 ! root      100:     uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS];
1.1.1.4   root      101:     SERIOQueue queue;
1.1       root      102:     CharDriverState *chr;
1.1.1.5 ! root      103:     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
        !           104:     int disabled;
1.1       root      105: } ChannelState;
                    106: 
                    107: struct SerialState {
                    108:     struct ChannelState chn[2];
                    109: };
                    110: 
                    111: #define SERIAL_MAXADDR 7
1.1.1.5 ! root      112: #define SERIAL_SIZE (SERIAL_MAXADDR + 1)
        !           113: #define SERIAL_CTRL 0
        !           114: #define SERIAL_DATA 1
        !           115: 
        !           116: #define W_CMD     0
        !           117: #define CMD_PTR_MASK   0x07
        !           118: #define CMD_CMD_MASK   0x38
        !           119: #define CMD_HI         0x08
        !           120: #define CMD_CLR_TXINT  0x28
        !           121: #define CMD_CLR_IUS    0x38
        !           122: #define W_INTR    1
        !           123: #define INTR_INTALL    0x01
        !           124: #define INTR_TXINT     0x02
        !           125: #define INTR_RXMODEMSK 0x18
        !           126: #define INTR_RXINT1ST  0x08
        !           127: #define INTR_RXINTALL  0x10
        !           128: #define W_IVEC    2
        !           129: #define W_RXCTRL  3
        !           130: #define RXCTRL_RXEN    0x01
        !           131: #define W_TXCTRL1 4
        !           132: #define TXCTRL1_PAREN  0x01
        !           133: #define TXCTRL1_PAREV  0x02
        !           134: #define TXCTRL1_1STOP  0x04
        !           135: #define TXCTRL1_1HSTOP 0x08
        !           136: #define TXCTRL1_2STOP  0x0c
        !           137: #define TXCTRL1_STPMSK 0x0c
        !           138: #define TXCTRL1_CLK1X  0x00
        !           139: #define TXCTRL1_CLK16X 0x40
        !           140: #define TXCTRL1_CLK32X 0x80
        !           141: #define TXCTRL1_CLK64X 0xc0
        !           142: #define TXCTRL1_CLKMSK 0xc0
        !           143: #define W_TXCTRL2 5
        !           144: #define TXCTRL2_TXEN   0x08
        !           145: #define TXCTRL2_BITMSK 0x60
        !           146: #define TXCTRL2_5BITS  0x00
        !           147: #define TXCTRL2_7BITS  0x20
        !           148: #define TXCTRL2_6BITS  0x40
        !           149: #define TXCTRL2_8BITS  0x60
        !           150: #define W_SYNC1   6
        !           151: #define W_SYNC2   7
        !           152: #define W_TXBUF   8
        !           153: #define W_MINTR   9
        !           154: #define MINTR_STATUSHI 0x10
        !           155: #define MINTR_RST_MASK 0xc0
        !           156: #define MINTR_RST_B    0x40
        !           157: #define MINTR_RST_A    0x80
        !           158: #define MINTR_RST_ALL  0xc0
        !           159: #define W_MISC1  10
        !           160: #define W_CLOCK  11
        !           161: #define CLOCK_TRXC     0x08
        !           162: #define W_BRGLO  12
        !           163: #define W_BRGHI  13
        !           164: #define W_MISC2  14
        !           165: #define MISC2_PLLDIS   0x30
        !           166: #define W_EXTINT 15
        !           167: #define EXTINT_DCD     0x08
        !           168: #define EXTINT_SYNCINT 0x10
        !           169: #define EXTINT_CTSINT  0x20
        !           170: #define EXTINT_TXUNDRN 0x40
        !           171: #define EXTINT_BRKINT  0x80
        !           172: 
        !           173: #define R_STATUS  0
        !           174: #define STATUS_RXAV    0x01
        !           175: #define STATUS_ZERO    0x02
        !           176: #define STATUS_TXEMPTY 0x04
        !           177: #define STATUS_DCD     0x08
        !           178: #define STATUS_SYNC    0x10
        !           179: #define STATUS_CTS     0x20
        !           180: #define STATUS_TXUNDRN 0x40
        !           181: #define STATUS_BRK     0x80
        !           182: #define R_SPEC    1
        !           183: #define SPEC_ALLSENT   0x01
        !           184: #define SPEC_BITS8     0x06
        !           185: #define R_IVEC    2
        !           186: #define IVEC_TXINTB    0x00
        !           187: #define IVEC_LONOINT   0x06
        !           188: #define IVEC_LORXINTA  0x0c
        !           189: #define IVEC_LORXINTB  0x04
        !           190: #define IVEC_LOTXINTA  0x08
        !           191: #define IVEC_HINOINT   0x60
        !           192: #define IVEC_HIRXINTA  0x30
        !           193: #define IVEC_HIRXINTB  0x20
        !           194: #define IVEC_HITXINTA  0x10
        !           195: #define R_INTR    3
        !           196: #define INTR_EXTINTB   0x01
        !           197: #define INTR_TXINTB    0x02
        !           198: #define INTR_RXINTB    0x04
        !           199: #define INTR_EXTINTA   0x08
        !           200: #define INTR_TXINTA    0x10
        !           201: #define INTR_RXINTA    0x20
        !           202: #define R_IPEN    4
        !           203: #define R_TXCTRL1 5
        !           204: #define R_TXCTRL2 6
        !           205: #define R_BC      7
        !           206: #define R_RXBUF   8
        !           207: #define R_RXCTRL  9
        !           208: #define R_MISC   10
        !           209: #define R_MISC1  11
        !           210: #define R_BRGLO  12
        !           211: #define R_BRGHI  13
        !           212: #define R_MISC1I 14
        !           213: #define R_EXTINT 15
1.1       root      214: 
                    215: static void handle_kbd_command(ChannelState *s, int val);
                    216: static int serial_can_receive(void *opaque);
                    217: static void serial_receive_byte(ChannelState *s, int ch);
1.1.1.4   root      218: static inline void set_txint(ChannelState *s);
1.1       root      219: 
1.1.1.5 ! root      220: static void clear_queue(void *opaque)
        !           221: {
        !           222:     ChannelState *s = opaque;
        !           223:     SERIOQueue *q = &s->queue;
        !           224:     q->rptr = q->wptr = q->count = 0;
        !           225: }
        !           226: 
1.1       root      227: static void put_queue(void *opaque, int b)
                    228: {
                    229:     ChannelState *s = opaque;
1.1.1.4   root      230:     SERIOQueue *q = &s->queue;
1.1       root      231: 
1.1.1.4   root      232:     SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
                    233:     if (q->count >= SERIO_QUEUE_SIZE)
1.1       root      234:         return;
                    235:     q->data[q->wptr] = b;
1.1.1.4   root      236:     if (++q->wptr == SERIO_QUEUE_SIZE)
1.1       root      237:         q->wptr = 0;
                    238:     q->count++;
                    239:     serial_receive_byte(s, 0);
                    240: }
                    241: 
                    242: static uint32_t get_queue(void *opaque)
                    243: {
                    244:     ChannelState *s = opaque;
1.1.1.4   root      245:     SERIOQueue *q = &s->queue;
1.1       root      246:     int val;
1.1.1.5 ! root      247: 
1.1       root      248:     if (q->count == 0) {
1.1.1.5 ! root      249:         return 0;
1.1       root      250:     } else {
                    251:         val = q->data[q->rptr];
1.1.1.4   root      252:         if (++q->rptr == SERIO_QUEUE_SIZE)
1.1       root      253:             q->rptr = 0;
                    254:         q->count--;
                    255:     }
1.1.1.5 ! root      256:     SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
1.1       root      257:     if (q->count > 0)
1.1.1.5 ! root      258:         serial_receive_byte(s, 0);
1.1       root      259:     return val;
                    260: }
                    261: 
1.1.1.4   root      262: static int slavio_serial_update_irq_chn(ChannelState *s)
1.1       root      263: {
1.1.1.5 ! root      264:     if ((s->wregs[W_INTR] & INTR_INTALL) && // interrupts enabled
        !           265:         (((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
        !           266:          // tx ints enabled, pending
        !           267:          ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
        !           268:            ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
        !           269:           s->rxint == 1) || // rx ints enabled, pending
        !           270:          ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
        !           271:           (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
1.1.1.4   root      272:         return 1;
1.1       root      273:     }
1.1.1.4   root      274:     return 0;
                    275: }
                    276: 
                    277: static void slavio_serial_update_irq(ChannelState *s)
                    278: {
                    279:     int irq;
                    280: 
                    281:     irq = slavio_serial_update_irq_chn(s);
                    282:     irq |= slavio_serial_update_irq_chn(s->otherchn);
                    283: 
1.1.1.5 ! root      284:     SER_DPRINTF("IRQ = %d\n", irq);
        !           285:     qemu_set_irq(s->irq, irq);
1.1       root      286: }
                    287: 
                    288: static void slavio_serial_reset_chn(ChannelState *s)
                    289: {
                    290:     int i;
                    291: 
                    292:     s->reg = 0;
1.1.1.5 ! root      293:     for (i = 0; i < SERIAL_SIZE; i++) {
        !           294:         s->rregs[i] = 0;
        !           295:         s->wregs[i] = 0;
        !           296:     }
        !           297:     s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
        !           298:     s->wregs[W_MINTR] = MINTR_RST_ALL;
        !           299:     s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
        !           300:     s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
        !           301:     s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
        !           302:         EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
        !           303:     if (s->disabled)
        !           304:         s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
        !           305:             STATUS_CTS | STATUS_TXUNDRN;
        !           306:     else
        !           307:         s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
        !           308:     s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
1.1       root      309: 
                    310:     s->rx = s->tx = 0;
                    311:     s->rxint = s->txint = 0;
1.1.1.4   root      312:     s->rxint_under_svc = s->txint_under_svc = 0;
1.1.1.5 ! root      313:     s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
        !           314:     clear_queue(s);
1.1       root      315: }
                    316: 
                    317: static void slavio_serial_reset(void *opaque)
                    318: {
                    319:     SerialState *s = opaque;
                    320:     slavio_serial_reset_chn(&s->chn[0]);
                    321:     slavio_serial_reset_chn(&s->chn[1]);
                    322: }
                    323: 
1.1.1.2   root      324: static inline void clr_rxint(ChannelState *s)
                    325: {
                    326:     s->rxint = 0;
1.1.1.4   root      327:     s->rxint_under_svc = 0;
1.1.1.5 ! root      328:     if (s->chn == chn_a) {
        !           329:         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           330:             s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
        !           331:         else
        !           332:             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
        !           333:         s->rregs[R_INTR] &= ~INTR_RXINTA;
        !           334:     } else {
        !           335:         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           336:             s->rregs[R_IVEC] = IVEC_HINOINT;
        !           337:         else
        !           338:             s->rregs[R_IVEC] = IVEC_LONOINT;
        !           339:         s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
        !           340:     }
1.1.1.4   root      341:     if (s->txint)
                    342:         set_txint(s);
1.1.1.2   root      343:     slavio_serial_update_irq(s);
                    344: }
                    345: 
                    346: static inline void set_rxint(ChannelState *s)
                    347: {
                    348:     s->rxint = 1;
1.1.1.4   root      349:     if (!s->txint_under_svc) {
                    350:         s->rxint_under_svc = 1;
1.1.1.5 ! root      351:         if (s->chn == chn_a) {
        !           352:             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           353:                 s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
        !           354:             else
        !           355:                 s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
        !           356:         } else {
        !           357:             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           358:                 s->rregs[R_IVEC] = IVEC_HIRXINTB;
        !           359:             else
        !           360:                 s->rregs[R_IVEC] = IVEC_LORXINTB;
        !           361:         }
1.1.1.2   root      362:     }
1.1.1.5 ! root      363:     if (s->chn == chn_a)
        !           364:         s->rregs[R_INTR] |= INTR_RXINTA;
        !           365:     else
        !           366:         s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
        !           367:     slavio_serial_update_irq(s);
1.1.1.2   root      368: }
                    369: 
                    370: static inline void clr_txint(ChannelState *s)
                    371: {
                    372:     s->txint = 0;
1.1.1.4   root      373:     s->txint_under_svc = 0;
1.1.1.5 ! root      374:     if (s->chn == chn_a) {
        !           375:         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           376:             s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
        !           377:         else
        !           378:             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
        !           379:         s->rregs[R_INTR] &= ~INTR_TXINTA;
        !           380:     } else {
        !           381:         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           382:             s->rregs[R_IVEC] = IVEC_HINOINT;
        !           383:         else
        !           384:             s->rregs[R_IVEC] = IVEC_LONOINT;
        !           385:         s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
        !           386:     }
1.1.1.4   root      387:     if (s->rxint)
                    388:         set_rxint(s);
1.1.1.2   root      389:     slavio_serial_update_irq(s);
                    390: }
                    391: 
                    392: static inline void set_txint(ChannelState *s)
                    393: {
                    394:     s->txint = 1;
1.1.1.4   root      395:     if (!s->rxint_under_svc) {
                    396:         s->txint_under_svc = 1;
1.1.1.5 ! root      397:         if (s->chn == chn_a) {
        !           398:             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
        !           399:                 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
        !           400:             else
        !           401:                 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
        !           402:         } else {
        !           403:             s->rregs[R_IVEC] = IVEC_TXINTB;
        !           404:         }
1.1.1.2   root      405:     }
1.1.1.5 ! root      406:     if (s->chn == chn_a)
        !           407:         s->rregs[R_INTR] |= INTR_TXINTA;
        !           408:     else
        !           409:         s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
        !           410:     slavio_serial_update_irq(s);
1.1.1.4   root      411: }
                    412: 
                    413: static void slavio_serial_update_parameters(ChannelState *s)
                    414: {
                    415:     int speed, parity, data_bits, stop_bits;
                    416:     QEMUSerialSetParams ssp;
                    417: 
                    418:     if (!s->chr || s->type != ser)
                    419:         return;
                    420: 
1.1.1.5 ! root      421:     if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
        !           422:         if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
1.1.1.4   root      423:             parity = 'E';
                    424:         else
                    425:             parity = 'O';
                    426:     } else {
                    427:         parity = 'N';
                    428:     }
1.1.1.5 ! root      429:     if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
1.1.1.4   root      430:         stop_bits = 2;
                    431:     else
                    432:         stop_bits = 1;
1.1.1.5 ! root      433:     switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
        !           434:     case TXCTRL2_5BITS:
1.1.1.4   root      435:         data_bits = 5;
                    436:         break;
1.1.1.5 ! root      437:     case TXCTRL2_7BITS:
1.1.1.4   root      438:         data_bits = 7;
                    439:         break;
1.1.1.5 ! root      440:     case TXCTRL2_6BITS:
1.1.1.4   root      441:         data_bits = 6;
                    442:         break;
                    443:     default:
1.1.1.5 ! root      444:     case TXCTRL2_8BITS:
1.1.1.4   root      445:         data_bits = 8;
                    446:         break;
                    447:     }
1.1.1.5 ! root      448:     speed = 2457600 / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
        !           449:     switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
        !           450:     case TXCTRL1_CLK1X:
1.1.1.4   root      451:         break;
1.1.1.5 ! root      452:     case TXCTRL1_CLK16X:
1.1.1.4   root      453:         speed /= 16;
                    454:         break;
1.1.1.5 ! root      455:     case TXCTRL1_CLK32X:
1.1.1.4   root      456:         speed /= 32;
                    457:         break;
                    458:     default:
1.1.1.5 ! root      459:     case TXCTRL1_CLK64X:
1.1.1.4   root      460:         speed /= 64;
                    461:         break;
                    462:     }
                    463:     ssp.speed = speed;
                    464:     ssp.parity = parity;
                    465:     ssp.data_bits = data_bits;
                    466:     ssp.stop_bits = stop_bits;
                    467:     SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
                    468:                 speed, parity, data_bits, stop_bits);
                    469:     qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
1.1.1.2   root      470: }
                    471: 
1.1.1.5 ! root      472: static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr,
        !           473:                                      uint32_t val)
1.1       root      474: {
1.1.1.5 ! root      475:     SerialState *serial = opaque;
1.1       root      476:     ChannelState *s;
                    477:     uint32_t saddr;
                    478:     int newreg, channel;
                    479: 
                    480:     val &= 0xff;
                    481:     saddr = (addr & 3) >> 1;
                    482:     channel = (addr & SERIAL_MAXADDR) >> 2;
1.1.1.5 ! root      483:     s = &serial->chn[channel];
1.1       root      484:     switch (saddr) {
1.1.1.5 ! root      485:     case SERIAL_CTRL:
        !           486:         SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
        !           487:                     val & 0xff);
        !           488:         newreg = 0;
        !           489:         switch (s->reg) {
        !           490:         case W_CMD:
        !           491:             newreg = val & CMD_PTR_MASK;
        !           492:             val &= CMD_CMD_MASK;
        !           493:             switch (val) {
        !           494:             case CMD_HI:
        !           495:                 newreg |= CMD_HI;
        !           496:                 break;
        !           497:             case CMD_CLR_TXINT:
1.1.1.2   root      498:                 clr_txint(s);
1.1.1.5 ! root      499:                 break;
        !           500:             case CMD_CLR_IUS:
1.1.1.4   root      501:                 if (s->rxint_under_svc)
                    502:                     clr_rxint(s);
                    503:                 else if (s->txint_under_svc)
                    504:                     clr_txint(s);
1.1.1.5 ! root      505:                 break;
        !           506:             default:
        !           507:                 break;
        !           508:             }
        !           509:             break;
        !           510:         case W_INTR ... W_RXCTRL:
        !           511:         case W_SYNC1 ... W_TXBUF:
        !           512:         case W_MISC1 ... W_CLOCK:
        !           513:         case W_MISC2 ... W_EXTINT:
        !           514:             s->wregs[s->reg] = val;
        !           515:             break;
        !           516:         case W_TXCTRL1:
        !           517:         case W_TXCTRL2:
        !           518:         case W_BRGLO:
        !           519:         case W_BRGHI:
        !           520:             s->wregs[s->reg] = val;
1.1.1.4   root      521:             slavio_serial_update_parameters(s);
1.1.1.5 ! root      522:             break;
        !           523:         case W_MINTR:
        !           524:             switch (val & MINTR_RST_MASK) {
        !           525:             case 0:
        !           526:             default:
        !           527:                 break;
        !           528:             case MINTR_RST_B:
        !           529:                 slavio_serial_reset_chn(&serial->chn[1]);
        !           530:                 return;
        !           531:             case MINTR_RST_A:
        !           532:                 slavio_serial_reset_chn(&serial->chn[0]);
        !           533:                 return;
        !           534:             case MINTR_RST_ALL:
        !           535:                 slavio_serial_reset(serial);
        !           536:                 return;
        !           537:             }
        !           538:             break;
        !           539:         default:
        !           540:             break;
        !           541:         }
        !           542:         if (s->reg == 0)
        !           543:             s->reg = newreg;
        !           544:         else
        !           545:             s->reg = 0;
        !           546:         break;
        !           547:     case SERIAL_DATA:
        !           548:         SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
        !           549:         s->tx = val;
        !           550:         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
        !           551:             if (s->chr)
        !           552:                 qemu_chr_write(s->chr, &s->tx, 1);
        !           553:             else if (s->type == kbd && !s->disabled) {
        !           554:                 handle_kbd_command(s, val);
        !           555:             }
        !           556:         }
        !           557:         s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
        !           558:         s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
        !           559:         set_txint(s);
        !           560:         break;
1.1       root      561:     default:
1.1.1.5 ! root      562:         break;
1.1       root      563:     }
                    564: }
                    565: 
                    566: static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
                    567: {
1.1.1.5 ! root      568:     SerialState *serial = opaque;
1.1       root      569:     ChannelState *s;
                    570:     uint32_t saddr;
                    571:     uint32_t ret;
                    572:     int channel;
                    573: 
                    574:     saddr = (addr & 3) >> 1;
                    575:     channel = (addr & SERIAL_MAXADDR) >> 2;
1.1.1.5 ! root      576:     s = &serial->chn[channel];
1.1       root      577:     switch (saddr) {
1.1.1.5 ! root      578:     case SERIAL_CTRL:
        !           579:         SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
        !           580:                     s->rregs[s->reg]);
        !           581:         ret = s->rregs[s->reg];
        !           582:         s->reg = 0;
        !           583:         return ret;
        !           584:     case SERIAL_DATA:
        !           585:         s->rregs[R_STATUS] &= ~STATUS_RXAV;
1.1.1.2   root      586:         clr_rxint(s);
1.1.1.5 ! root      587:         if (s->type == kbd || s->type == mouse)
        !           588:             ret = get_queue(s);
        !           589:         else
        !           590:             ret = s->rx;
        !           591:         SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
        !           592:         if (s->chr)
        !           593:             qemu_chr_accept_input(s->chr);
        !           594:         return ret;
1.1       root      595:     default:
1.1.1.5 ! root      596:         break;
1.1       root      597:     }
                    598:     return 0;
                    599: }
                    600: 
                    601: static int serial_can_receive(void *opaque)
                    602: {
                    603:     ChannelState *s = opaque;
1.1.1.4   root      604:     int ret;
                    605: 
1.1.1.5 ! root      606:     if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
        !           607:         || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
        !           608:         // char already available
        !           609:         ret = 0;
1.1       root      610:     else
1.1.1.5 ! root      611:         ret = 1;
1.1.1.4   root      612:     return ret;
1.1       root      613: }
                    614: 
                    615: static void serial_receive_byte(ChannelState *s, int ch)
                    616: {
1.1.1.4   root      617:     SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
1.1.1.5 ! root      618:     s->rregs[R_STATUS] |= STATUS_RXAV;
1.1       root      619:     s->rx = ch;
1.1.1.2   root      620:     set_rxint(s);
1.1       root      621: }
                    622: 
                    623: static void serial_receive_break(ChannelState *s)
                    624: {
1.1.1.5 ! root      625:     s->rregs[R_STATUS] |= STATUS_BRK;
1.1       root      626:     slavio_serial_update_irq(s);
                    627: }
                    628: 
                    629: static void serial_receive1(void *opaque, const uint8_t *buf, int size)
                    630: {
                    631:     ChannelState *s = opaque;
                    632:     serial_receive_byte(s, buf[0]);
                    633: }
                    634: 
                    635: static void serial_event(void *opaque, int event)
                    636: {
                    637:     ChannelState *s = opaque;
                    638:     if (event == CHR_EVENT_BREAK)
                    639:         serial_receive_break(s);
                    640: }
                    641: 
                    642: static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
                    643:     slavio_serial_mem_readb,
1.1.1.5 ! root      644:     NULL,
        !           645:     NULL,
1.1       root      646: };
                    647: 
                    648: static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
                    649:     slavio_serial_mem_writeb,
1.1.1.5 ! root      650:     NULL,
        !           651:     NULL,
1.1       root      652: };
                    653: 
                    654: static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
                    655: {
1.1.1.5 ! root      656:     int tmp;
        !           657:     tmp = 0;
        !           658:     qemu_put_be32s(f, &tmp); /* unused, was IRQ.  */
1.1       root      659:     qemu_put_be32s(f, &s->reg);
                    660:     qemu_put_be32s(f, &s->rxint);
                    661:     qemu_put_be32s(f, &s->txint);
1.1.1.4   root      662:     qemu_put_be32s(f, &s->rxint_under_svc);
                    663:     qemu_put_be32s(f, &s->txint_under_svc);
1.1       root      664:     qemu_put_8s(f, &s->rx);
                    665:     qemu_put_8s(f, &s->tx);
1.1.1.5 ! root      666:     qemu_put_buffer(f, s->wregs, SERIAL_REGS);
        !           667:     qemu_put_buffer(f, s->rregs, SERIAL_REGS);
1.1       root      668: }
                    669: 
                    670: static void slavio_serial_save(QEMUFile *f, void *opaque)
                    671: {
                    672:     SerialState *s = opaque;
                    673: 
                    674:     slavio_serial_save_chn(f, &s->chn[0]);
                    675:     slavio_serial_save_chn(f, &s->chn[1]);
                    676: }
                    677: 
                    678: static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
                    679: {
1.1.1.5 ! root      680:     int tmp;
        !           681: 
1.1.1.4   root      682:     if (version_id > 2)
1.1       root      683:         return -EINVAL;
                    684: 
1.1.1.5 ! root      685:     qemu_get_be32s(f, &tmp); /* unused */
1.1       root      686:     qemu_get_be32s(f, &s->reg);
                    687:     qemu_get_be32s(f, &s->rxint);
                    688:     qemu_get_be32s(f, &s->txint);
1.1.1.4   root      689:     if (version_id >= 2) {
                    690:         qemu_get_be32s(f, &s->rxint_under_svc);
                    691:         qemu_get_be32s(f, &s->txint_under_svc);
                    692:     }
1.1       root      693:     qemu_get_8s(f, &s->rx);
                    694:     qemu_get_8s(f, &s->tx);
1.1.1.5 ! root      695:     qemu_get_buffer(f, s->wregs, SERIAL_REGS);
        !           696:     qemu_get_buffer(f, s->rregs, SERIAL_REGS);
1.1       root      697:     return 0;
                    698: }
                    699: 
                    700: static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
                    701: {
                    702:     SerialState *s = opaque;
                    703:     int ret;
                    704: 
                    705:     ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
                    706:     if (ret != 0)
1.1.1.5 ! root      707:         return ret;
1.1       root      708:     ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
                    709:     return ret;
                    710: 
                    711: }
                    712: 
1.1.1.5 ! root      713: SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,
        !           714:                                 CharDriverState *chr1, CharDriverState *chr2)
1.1       root      715: {
                    716:     int slavio_serial_io_memory, i;
                    717:     SerialState *s;
                    718: 
                    719:     s = qemu_mallocz(sizeof(SerialState));
                    720:     if (!s)
                    721:         return NULL;
                    722: 
1.1.1.5 ! root      723:     slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read,
        !           724:                                                      slavio_serial_mem_write,
        !           725:                                                      s);
        !           726:     cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory);
1.1       root      727: 
                    728:     s->chn[0].chr = chr1;
                    729:     s->chn[1].chr = chr2;
1.1.1.5 ! root      730:     s->chn[0].disabled = 0;
        !           731:     s->chn[1].disabled = 0;
1.1       root      732: 
                    733:     for (i = 0; i < 2; i++) {
1.1.1.5 ! root      734:         s->chn[i].irq = irq;
        !           735:         s->chn[i].chn = 1 - i;
        !           736:         s->chn[i].type = ser;
        !           737:         if (s->chn[i].chr) {
        !           738:             qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
1.1.1.4   root      739:                                   serial_receive1, serial_event, &s->chn[i]);
1.1.1.5 ! root      740:         }
1.1       root      741:     }
                    742:     s->chn[0].otherchn = &s->chn[1];
                    743:     s->chn[1].otherchn = &s->chn[0];
1.1.1.5 ! root      744:     register_savevm("slavio_serial", base, 2, slavio_serial_save,
        !           745:                     slavio_serial_load, s);
1.1       root      746:     qemu_register_reset(slavio_serial_reset, s);
                    747:     slavio_serial_reset(s);
                    748:     return s;
                    749: }
                    750: 
                    751: static const uint8_t keycodes[128] = {
                    752:     127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
                    753:     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
                    754:     79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
                    755:     104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
                    756:     14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
                    757:     113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
                    758:     90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
                    759:     0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
                    760: };
                    761: 
1.1.1.5 ! root      762: static const uint8_t e0_keycodes[128] = {
        !           763:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           764:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
        !           765:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           766:     0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
        !           767:     0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
        !           768:     113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           769:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           770:     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !           771: };
        !           772: 
1.1       root      773: static void sunkbd_event(void *opaque, int ch)
                    774: {
                    775:     ChannelState *s = opaque;
                    776:     int release = ch & 0x80;
                    777: 
1.1.1.5 ! root      778:     KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" :
        !           779:                 "press");
        !           780:     switch (ch) {
        !           781:     case 58: // Caps lock press
        !           782:         s->caps_lock_mode ^= 1;
        !           783:         if (s->caps_lock_mode == 2)
        !           784:             return; // Drop second press
        !           785:         break;
        !           786:     case 69: // Num lock press
        !           787:         s->num_lock_mode ^= 1;
        !           788:         if (s->num_lock_mode == 2)
        !           789:             return; // Drop second press
        !           790:         break;
        !           791:     case 186: // Caps lock release
        !           792:         s->caps_lock_mode ^= 2;
        !           793:         if (s->caps_lock_mode == 3)
        !           794:             return; // Drop first release
        !           795:         break;
        !           796:     case 197: // Num lock release
        !           797:         s->num_lock_mode ^= 2;
        !           798:         if (s->num_lock_mode == 3)
        !           799:             return; // Drop first release
        !           800:         break;
        !           801:     case 0xe0:
        !           802:         s->e0_mode = 1;
        !           803:         return;
        !           804:     default:
        !           805:         break;
        !           806:     }
        !           807:     if (s->e0_mode) {
        !           808:         s->e0_mode = 0;
        !           809:         ch = e0_keycodes[ch & 0x7f];
        !           810:     } else {
        !           811:         ch = keycodes[ch & 0x7f];
        !           812:     }
        !           813:     KBD_DPRINTF("Translated keycode %2.2x\n", ch);
1.1       root      814:     put_queue(s, ch | release);
                    815: }
                    816: 
                    817: static void handle_kbd_command(ChannelState *s, int val)
                    818: {
                    819:     KBD_DPRINTF("Command %d\n", val);
1.1.1.5 ! root      820:     if (s->led_mode) { // Ignore led byte
        !           821:         s->led_mode = 0;
        !           822:         return;
        !           823:     }
1.1       root      824:     switch (val) {
                    825:     case 1: // Reset, return type code
1.1.1.5 ! root      826:         clear_queue(s);
        !           827:         put_queue(s, 0xff);
        !           828:         put_queue(s, 4); // Type 4
        !           829:         put_queue(s, 0x7f);
        !           830:         break;
        !           831:     case 0xe: // Set leds
        !           832:         s->led_mode = 1;
        !           833:         break;
1.1       root      834:     case 7: // Query layout
1.1.1.5 ! root      835:     case 0xf:
        !           836:         clear_queue(s);
        !           837:         put_queue(s, 0xfe);
        !           838:         put_queue(s, 0); // XXX, layout?
        !           839:         break;
1.1       root      840:     default:
1.1.1.5 ! root      841:         break;
1.1       root      842:     }
                    843: }
                    844: 
1.1.1.5 ! root      845: static void sunmouse_event(void *opaque,
1.1       root      846:                                int dx, int dy, int dz, int buttons_state)
                    847: {
                    848:     ChannelState *s = opaque;
                    849:     int ch;
                    850: 
1.1.1.4   root      851:     MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
                    852: 
                    853:     ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
                    854: 
                    855:     if (buttons_state & MOUSE_EVENT_LBUTTON)
                    856:         ch ^= 0x4;
                    857:     if (buttons_state & MOUSE_EVENT_MBUTTON)
                    858:         ch ^= 0x2;
                    859:     if (buttons_state & MOUSE_EVENT_RBUTTON)
                    860:         ch ^= 0x1;
                    861: 
                    862:     put_queue(s, ch);
                    863: 
                    864:     ch = dx;
                    865: 
                    866:     if (ch > 127)
                    867:         ch=127;
                    868:     else if (ch < -127)
                    869:         ch=-127;
                    870: 
                    871:     put_queue(s, ch & 0xff);
                    872: 
                    873:     ch = -dy;
                    874: 
                    875:     if (ch > 127)
                    876:         ch=127;
                    877:     else if (ch < -127)
                    878:         ch=-127;
                    879: 
                    880:     put_queue(s, ch & 0xff);
                    881: 
                    882:     // MSC protocol specify two extra motion bytes
                    883: 
                    884:     put_queue(s, 0);
                    885:     put_queue(s, 0);
1.1       root      886: }
                    887: 
1.1.1.5 ! root      888: void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
        !           889:                                int disabled)
1.1       root      890: {
                    891:     int slavio_serial_io_memory, i;
                    892:     SerialState *s;
                    893: 
                    894:     s = qemu_mallocz(sizeof(SerialState));
                    895:     if (!s)
                    896:         return;
                    897:     for (i = 0; i < 2; i++) {
1.1.1.5 ! root      898:         s->chn[i].irq = irq;
        !           899:         s->chn[i].chn = 1 - i;
        !           900:         s->chn[i].chr = NULL;
1.1       root      901:     }
                    902:     s->chn[0].otherchn = &s->chn[1];
                    903:     s->chn[1].otherchn = &s->chn[0];
                    904:     s->chn[0].type = mouse;
                    905:     s->chn[1].type = kbd;
1.1.1.5 ! root      906:     s->chn[0].disabled = disabled;
        !           907:     s->chn[1].disabled = disabled;
1.1       root      908: 
1.1.1.5 ! root      909:     slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read,
        !           910:                                                      slavio_serial_mem_write,
        !           911:                                                      s);
        !           912:     cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory);
1.1       root      913: 
1.1.1.5 ! root      914:     qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
        !           915:                                  "QEMU Sun Mouse");
1.1       root      916:     qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
1.1.1.5 ! root      917:     register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save,
        !           918:                     slavio_serial_load, s);
1.1       root      919:     qemu_register_reset(slavio_serial_reset, s);
                    920:     slavio_serial_reset(s);
                    921: }

unix.superglobalmegacorp.com

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