qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

etraxfs_ser.c (7224B)


      1 /*
      2  * QEMU ETRAX System Emulator
      3  *
      4  * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
      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 
     25 #include "qemu/osdep.h"
     26 #include "hw/irq.h"
     27 #include "hw/qdev-properties.h"
     28 #include "hw/qdev-properties-system.h"
     29 #include "hw/sysbus.h"
     30 #include "chardev/char-fe.h"
     31 #include "qemu/log.h"
     32 #include "qemu/module.h"
     33 #include "qom/object.h"
     34 
     35 #define D(x)
     36 
     37 #define RW_TR_CTRL     (0x00 / 4)
     38 #define RW_TR_DMA_EN   (0x04 / 4)
     39 #define RW_REC_CTRL    (0x08 / 4)
     40 #define RW_DOUT        (0x1c / 4)
     41 #define RS_STAT_DIN    (0x20 / 4)
     42 #define R_STAT_DIN     (0x24 / 4)
     43 #define RW_INTR_MASK   (0x2c / 4)
     44 #define RW_ACK_INTR    (0x30 / 4)
     45 #define R_INTR         (0x34 / 4)
     46 #define R_MASKED_INTR  (0x38 / 4)
     47 #define R_MAX          (0x3c / 4)
     48 
     49 #define STAT_DAV     16
     50 #define STAT_TR_IDLE 22
     51 #define STAT_TR_RDY  24
     52 
     53 #define TYPE_ETRAX_FS_SERIAL "etraxfs-serial"
     54 typedef struct ETRAXSerial ETRAXSerial;
     55 DECLARE_INSTANCE_CHECKER(ETRAXSerial, ETRAX_SERIAL,
     56                          TYPE_ETRAX_FS_SERIAL)
     57 
     58 struct ETRAXSerial {
     59     SysBusDevice parent_obj;
     60 
     61     MemoryRegion mmio;
     62     CharBackend chr;
     63     qemu_irq irq;
     64 
     65     int pending_tx;
     66 
     67     uint8_t rx_fifo[16];
     68     unsigned int rx_fifo_pos;
     69     unsigned int rx_fifo_len;
     70 
     71     /* Control registers.  */
     72     uint32_t regs[R_MAX];
     73 };
     74 
     75 static void ser_update_irq(ETRAXSerial *s)
     76 {
     77 
     78     if (s->rx_fifo_len) {
     79         s->regs[R_INTR] |= 8;
     80     } else {
     81         s->regs[R_INTR] &= ~8;
     82     }
     83 
     84     s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
     85     qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
     86 }
     87 
     88 static uint64_t
     89 ser_read(void *opaque, hwaddr addr, unsigned int size)
     90 {
     91     ETRAXSerial *s = opaque;
     92     uint32_t r = 0;
     93 
     94     addr >>= 2;
     95     switch (addr)
     96     {
     97         case R_STAT_DIN:
     98             r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
     99             if (s->rx_fifo_len) {
    100                 r |= 1 << STAT_DAV;
    101             }
    102             r |= 1 << STAT_TR_RDY;
    103             r |= 1 << STAT_TR_IDLE;
    104             break;
    105         case RS_STAT_DIN:
    106             r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
    107             if (s->rx_fifo_len) {
    108                 r |= 1 << STAT_DAV;
    109                 s->rx_fifo_len--;
    110             }
    111             r |= 1 << STAT_TR_RDY;
    112             r |= 1 << STAT_TR_IDLE;
    113             break;
    114         default:
    115             r = s->regs[addr];
    116             D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
    117             break;
    118     }
    119     return r;
    120 }
    121 
    122 static void
    123 ser_write(void *opaque, hwaddr addr,
    124           uint64_t val64, unsigned int size)
    125 {
    126     ETRAXSerial *s = opaque;
    127     uint32_t value = val64;
    128     unsigned char ch = val64;
    129 
    130     D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
    131     addr >>= 2;
    132     switch (addr)
    133     {
    134         case RW_DOUT:
    135             /* XXX this blocks entire thread. Rewrite to use
    136              * qemu_chr_fe_write and background I/O callbacks */
    137             qemu_chr_fe_write_all(&s->chr, &ch, 1);
    138             s->regs[R_INTR] |= 3;
    139             s->pending_tx = 1;
    140             s->regs[addr] = value;
    141             break;
    142         case RW_ACK_INTR:
    143             if (s->pending_tx) {
    144                 value &= ~1;
    145                 s->pending_tx = 0;
    146                 D(qemu_log("fixedup value=%x r_intr=%x\n",
    147                            value, s->regs[R_INTR]));
    148             }
    149             s->regs[addr] = value;
    150             s->regs[R_INTR] &= ~value;
    151             D(printf("r_intr=%x\n", s->regs[R_INTR]));
    152             break;
    153         default:
    154             s->regs[addr] = value;
    155             break;
    156     }
    157     ser_update_irq(s);
    158 }
    159 
    160 static const MemoryRegionOps ser_ops = {
    161     .read = ser_read,
    162     .write = ser_write,
    163     .endianness = DEVICE_NATIVE_ENDIAN,
    164     .valid = {
    165         .min_access_size = 4,
    166         .max_access_size = 4
    167     }
    168 };
    169 
    170 static Property etraxfs_ser_properties[] = {
    171     DEFINE_PROP_CHR("chardev", ETRAXSerial, chr),
    172     DEFINE_PROP_END_OF_LIST(),
    173 };
    174 
    175 static void serial_receive(void *opaque, const uint8_t *buf, int size)
    176 {
    177     ETRAXSerial *s = opaque;
    178     int i;
    179 
    180     /* Got a byte.  */
    181     if (s->rx_fifo_len >= 16) {
    182         D(qemu_log("WARNING: UART dropped char.\n"));
    183         return;
    184     }
    185 
    186     for (i = 0; i < size; i++) { 
    187         s->rx_fifo[s->rx_fifo_pos] = buf[i];
    188         s->rx_fifo_pos++;
    189         s->rx_fifo_pos &= 15;
    190         s->rx_fifo_len++;
    191     }
    192 
    193     ser_update_irq(s);
    194 }
    195 
    196 static int serial_can_receive(void *opaque)
    197 {
    198     ETRAXSerial *s = opaque;
    199 
    200     /* Is the receiver enabled?  */
    201     if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
    202         return 0;
    203     }
    204 
    205     return sizeof(s->rx_fifo) - s->rx_fifo_len;
    206 }
    207 
    208 static void serial_event(void *opaque, QEMUChrEvent event)
    209 {
    210 
    211 }
    212 
    213 static void etraxfs_ser_reset(DeviceState *d)
    214 {
    215     ETRAXSerial *s = ETRAX_SERIAL(d);
    216 
    217     /* transmitter begins ready and idle.  */
    218     s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
    219     s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
    220 
    221     s->regs[RW_REC_CTRL] = 0x10000;
    222 
    223 }
    224 
    225 static void etraxfs_ser_init(Object *obj)
    226 {
    227     ETRAXSerial *s = ETRAX_SERIAL(obj);
    228     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
    229 
    230     sysbus_init_irq(dev, &s->irq);
    231     memory_region_init_io(&s->mmio, obj, &ser_ops, s,
    232                           "etraxfs-serial", R_MAX * 4);
    233     sysbus_init_mmio(dev, &s->mmio);
    234 }
    235 
    236 static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
    237 {
    238     ETRAXSerial *s = ETRAX_SERIAL(dev);
    239 
    240     qemu_chr_fe_set_handlers(&s->chr,
    241                              serial_can_receive, serial_receive,
    242                              serial_event, NULL, s, NULL, true);
    243 }
    244 
    245 static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
    246 {
    247     DeviceClass *dc = DEVICE_CLASS(klass);
    248 
    249     dc->reset = etraxfs_ser_reset;
    250     device_class_set_props(dc, etraxfs_ser_properties);
    251     dc->realize = etraxfs_ser_realize;
    252 }
    253 
    254 static const TypeInfo etraxfs_ser_info = {
    255     .name          = TYPE_ETRAX_FS_SERIAL,
    256     .parent        = TYPE_SYS_BUS_DEVICE,
    257     .instance_size = sizeof(ETRAXSerial),
    258     .instance_init = etraxfs_ser_init,
    259     .class_init    = etraxfs_ser_class_init,
    260 };
    261 
    262 static void etraxfs_serial_register_types(void)
    263 {
    264     type_register_static(&etraxfs_ser_info);
    265 }
    266 
    267 type_init(etraxfs_serial_register_types)