|
|
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);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.