Annotation of qemu/hw/i8254_common.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU 8253/8254 - common bits of emulated and KVM kernel model
                      3:  *
                      4:  * Copyright (c) 2003-2004 Fabrice Bellard
                      5:  * Copyright (c) 2012      Jan Kiszka, Siemens AG
                      6:  *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      8:  * of this software and associated documentation files (the "Software"), to deal
                      9:  * in the Software without restriction, including without limitation the rights
                     10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     11:  * copies of the Software, and to permit persons to whom the Software is
                     12:  * furnished to do so, subject to the following conditions:
                     13:  *
                     14:  * The above copyright notice and this permission notice shall be included in
                     15:  * all copies or substantial portions of the Software.
                     16:  *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     23:  * THE SOFTWARE.
                     24:  */
                     25: #include "hw.h"
                     26: #include "pc.h"
                     27: #include "isa.h"
                     28: #include "qemu-timer.h"
                     29: #include "i8254.h"
                     30: #include "i8254_internal.h"
                     31: 
                     32: /* val must be 0 or 1 */
                     33: void pit_set_gate(ISADevice *dev, int channel, int val)
                     34: {
                     35:     PITCommonState *pit = PIT_COMMON(dev);
                     36:     PITChannelState *s = &pit->channels[channel];
                     37:     PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
                     38: 
                     39:     c->set_channel_gate(pit, s, val);
                     40: }
                     41: 
                     42: /* get pit output bit */
                     43: int pit_get_out(PITChannelState *s, int64_t current_time)
                     44: {
                     45:     uint64_t d;
                     46:     int out;
                     47: 
                     48:     d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
                     49:                  get_ticks_per_sec());
                     50:     switch (s->mode) {
                     51:     default:
                     52:     case 0:
                     53:         out = (d >= s->count);
                     54:         break;
                     55:     case 1:
                     56:         out = (d < s->count);
                     57:         break;
                     58:     case 2:
                     59:         if ((d % s->count) == 0 && d != 0) {
                     60:             out = 1;
                     61:         } else {
                     62:             out = 0;
                     63:         }
                     64:         break;
                     65:     case 3:
                     66:         out = (d % s->count) < ((s->count + 1) >> 1);
                     67:         break;
                     68:     case 4:
                     69:     case 5:
                     70:         out = (d == s->count);
                     71:         break;
                     72:     }
                     73:     return out;
                     74: }
                     75: 
                     76: /* return -1 if no transition will occur.  */
                     77: int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
                     78: {
                     79:     uint64_t d, next_time, base;
                     80:     int period2;
                     81: 
                     82:     d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
                     83:                  get_ticks_per_sec());
                     84:     switch (s->mode) {
                     85:     default:
                     86:     case 0:
                     87:     case 1:
                     88:         if (d < s->count) {
                     89:             next_time = s->count;
                     90:         } else {
                     91:             return -1;
                     92:         }
                     93:         break;
                     94:     case 2:
                     95:         base = (d / s->count) * s->count;
                     96:         if ((d - base) == 0 && d != 0) {
                     97:             next_time = base + s->count;
                     98:         } else {
                     99:             next_time = base + s->count + 1;
                    100:         }
                    101:         break;
                    102:     case 3:
                    103:         base = (d / s->count) * s->count;
                    104:         period2 = ((s->count + 1) >> 1);
                    105:         if ((d - base) < period2) {
                    106:             next_time = base + period2;
                    107:         } else {
                    108:             next_time = base + s->count;
                    109:         }
                    110:         break;
                    111:     case 4:
                    112:     case 5:
                    113:         if (d < s->count) {
                    114:             next_time = s->count;
                    115:         } else if (d == s->count) {
                    116:             next_time = s->count + 1;
                    117:         } else {
                    118:             return -1;
                    119:         }
                    120:         break;
                    121:     }
                    122:     /* convert to timer units */
                    123:     next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
                    124:                                               PIT_FREQ);
                    125:     /* fix potential rounding problems */
                    126:     /* XXX: better solution: use a clock at PIT_FREQ Hz */
                    127:     if (next_time <= current_time) {
                    128:         next_time = current_time + 1;
                    129:     }
                    130:     return next_time;
                    131: }
                    132: 
                    133: void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
                    134:                                  PITChannelInfo *info)
                    135: {
                    136:     info->gate = sc->gate;
                    137:     info->mode = sc->mode;
                    138:     info->initial_count = sc->count;
                    139:     info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock));
                    140: }
                    141: 
                    142: void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
                    143: {
                    144:     PITCommonState *pit = PIT_COMMON(dev);
                    145:     PITChannelState *s = &pit->channels[channel];
                    146:     PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
                    147: 
                    148:     c->get_channel_info(pit, s, info);
                    149: }
                    150: 
                    151: void pit_reset_common(PITCommonState *pit)
                    152: {
                    153:     PITChannelState *s;
                    154:     int i;
                    155: 
                    156:     for (i = 0; i < 3; i++) {
                    157:         s = &pit->channels[i];
                    158:         s->mode = 3;
                    159:         s->gate = (i != 2);
                    160:         s->count_load_time = qemu_get_clock_ns(vm_clock);
                    161:         s->count = 0x10000;
                    162:         if (i == 0 && !s->irq_disabled) {
                    163:             s->next_transition_time =
                    164:                 pit_get_next_transition_time(s, s->count_load_time);
                    165:         }
                    166:     }
                    167: }
                    168: 
                    169: static int pit_init_common(ISADevice *dev)
                    170: {
                    171:     PITCommonState *pit = PIT_COMMON(dev);
                    172:     PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
                    173:     int ret;
                    174: 
                    175:     ret = c->init(pit);
                    176:     if (ret < 0) {
                    177:         return ret;
                    178:     }
                    179: 
                    180:     isa_register_ioport(dev, &pit->ioports, pit->iobase);
                    181: 
                    182:     qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
                    183: 
                    184:     return 0;
                    185: }
                    186: 
                    187: static const VMStateDescription vmstate_pit_channel = {
                    188:     .name = "pit channel",
                    189:     .version_id = 2,
                    190:     .minimum_version_id = 2,
                    191:     .minimum_version_id_old = 2,
                    192:     .fields = (VMStateField[]) {
                    193:         VMSTATE_INT32(count, PITChannelState),
                    194:         VMSTATE_UINT16(latched_count, PITChannelState),
                    195:         VMSTATE_UINT8(count_latched, PITChannelState),
                    196:         VMSTATE_UINT8(status_latched, PITChannelState),
                    197:         VMSTATE_UINT8(status, PITChannelState),
                    198:         VMSTATE_UINT8(read_state, PITChannelState),
                    199:         VMSTATE_UINT8(write_state, PITChannelState),
                    200:         VMSTATE_UINT8(write_latch, PITChannelState),
                    201:         VMSTATE_UINT8(rw_mode, PITChannelState),
                    202:         VMSTATE_UINT8(mode, PITChannelState),
                    203:         VMSTATE_UINT8(bcd, PITChannelState),
                    204:         VMSTATE_UINT8(gate, PITChannelState),
                    205:         VMSTATE_INT64(count_load_time, PITChannelState),
                    206:         VMSTATE_INT64(next_transition_time, PITChannelState),
                    207:         VMSTATE_END_OF_LIST()
                    208:     }
                    209: };
                    210: 
                    211: static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
                    212: {
                    213:     PITCommonState *pit = opaque;
                    214:     PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
                    215:     PITChannelState *s;
                    216:     int i;
                    217: 
                    218:     if (version_id != 1) {
                    219:         return -EINVAL;
                    220:     }
                    221: 
                    222:     for (i = 0; i < 3; i++) {
                    223:         s = &pit->channels[i];
                    224:         s->count = qemu_get_be32(f);
                    225:         qemu_get_be16s(f, &s->latched_count);
                    226:         qemu_get_8s(f, &s->count_latched);
                    227:         qemu_get_8s(f, &s->status_latched);
                    228:         qemu_get_8s(f, &s->status);
                    229:         qemu_get_8s(f, &s->read_state);
                    230:         qemu_get_8s(f, &s->write_state);
                    231:         qemu_get_8s(f, &s->write_latch);
                    232:         qemu_get_8s(f, &s->rw_mode);
                    233:         qemu_get_8s(f, &s->mode);
                    234:         qemu_get_8s(f, &s->bcd);
                    235:         qemu_get_8s(f, &s->gate);
                    236:         s->count_load_time = qemu_get_be64(f);
                    237:         s->irq_disabled = 0;
                    238:         if (i == 0) {
                    239:             s->next_transition_time = qemu_get_be64(f);
                    240:         }
                    241:     }
                    242:     if (c->post_load) {
                    243:         c->post_load(pit);
                    244:     }
                    245:     return 0;
                    246: }
                    247: 
                    248: static void pit_dispatch_pre_save(void *opaque)
                    249: {
                    250:     PITCommonState *s = opaque;
                    251:     PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
                    252: 
                    253:     if (c->pre_save) {
                    254:         c->pre_save(s);
                    255:     }
                    256: }
                    257: 
                    258: static int pit_dispatch_post_load(void *opaque, int version_id)
                    259: {
                    260:     PITCommonState *s = opaque;
                    261:     PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
                    262: 
                    263:     if (c->post_load) {
                    264:         c->post_load(s);
                    265:     }
                    266:     return 0;
                    267: }
                    268: 
                    269: static const VMStateDescription vmstate_pit_common = {
                    270:     .name = "i8254",
                    271:     .version_id = 3,
                    272:     .minimum_version_id = 2,
                    273:     .minimum_version_id_old = 1,
                    274:     .load_state_old = pit_load_old,
                    275:     .pre_save = pit_dispatch_pre_save,
                    276:     .post_load = pit_dispatch_post_load,
                    277:     .fields = (VMStateField[]) {
                    278:         VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
                    279:         VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
                    280:                              vmstate_pit_channel, PITChannelState),
                    281:         VMSTATE_INT64(channels[0].next_transition_time,
                    282:                       PITCommonState), /* formerly irq_timer */
                    283:         VMSTATE_END_OF_LIST()
                    284:     }
                    285: };
                    286: 
                    287: static void pit_common_class_init(ObjectClass *klass, void *data)
                    288: {
                    289:     ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
                    290:     DeviceClass *dc = DEVICE_CLASS(klass);
                    291: 
                    292:     ic->init = pit_init_common;
                    293:     dc->vmsd = &vmstate_pit_common;
                    294:     dc->no_user = 1;
                    295: }
                    296: 
                    297: static TypeInfo pit_common_type = {
                    298:     .name          = TYPE_PIT_COMMON,
                    299:     .parent        = TYPE_ISA_DEVICE,
                    300:     .instance_size = sizeof(PITCommonState),
                    301:     .class_size    = sizeof(PITCommonClass),
                    302:     .class_init    = pit_common_class_init,
                    303:     .abstract      = true,
                    304: };
                    305: 
                    306: static void register_devices(void)
                    307: {
                    308:     type_register_static(&pit_common_type);
                    309: }
                    310: 
                    311: type_init(register_devices);

unix.superglobalmegacorp.com

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