Commit 80cabfad16384ca47f783a7c494bd1c3c6e3c4bc

Authored by bellard
1 parent 38ca2abc

separated more devices from emulator


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@656 c046a42c-6fe2-441c-8c8c-71466251a162

Too many changes to show.

To preserve performance only 8 of 10 files are displayed.

Makefile.target
1 1 include config.mak
2 2  
3 3 TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
4   -VPATH=$(SRC_PATH):$(TARGET_PATH)
  4 +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
5 5 CFLAGS=-Wall -O2 -g
6 6 LDFLAGS=-g
7 7 LIBS=
... ... @@ -204,7 +204,8 @@ ifeq ($(ARCH),alpha)
204 204 endif
205 205  
206 206 # must use static linking to avoid leaving stuff in virtual address space
207   -VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o
  207 +VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \
  208 + fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
208 209 ifeq ($(TARGET_ARCH), ppc)
209 210 VL_OBJS+= hw.o
210 211 endif
... ...
hw/i8254.c 0 → 100644
  1 +/*
  2 + * QEMU 8253/8254 interval timer emulation
  3 + *
  4 + * Copyright (c) 2003-2004 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +#define RW_STATE_LSB 0
  47 +#define RW_STATE_MSB 1
  48 +#define RW_STATE_WORD0 2
  49 +#define RW_STATE_WORD1 3
  50 +#define RW_STATE_LATCHED_WORD0 4
  51 +#define RW_STATE_LATCHED_WORD1 5
  52 +
  53 +PITChannelState pit_channels[3];
  54 +
  55 +static int pit_get_count(PITChannelState *s)
  56 +{
  57 + uint64_t d;
  58 + int counter;
  59 +
  60 + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec);
  61 + switch(s->mode) {
  62 + case 0:
  63 + case 1:
  64 + case 4:
  65 + case 5:
  66 + counter = (s->count - d) & 0xffff;
  67 + break;
  68 + case 3:
  69 + /* XXX: may be incorrect for odd counts */
  70 + counter = s->count - ((2 * d) % s->count);
  71 + break;
  72 + default:
  73 + counter = s->count - (d % s->count);
  74 + break;
  75 + }
  76 + return counter;
  77 +}
  78 +
  79 +/* get pit output bit */
  80 +int pit_get_out(PITChannelState *s)
  81 +{
  82 + uint64_t d;
  83 + int out;
  84 +
  85 + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec);
  86 + switch(s->mode) {
  87 + default:
  88 + case 0:
  89 + out = (d >= s->count);
  90 + break;
  91 + case 1:
  92 + out = (d < s->count);
  93 + break;
  94 + case 2:
  95 + if ((d % s->count) == 0 && d != 0)
  96 + out = 1;
  97 + else
  98 + out = 0;
  99 + break;
  100 + case 3:
  101 + out = (d % s->count) < ((s->count + 1) >> 1);
  102 + break;
  103 + case 4:
  104 + case 5:
  105 + out = (d == s->count);
  106 + break;
  107 + }
  108 + return out;
  109 +}
  110 +
  111 +/* get the number of 0 to 1 transitions we had since we call this
  112 + function */
  113 +/* XXX: maybe better to use ticks precision to avoid getting edges
  114 + twice if checks are done at very small intervals */
  115 +int pit_get_out_edges(PITChannelState *s)
  116 +{
  117 + uint64_t d1, d2;
  118 + int64_t ticks;
  119 + int ret, v;
  120 +
  121 + ticks = cpu_get_ticks();
  122 + d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time,
  123 + PIT_FREQ, ticks_per_sec);
  124 + d2 = muldiv64(ticks - s->count_load_time,
  125 + PIT_FREQ, ticks_per_sec);
  126 + s->count_last_edge_check_time = ticks;
  127 + switch(s->mode) {
  128 + default:
  129 + case 0:
  130 + if (d1 < s->count && d2 >= s->count)
  131 + ret = 1;
  132 + else
  133 + ret = 0;
  134 + break;
  135 + case 1:
  136 + ret = 0;
  137 + break;
  138 + case 2:
  139 + d1 /= s->count;
  140 + d2 /= s->count;
  141 + ret = d2 - d1;
  142 + break;
  143 + case 3:
  144 + v = s->count - ((s->count + 1) >> 1);
  145 + d1 = (d1 + v) / s->count;
  146 + d2 = (d2 + v) / s->count;
  147 + ret = d2 - d1;
  148 + break;
  149 + case 4:
  150 + case 5:
  151 + if (d1 < s->count && d2 >= s->count)
  152 + ret = 1;
  153 + else
  154 + ret = 0;
  155 + break;
  156 + }
  157 + return ret;
  158 +}
  159 +
  160 +/* val must be 0 or 1 */
  161 +void pit_set_gate(PITChannelState *s, int val)
  162 +{
  163 + switch(s->mode) {
  164 + default:
  165 + case 0:
  166 + case 4:
  167 + /* XXX: just disable/enable counting */
  168 + break;
  169 + case 1:
  170 + case 5:
  171 + if (s->gate < val) {
  172 + /* restart counting on rising edge */
  173 + s->count_load_time = cpu_get_ticks();
  174 + s->count_last_edge_check_time = s->count_load_time;
  175 + }
  176 + break;
  177 + case 2:
  178 + case 3:
  179 + if (s->gate < val) {
  180 + /* restart counting on rising edge */
  181 + s->count_load_time = cpu_get_ticks();
  182 + s->count_last_edge_check_time = s->count_load_time;
  183 + }
  184 + /* XXX: disable/enable counting */
  185 + break;
  186 + }
  187 + s->gate = val;
  188 +}
  189 +
  190 +static inline void pit_load_count(PITChannelState *s, int val)
  191 +{
  192 + if (val == 0)
  193 + val = 0x10000;
  194 + s->count_load_time = cpu_get_ticks();
  195 + s->count_last_edge_check_time = s->count_load_time;
  196 + s->count = val;
  197 + if (s == &pit_channels[0] && val <= pit_min_timer_count) {
  198 + fprintf(stderr,
  199 + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n",
  200 + PIT_FREQ / pit_min_timer_count);
  201 + }
  202 +}
  203 +
  204 +void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  205 +{
  206 + int channel, access;
  207 + PITChannelState *s;
  208 +
  209 + addr &= 3;
  210 + if (addr == 3) {
  211 + channel = val >> 6;
  212 + if (channel == 3)
  213 + return;
  214 + s = &pit_channels[channel];
  215 + access = (val >> 4) & 3;
  216 + switch(access) {
  217 + case 0:
  218 + s->latched_count = pit_get_count(s);
  219 + s->rw_state = RW_STATE_LATCHED_WORD0;
  220 + break;
  221 + default:
  222 + s->mode = (val >> 1) & 7;
  223 + s->bcd = val & 1;
  224 + s->rw_state = access - 1 + RW_STATE_LSB;
  225 + break;
  226 + }
  227 + } else {
  228 + s = &pit_channels[addr];
  229 + switch(s->rw_state) {
  230 + case RW_STATE_LSB:
  231 + pit_load_count(s, val);
  232 + break;
  233 + case RW_STATE_MSB:
  234 + pit_load_count(s, val << 8);
  235 + break;
  236 + case RW_STATE_WORD0:
  237 + case RW_STATE_WORD1:
  238 + if (s->rw_state & 1) {
  239 + pit_load_count(s, (s->latched_count & 0xff) | (val << 8));
  240 + } else {
  241 + s->latched_count = val;
  242 + }
  243 + s->rw_state ^= 1;
  244 + break;
  245 + }
  246 + }
  247 +}
  248 +
  249 +uint32_t pit_ioport_read(CPUState *env, uint32_t addr)
  250 +{
  251 + int ret, count;
  252 + PITChannelState *s;
  253 +
  254 + addr &= 3;
  255 + s = &pit_channels[addr];
  256 + switch(s->rw_state) {
  257 + case RW_STATE_LSB:
  258 + case RW_STATE_MSB:
  259 + case RW_STATE_WORD0:
  260 + case RW_STATE_WORD1:
  261 + count = pit_get_count(s);
  262 + if (s->rw_state & 1)
  263 + ret = (count >> 8) & 0xff;
  264 + else
  265 + ret = count & 0xff;
  266 + if (s->rw_state & 2)
  267 + s->rw_state ^= 1;
  268 + break;
  269 + default:
  270 + case RW_STATE_LATCHED_WORD0:
  271 + case RW_STATE_LATCHED_WORD1:
  272 + if (s->rw_state & 1)
  273 + ret = s->latched_count >> 8;
  274 + else
  275 + ret = s->latched_count & 0xff;
  276 + s->rw_state ^= 1;
  277 + break;
  278 + }
  279 + return ret;
  280 +}
  281 +
  282 +void pit_init(void)
  283 +{
  284 + PITChannelState *s;
  285 + int i;
  286 +
  287 + for(i = 0;i < 3; i++) {
  288 + s = &pit_channels[i];
  289 + s->mode = 3;
  290 + s->gate = (i != 2);
  291 + pit_load_count(s, 0);
  292 + }
  293 +
  294 + register_ioport_write(0x40, 4, pit_ioport_write, 1);
  295 + register_ioport_read(0x40, 3, pit_ioport_read, 1);
  296 +}
  297 +
... ...
hw/i8259.c 0 → 100644
  1 +/*
  2 + * QEMU 8259 interrupt controller emulation
  3 + *
  4 + * Copyright (c) 2003-2004 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +/* debug PIC */
  47 +//#define DEBUG_PIC
  48 +
  49 +typedef struct PicState {
  50 + uint8_t last_irr; /* edge detection */
  51 + uint8_t irr; /* interrupt request register */
  52 + uint8_t imr; /* interrupt mask register */
  53 + uint8_t isr; /* interrupt service register */
  54 + uint8_t priority_add; /* highest irq priority */
  55 + uint8_t irq_base;
  56 + uint8_t read_reg_select;
  57 + uint8_t poll;
  58 + uint8_t special_mask;
  59 + uint8_t init_state;
  60 + uint8_t auto_eoi;
  61 + uint8_t rotate_on_auto_eoi;
  62 + uint8_t special_fully_nested_mode;
  63 + uint8_t init4; /* true if 4 byte init */
  64 +} PicState;
  65 +
  66 +/* 0 is master pic, 1 is slave pic */
  67 +PicState pics[2];
  68 +int pic_irq_requested;
  69 +
  70 +/* set irq level. If an edge is detected, then the IRR is set to 1 */
  71 +static inline void pic_set_irq1(PicState *s, int irq, int level)
  72 +{
  73 + int mask;
  74 + mask = 1 << irq;
  75 + if (level) {
  76 + if ((s->last_irr & mask) == 0)
  77 + s->irr |= mask;
  78 + s->last_irr |= mask;
  79 + } else {
  80 + s->last_irr &= ~mask;
  81 + }
  82 +}
  83 +
  84 +/* return the highest priority found in mask (highest = smallest
  85 + number). Return 8 if no irq */
  86 +static inline int get_priority(PicState *s, int mask)
  87 +{
  88 + int priority;
  89 + if (mask == 0)
  90 + return 8;
  91 + priority = 0;
  92 + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
  93 + priority++;
  94 + return priority;
  95 +}
  96 +
  97 +/* return the pic wanted interrupt. return -1 if none */
  98 +static int pic_get_irq(PicState *s)
  99 +{
  100 + int mask, cur_priority, priority;
  101 +
  102 + mask = s->irr & ~s->imr;
  103 + priority = get_priority(s, mask);
  104 + if (priority == 8)
  105 + return -1;
  106 + /* compute current priority. If special fully nested mode on the
  107 + master, the IRQ coming from the slave is not taken into account
  108 + for the priority computation. */
  109 + mask = s->isr;
  110 + if (s->special_fully_nested_mode && s == &pics[0])
  111 + mask &= ~(1 << 2);
  112 + cur_priority = get_priority(s, mask);
  113 + if (priority < cur_priority) {
  114 + /* higher priority found: an irq should be generated */
  115 + return (priority + s->priority_add) & 7;
  116 + } else {
  117 + return -1;
  118 + }
  119 +}
  120 +
  121 +/* raise irq to CPU if necessary. must be called every time the active
  122 + irq may change */
  123 +void pic_update_irq(void)
  124 +{
  125 + int irq2, irq;
  126 +
  127 + /* first look at slave pic */
  128 + irq2 = pic_get_irq(&pics[1]);
  129 + if (irq2 >= 0) {
  130 + /* if irq request by slave pic, signal master PIC */
  131 + pic_set_irq1(&pics[0], 2, 1);
  132 + pic_set_irq1(&pics[0], 2, 0);
  133 + }
  134 + /* look at requested irq */
  135 + irq = pic_get_irq(&pics[0]);
  136 + if (irq >= 0) {
  137 + if (irq == 2) {
  138 + /* from slave pic */
  139 + pic_irq_requested = 8 + irq2;
  140 + } else {
  141 + /* from master pic */
  142 + pic_irq_requested = irq;
  143 + }
  144 +#if defined(DEBUG_PIC)
  145 + {
  146 + int i;
  147 + for(i = 0; i < 2; i++) {
  148 + printf("pic%d: imr=%x irr=%x padd=%d\n",
  149 + i, pics[i].imr, pics[i].irr, pics[i].priority_add);
  150 +
  151 + }
  152 + }
  153 + printf("pic: cpu_interrupt req=%d\n", pic_irq_requested);
  154 +#endif
  155 + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
  156 + }
  157 +}
  158 +
  159 +#ifdef DEBUG_IRQ_LATENCY
  160 +int64_t irq_time[16];
  161 +int64_t cpu_get_ticks(void);
  162 +#endif
  163 +#if defined(DEBUG_PIC)
  164 +int irq_level[16];
  165 +#endif
  166 +
  167 +void pic_set_irq(int irq, int level)
  168 +{
  169 +#if defined(DEBUG_PIC)
  170 + if (level != irq_level[irq]) {
  171 + printf("pic_set_irq: irq=%d level=%d\n", irq, level);
  172 + irq_level[irq] = level;
  173 + }
  174 +#endif
  175 +#ifdef DEBUG_IRQ_LATENCY
  176 + if (level) {
  177 + irq_time[irq] = cpu_get_ticks();
  178 + }
  179 +#endif
  180 + pic_set_irq1(&pics[irq >> 3], irq & 7, level);
  181 + pic_update_irq();
  182 +}
  183 +
  184 +/* acknowledge interrupt 'irq' */
  185 +static inline void pic_intack(PicState *s, int irq)
  186 +{
  187 + if (s->auto_eoi) {
  188 + if (s->rotate_on_auto_eoi)
  189 + s->priority_add = (irq + 1) & 7;
  190 + } else {
  191 + s->isr |= (1 << irq);
  192 + }
  193 + s->irr &= ~(1 << irq);
  194 +}
  195 +
  196 +int cpu_x86_get_pic_interrupt(CPUState *env)
  197 +{
  198 + int irq, irq2, intno;
  199 +
  200 + /* signal the pic that the irq was acked by the CPU */
  201 + irq = pic_irq_requested;
  202 +#ifdef DEBUG_IRQ_LATENCY
  203 + printf("IRQ%d latency=%0.3fus\n",
  204 + irq,
  205 + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec);
  206 +#endif
  207 +#if defined(DEBUG_PIC)
  208 + printf("pic_interrupt: irq=%d\n", irq);
  209 +#endif
  210 +
  211 + if (irq >= 8) {
  212 + irq2 = irq & 7;
  213 + pic_intack(&pics[1], irq2);
  214 + irq = 2;
  215 + intno = pics[1].irq_base + irq2;
  216 + } else {
  217 + intno = pics[0].irq_base + irq;
  218 + }
  219 + pic_intack(&pics[0], irq);
  220 + return intno;
  221 +}
  222 +
  223 +void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  224 +{
  225 + PicState *s;
  226 + int priority, cmd, irq;
  227 +
  228 +#ifdef DEBUG_PIC
  229 + printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
  230 +#endif
  231 + s = &pics[addr >> 7];
  232 + addr &= 1;
  233 + if (addr == 0) {
  234 + if (val & 0x10) {
  235 + /* init */
  236 + memset(s, 0, sizeof(PicState));
  237 + s->init_state = 1;
  238 + s->init4 = val & 1;
  239 + if (val & 0x02)
  240 + hw_error("single mode not supported");
  241 + if (val & 0x08)
  242 + hw_error("level sensitive irq not supported");
  243 + } else if (val & 0x08) {
  244 + if (val & 0x04)
  245 + s->poll = 1;
  246 + if (val & 0x02)
  247 + s->read_reg_select = val & 1;
  248 + if (val & 0x40)
  249 + s->special_mask = (val >> 5) & 1;
  250 + } else {
  251 + cmd = val >> 5;
  252 + switch(cmd) {
  253 + case 0:
  254 + case 4:
  255 + s->rotate_on_auto_eoi = cmd >> 2;
  256 + break;
  257 + case 1: /* end of interrupt */
  258 + case 5:
  259 + priority = get_priority(s, s->isr);
  260 + if (priority != 8) {
  261 + irq = (priority + s->priority_add) & 7;
  262 + s->isr &= ~(1 << irq);
  263 + if (cmd == 5)
  264 + s->priority_add = (irq + 1) & 7;
  265 + pic_update_irq();
  266 + }
  267 + break;
  268 + case 3:
  269 + irq = val & 7;
  270 + s->isr &= ~(1 << irq);
  271 + pic_update_irq();
  272 + break;
  273 + case 6:
  274 + s->priority_add = (val + 1) & 7;
  275 + pic_update_irq();
  276 + break;
  277 + case 7:
  278 + irq = val & 7;
  279 + s->isr &= ~(1 << irq);
  280 + s->priority_add = (irq + 1) & 7;
  281 + pic_update_irq();
  282 + break;
  283 + default:
  284 + /* no operation */
  285 + break;
  286 + }
  287 + }
  288 + } else {
  289 + switch(s->init_state) {
  290 + case 0:
  291 + /* normal mode */
  292 + s->imr = val;
  293 + pic_update_irq();
  294 + break;
  295 + case 1:
  296 + s->irq_base = val & 0xf8;
  297 + s->init_state = 2;
  298 + break;
  299 + case 2:
  300 + if (s->init4) {
  301 + s->init_state = 3;
  302 + } else {
  303 + s->init_state = 0;
  304 + }
  305 + break;
  306 + case 3:
  307 + s->special_fully_nested_mode = (val >> 4) & 1;
  308 + s->auto_eoi = (val >> 1) & 1;
  309 + s->init_state = 0;
  310 + break;
  311 + }
  312 + }
  313 +}
  314 +
  315 +static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
  316 +{
  317 + int ret;
  318 +
  319 + ret = pic_get_irq(s);
  320 + if (ret >= 0) {
  321 + if (addr1 >> 7) {
  322 + pics[0].isr &= ~(1 << 2);
  323 + pics[0].irr &= ~(1 << 2);
  324 + }
  325 + s->irr &= ~(1 << ret);
  326 + s->isr &= ~(1 << ret);
  327 + if (addr1 >> 7 || ret != 2)
  328 + pic_update_irq();
  329 + } else {
  330 + ret = 0x07;
  331 + pic_update_irq();
  332 + }
  333 +
  334 + return ret;
  335 +}
  336 +
  337 +uint32_t pic_ioport_read(CPUState *env, uint32_t addr1)
  338 +{
  339 + PicState *s;
  340 + unsigned int addr;
  341 + int ret;
  342 +
  343 + addr = addr1;
  344 + s = &pics[addr >> 7];
  345 + addr &= 1;
  346 + if (s->poll) {
  347 + ret = pic_poll_read(s, addr1);
  348 + s->poll = 0;
  349 + } else {
  350 + if (addr == 0) {
  351 + if (s->read_reg_select)
  352 + ret = s->isr;
  353 + else
  354 + ret = s->irr;
  355 + } else {
  356 + ret = s->imr;
  357 + }
  358 + }
  359 +#ifdef DEBUG_PIC
  360 + printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
  361 +#endif
  362 + return ret;
  363 +}
  364 +
  365 +/* memory mapped interrupt status */
  366 +uint32_t pic_intack_read(CPUState *env)
  367 +{
  368 + int ret;
  369 +
  370 + ret = pic_poll_read(&pics[0], 0x00);
  371 + if (ret == 2)
  372 + ret = pic_poll_read(&pics[1], 0x80) + 8;
  373 + /* Prepare for ISR read */
  374 + pics[0].read_reg_select = 1;
  375 +
  376 + return ret;
  377 +}
  378 +
  379 +void pic_init(void)
  380 +{
  381 +#if defined (TARGET_I386) || defined (TARGET_PPC)
  382 + register_ioport_write(0x20, 2, pic_ioport_write, 1);
  383 + register_ioport_read(0x20, 2, pic_ioport_read, 1);
  384 + register_ioport_write(0xa0, 2, pic_ioport_write, 1);
  385 + register_ioport_read(0xa0, 2, pic_ioport_read, 1);
  386 +#endif
  387 +}
  388 +
... ...
hw/mc146818rtc.c 0 → 100644
  1 +/*
  2 + * QEMU MC146818 RTC emulation
  3 + *
  4 + * Copyright (c) 2003-2004 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +//#define DEBUG_CMOS
  47 +
  48 +#define RTC_SECONDS 0
  49 +#define RTC_SECONDS_ALARM 1
  50 +#define RTC_MINUTES 2
  51 +#define RTC_MINUTES_ALARM 3
  52 +#define RTC_HOURS 4
  53 +#define RTC_HOURS_ALARM 5
  54 +#define RTC_ALARM_DONT_CARE 0xC0
  55 +
  56 +#define RTC_DAY_OF_WEEK 6
  57 +#define RTC_DAY_OF_MONTH 7
  58 +#define RTC_MONTH 8
  59 +#define RTC_YEAR 9
  60 +
  61 +#define RTC_REG_A 10
  62 +#define RTC_REG_B 11
  63 +#define RTC_REG_C 12
  64 +#define RTC_REG_D 13
  65 +
  66 +/* PC cmos mappings */
  67 +#define REG_IBM_CENTURY_BYTE 0x32
  68 +#define REG_IBM_PS2_CENTURY_BYTE 0x37
  69 +
  70 +RTCState rtc_state;
  71 +
  72 +static void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data)
  73 +{
  74 + RTCState *s = &rtc_state;
  75 +
  76 + if ((addr & 1) == 0) {
  77 + s->cmos_index = data & 0x7f;
  78 + } else {
  79 +#ifdef DEBUG_CMOS
  80 + printf("cmos: write index=0x%02x val=0x%02x\n",
  81 + s->cmos_index, data);
  82 +#endif
  83 + switch(addr) {
  84 + case RTC_SECONDS_ALARM:
  85 + case RTC_MINUTES_ALARM:
  86 + case RTC_HOURS_ALARM:
  87 + /* XXX: not supported */
  88 + s->cmos_data[s->cmos_index] = data;
  89 + break;
  90 + case RTC_SECONDS:
  91 + case RTC_MINUTES:
  92 + case RTC_HOURS:
  93 + case RTC_DAY_OF_WEEK:
  94 + case RTC_DAY_OF_MONTH:
  95 + case RTC_MONTH:
  96 + case RTC_YEAR:
  97 + s->cmos_data[s->cmos_index] = data;
  98 + break;
  99 + case RTC_REG_A:
  100 + case RTC_REG_B:
  101 + s->cmos_data[s->cmos_index] = data;
  102 + break;
  103 + case RTC_REG_C:
  104 + case RTC_REG_D:
  105 + /* cannot write to them */
  106 + break;
  107 + default:
  108 + s->cmos_data[s->cmos_index] = data;
  109 + break;
  110 + }
  111 + }
  112 +}
  113 +
  114 +static inline int to_bcd(int a)
  115 +{
  116 + return ((a / 10) << 4) | (a % 10);
  117 +}
  118 +
  119 +static void cmos_update_time(RTCState *s)
  120 +{
  121 + struct tm *tm;
  122 + time_t ti;
  123 +
  124 + ti = time(NULL);
  125 + tm = gmtime(&ti);
  126 + s->cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec);
  127 + s->cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min);
  128 + s->cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour);
  129 + s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday);
  130 + s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday);
  131 + s->cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1);
  132 + s->cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100);
  133 + s->cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19);
  134 + s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE];
  135 +}
  136 +
  137 +static uint32_t cmos_ioport_read(CPUState *env, uint32_t addr)
  138 +{
  139 + RTCState *s = &rtc_state;
  140 + int ret;
  141 + if ((addr & 1) == 0) {
  142 + return 0xff;
  143 + } else {
  144 + switch(s->cmos_index) {
  145 + case RTC_SECONDS:
  146 + case RTC_MINUTES:
  147 + case RTC_HOURS:
  148 + case RTC_DAY_OF_WEEK:
  149 + case RTC_DAY_OF_MONTH:
  150 + case RTC_MONTH:
  151 + case RTC_YEAR:
  152 + case REG_IBM_CENTURY_BYTE:
  153 + case REG_IBM_PS2_CENTURY_BYTE:
  154 + cmos_update_time(s);
  155 + ret = s->cmos_data[s->cmos_index];
  156 + break;
  157 + case RTC_REG_A:
  158 + ret = s->cmos_data[s->cmos_index];
  159 + /* toggle update-in-progress bit for Linux (same hack as
  160 + plex86) */
  161 + s->cmos_data[RTC_REG_A] ^= 0x80;
  162 + break;
  163 + case RTC_REG_C:
  164 + ret = s->cmos_data[s->cmos_index];
  165 + pic_set_irq(s->irq, 0);
  166 + s->cmos_data[RTC_REG_C] = 0x00;
  167 + break;
  168 + default:
  169 + ret = s->cmos_data[s->cmos_index];
  170 + break;
  171 + }
  172 +#ifdef DEBUG_CMOS
  173 + printf("cmos: read index=0x%02x val=0x%02x\n",
  174 + s->cmos_index, ret);
  175 +#endif
  176 + return ret;
  177 + }
  178 +}
  179 +
  180 +void rtc_timer(void)
  181 +{
  182 + RTCState *s = &rtc_state;
  183 + if (s->cmos_data[RTC_REG_B] & 0x50) {
  184 + pic_set_irq(s->irq, 1);
  185 + }
  186 +}
  187 +
  188 +void rtc_init(int base, int irq)
  189 +{
  190 + RTCState *s = &rtc_state;
  191 +
  192 + cmos_update_time(s);
  193 +
  194 + s->irq = irq;
  195 + s->cmos_data[RTC_REG_A] = 0x26;
  196 + s->cmos_data[RTC_REG_B] = 0x02;
  197 + s->cmos_data[RTC_REG_C] = 0x00;
  198 + s->cmos_data[RTC_REG_D] = 0x80;
  199 +
  200 + register_ioport_write(base, 2, cmos_ioport_write, 1);
  201 + register_ioport_read(base, 2, cmos_ioport_read, 1);
  202 +}
  203 +
... ...
hw/ne2000.c 0 → 100644
  1 +/*
  2 + * QEMU NE2000 emulation
  3 + *
  4 + * Copyright (c) 2003-2004 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +/* debug NE2000 card */
  47 +//#define DEBUG_NE2000
  48 +
  49 +/***********************************************************/
  50 +/* ne2000 emulation */
  51 +
  52 +#define E8390_CMD 0x00 /* The command register (for all pages) */
  53 +/* Page 0 register offsets. */
  54 +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
  55 +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
  56 +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
  57 +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
  58 +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
  59 +#define EN0_TSR 0x04 /* Transmit status reg RD */
  60 +#define EN0_TPSR 0x04 /* Transmit starting page WR */
  61 +#define EN0_NCR 0x05 /* Number of collision reg RD */
  62 +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
  63 +#define EN0_FIFO 0x06 /* FIFO RD */
  64 +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
  65 +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
  66 +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
  67 +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
  68 +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
  69 +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
  70 +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
  71 +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
  72 +#define EN0_RSR 0x0c /* rx status reg RD */
  73 +#define EN0_RXCR 0x0c /* RX configuration reg WR */
  74 +#define EN0_TXCR 0x0d /* TX configuration reg WR */
  75 +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
  76 +#define EN0_DCFG 0x0e /* Data configuration reg WR */
  77 +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
  78 +#define EN0_IMR 0x0f /* Interrupt mask reg WR */
  79 +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
  80 +
  81 +#define EN1_PHYS 0x11
  82 +#define EN1_CURPAG 0x17
  83 +#define EN1_MULT 0x18
  84 +
  85 +/* Register accessed at EN_CMD, the 8390 base addr. */
  86 +#define E8390_STOP 0x01 /* Stop and reset the chip */
  87 +#define E8390_START 0x02 /* Start the chip, clear reset */
  88 +#define E8390_TRANS 0x04 /* Transmit a frame */
  89 +#define E8390_RREAD 0x08 /* Remote read */
  90 +#define E8390_RWRITE 0x10 /* Remote write */
  91 +#define E8390_NODMA 0x20 /* Remote DMA */
  92 +#define E8390_PAGE0 0x00 /* Select page chip registers */
  93 +#define E8390_PAGE1 0x40 /* using the two high-order bits */
  94 +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
  95 +
  96 +/* Bits in EN0_ISR - Interrupt status register */
  97 +#define ENISR_RX 0x01 /* Receiver, no error */
  98 +#define ENISR_TX 0x02 /* Transmitter, no error */
  99 +#define ENISR_RX_ERR 0x04 /* Receiver, with error */
  100 +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
  101 +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
  102 +#define ENISR_COUNTERS 0x20 /* Counters need emptying */
  103 +#define ENISR_RDC 0x40 /* remote dma complete */
  104 +#define ENISR_RESET 0x80 /* Reset completed */
  105 +#define ENISR_ALL 0x3f /* Interrupts we will enable */
  106 +
  107 +/* Bits in received packet status byte and EN0_RSR*/
  108 +#define ENRSR_RXOK 0x01 /* Received a good packet */
  109 +#define ENRSR_CRC 0x02 /* CRC error */
  110 +#define ENRSR_FAE 0x04 /* frame alignment error */
  111 +#define ENRSR_FO 0x08 /* FIFO overrun */
  112 +#define ENRSR_MPA 0x10 /* missed pkt */
  113 +#define ENRSR_PHY 0x20 /* physical/multicast address */
  114 +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
  115 +#define ENRSR_DEF 0x80 /* deferring */
  116 +
  117 +/* Transmitted packet status, EN0_TSR. */
  118 +#define ENTSR_PTX 0x01 /* Packet transmitted without error */
  119 +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
  120 +#define ENTSR_COL 0x04 /* The transmit collided at least once. */
  121 +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
  122 +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
  123 +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
  124 +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
  125 +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
  126 +
  127 +#define NE2000_MEM_SIZE 32768
  128 +
  129 +typedef struct NE2000State {
  130 + uint8_t cmd;
  131 + uint32_t start;
  132 + uint32_t stop;
  133 + uint8_t boundary;
  134 + uint8_t tsr;
  135 + uint8_t tpsr;
  136 + uint16_t tcnt;
  137 + uint16_t rcnt;
  138 + uint32_t rsar;
  139 + uint8_t isr;
  140 + uint8_t dcfg;
  141 + uint8_t imr;
  142 + uint8_t phys[6]; /* mac address */
  143 + uint8_t curpag;
  144 + uint8_t mult[8]; /* multicast mask array */
  145 + int irq;
  146 + uint8_t mem[NE2000_MEM_SIZE];
  147 +} NE2000State;
  148 +
  149 +static NE2000State ne2000_state;
  150 +int net_fd = -1;
  151 +
  152 +static void ne2000_reset(NE2000State *s)
  153 +{
  154 + int i;
  155 +
  156 + s->isr = ENISR_RESET;
  157 + s->mem[0] = 0x52;
  158 + s->mem[1] = 0x54;
  159 + s->mem[2] = 0x00;
  160 + s->mem[3] = 0x12;
  161 + s->mem[4] = 0x34;
  162 + s->mem[5] = 0x56;
  163 + s->mem[14] = 0x57;
  164 + s->mem[15] = 0x57;
  165 +
  166 + /* duplicate prom data */
  167 + for(i = 15;i >= 0; i--) {
  168 + s->mem[2 * i] = s->mem[i];
  169 + s->mem[2 * i + 1] = s->mem[i];
  170 + }
  171 +}
  172 +
  173 +static void ne2000_update_irq(NE2000State *s)
  174 +{
  175 + int isr;
  176 + isr = s->isr & s->imr;
  177 + if (isr)
  178 + pic_set_irq(s->irq, 1);
  179 + else
  180 + pic_set_irq(s->irq, 0);
  181 +}
  182 +
  183 +/* return true if the NE2000 can receive more data */
  184 +int ne2000_can_receive(void)
  185 +{
  186 + NE2000State *s = &ne2000_state;
  187 + int avail, index, boundary;
  188 +
  189 + if (s->cmd & E8390_STOP)
  190 + return 0;
  191 + index = s->curpag << 8;
  192 + boundary = s->boundary << 8;
  193 + if (index < boundary)
  194 + avail = boundary - index;
  195 + else
  196 + avail = (s->stop - s->start) - (index - boundary);
  197 + if (avail < (MAX_ETH_FRAME_SIZE + 4))
  198 + return 0;
  199 + return 1;
  200 +}
  201 +
  202 +void ne2000_receive(uint8_t *buf, int size)
  203 +{
  204 + NE2000State *s = &ne2000_state;
  205 + uint8_t *p;
  206 + int total_len, next, avail, len, index;
  207 +
  208 +#if defined(DEBUG_NE2000)
  209 + printf("NE2000: received len=%d\n", size);
  210 +#endif
  211 +
  212 + index = s->curpag << 8;
  213 + /* 4 bytes for header */
  214 + total_len = size + 4;
  215 + /* address for next packet (4 bytes for CRC) */
  216 + next = index + ((total_len + 4 + 255) & ~0xff);
  217 + if (next >= s->stop)
  218 + next -= (s->stop - s->start);
  219 + /* prepare packet header */
  220 + p = s->mem + index;
  221 + p[0] = ENRSR_RXOK; /* receive status */
  222 + p[1] = next >> 8;
  223 + p[2] = total_len;
  224 + p[3] = total_len >> 8;
  225 + index += 4;
  226 +
  227 + /* write packet data */
  228 + while (size > 0) {
  229 + avail = s->stop - index;
  230 + len = size;
  231 + if (len > avail)
  232 + len = avail;
  233 + memcpy(s->mem + index, buf, len);
  234 + buf += len;
  235 + index += len;
  236 + if (index == s->stop)
  237 + index = s->start;
  238 + size -= len;
  239 + }
  240 + s->curpag = next >> 8;
  241 +
  242 + /* now we can signal we have receive something */
  243 + s->isr |= ENISR_RX;
  244 + ne2000_update_irq(s);
  245 +}
  246 +
  247 +static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  248 +{
  249 + NE2000State *s = &ne2000_state;
  250 + int offset, page;
  251 +
  252 + addr &= 0xf;
  253 +#ifdef DEBUG_NE2000
  254 + printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
  255 +#endif
  256 + if (addr == E8390_CMD) {
  257 + /* control register */
  258 + s->cmd = val;
  259 + if (val & E8390_START) {
  260 + /* test specific case: zero length transfert */
  261 + if ((val & (E8390_RREAD | E8390_RWRITE)) &&
  262 + s->rcnt == 0) {
  263 + s->isr |= ENISR_RDC;
  264 + ne2000_update_irq(s);
  265 + }
  266 + if (val & E8390_TRANS) {
  267 + net_send_packet(net_fd, s->mem + (s->tpsr << 8), s->tcnt);
  268 + /* signal end of transfert */
  269 + s->tsr = ENTSR_PTX;
  270 + s->isr |= ENISR_TX;
  271 + ne2000_update_irq(s);
  272 + }
  273 + }
  274 + } else {
  275 + page = s->cmd >> 6;
  276 + offset = addr | (page << 4);
  277 + switch(offset) {
  278 + case EN0_STARTPG:
  279 + s->start = val << 8;
  280 + break;
  281 + case EN0_STOPPG:
  282 + s->stop = val << 8;
  283 + break;
  284 + case EN0_BOUNDARY:
  285 + s->boundary = val;
  286 + break;
  287 + case EN0_IMR:
  288 + s->imr = val;
  289 + ne2000_update_irq(s);
  290 + break;
  291 + case EN0_TPSR:
  292 + s->tpsr = val;
  293 + break;
  294 + case EN0_TCNTLO:
  295 + s->tcnt = (s->tcnt & 0xff00) | val;
  296 + break;
  297 + case EN0_TCNTHI:
  298 + s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
  299 + break;
  300 + case EN0_RSARLO:
  301 + s->rsar = (s->rsar & 0xff00) | val;
  302 + break;
  303 + case EN0_RSARHI:
  304 + s->rsar = (s->rsar & 0x00ff) | (val << 8);
  305 + break;
  306 + case EN0_RCNTLO:
  307 + s->rcnt = (s->rcnt & 0xff00) | val;
  308 + break;
  309 + case EN0_RCNTHI:
  310 + s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
  311 + break;
  312 + case EN0_DCFG:
  313 + s->dcfg = val;
  314 + break;
  315 + case EN0_ISR:
  316 + s->isr &= ~val;
  317 + ne2000_update_irq(s);
  318 + break;
  319 + case EN1_PHYS ... EN1_PHYS + 5:
  320 + s->phys[offset - EN1_PHYS] = val;
  321 + break;
  322 + case EN1_CURPAG:
  323 + s->curpag = val;
  324 + break;
  325 + case EN1_MULT ... EN1_MULT + 7:
  326 + s->mult[offset - EN1_MULT] = val;
  327 + break;
  328 + }
  329 + }
  330 +}
  331 +
  332 +static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr)
  333 +{
  334 + NE2000State *s = &ne2000_state;
  335 + int offset, page, ret;
  336 +
  337 + addr &= 0xf;
  338 + if (addr == E8390_CMD) {
  339 + ret = s->cmd;
  340 + } else {
  341 + page = s->cmd >> 6;
  342 + offset = addr | (page << 4);
  343 + switch(offset) {
  344 + case EN0_TSR:
  345 + ret = s->tsr;
  346 + break;
  347 + case EN0_BOUNDARY:
  348 + ret = s->boundary;
  349 + break;
  350 + case EN0_ISR:
  351 + ret = s->isr;
  352 + break;
  353 + case EN1_PHYS ... EN1_PHYS + 5:
  354 + ret = s->phys[offset - EN1_PHYS];
  355 + break;
  356 + case EN1_CURPAG:
  357 + ret = s->curpag;
  358 + break;
  359 + case EN1_MULT ... EN1_MULT + 7:
  360 + ret = s->mult[offset - EN1_MULT];
  361 + break;
  362 + default:
  363 + ret = 0x00;
  364 + break;
  365 + }
  366 + }
  367 +#ifdef DEBUG_NE2000
  368 + printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
  369 +#endif
  370 + return ret;
  371 +}
  372 +
  373 +static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  374 +{
  375 + NE2000State *s = &ne2000_state;
  376 + uint8_t *p;
  377 +
  378 +#ifdef DEBUG_NE2000
  379 + printf("NE2000: asic write val=0x%04x\n", val);
  380 +#endif
  381 + p = s->mem + s->rsar;
  382 + if (s->dcfg & 0x01) {
  383 + /* 16 bit access */
  384 + p[0] = val;
  385 + p[1] = val >> 8;
  386 + s->rsar += 2;
  387 + s->rcnt -= 2;
  388 + } else {
  389 + /* 8 bit access */
  390 + p[0] = val;
  391 + s->rsar++;
  392 + s->rcnt--;
  393 + }
  394 + /* wrap */
  395 + if (s->rsar == s->stop)
  396 + s->rsar = s->start;
  397 + if (s->rcnt == 0) {
  398 + /* signal end of transfert */
  399 + s->isr |= ENISR_RDC;
  400 + ne2000_update_irq(s);
  401 + }
  402 +}
  403 +
  404 +static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr)
  405 +{
  406 + NE2000State *s = &ne2000_state;
  407 + uint8_t *p;
  408 + int ret;
  409 +
  410 + p = s->mem + s->rsar;
  411 + if (s->dcfg & 0x01) {
  412 + /* 16 bit access */
  413 + ret = p[0] | (p[1] << 8);
  414 + s->rsar += 2;
  415 + s->rcnt -= 2;
  416 + } else {
  417 + /* 8 bit access */
  418 + ret = p[0];
  419 + s->rsar++;
  420 + s->rcnt--;
  421 + }
  422 + /* wrap */
  423 + if (s->rsar == s->stop)
  424 + s->rsar = s->start;
  425 + if (s->rcnt == 0) {
  426 + /* signal end of transfert */
  427 + s->isr |= ENISR_RDC;
  428 + ne2000_update_irq(s);
  429 + }
  430 +#ifdef DEBUG_NE2000
  431 + printf("NE2000: asic read val=0x%04x\n", ret);
  432 +#endif
  433 + return ret;
  434 +}
  435 +
  436 +static void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  437 +{
  438 + /* nothing to do (end of reset pulse) */
  439 +}
  440 +
  441 +static uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr)
  442 +{
  443 + NE2000State *s = &ne2000_state;
  444 + ne2000_reset(s);
  445 + return 0;
  446 +}
  447 +
  448 +void ne2000_init(int base, int irq)
  449 +{
  450 + NE2000State *s = &ne2000_state;
  451 +
  452 + register_ioport_write(base, 16, ne2000_ioport_write, 1);
  453 + register_ioport_read(base, 16, ne2000_ioport_read, 1);
  454 +
  455 + register_ioport_write(base + 0x10, 1, ne2000_asic_ioport_write, 1);
  456 + register_ioport_read(base + 0x10, 1, ne2000_asic_ioport_read, 1);
  457 + register_ioport_write(base + 0x10, 2, ne2000_asic_ioport_write, 2);
  458 + register_ioport_read(base + 0x10, 2, ne2000_asic_ioport_read, 2);
  459 +
  460 + register_ioport_write(base + 0x1f, 1, ne2000_reset_ioport_write, 1);
  461 + register_ioport_read(base + 0x1f, 1, ne2000_reset_ioport_read, 1);
  462 + s->irq = irq;
  463 +
  464 + ne2000_reset(s);
  465 +}
... ...
hw/pc.c 0 → 100644
  1 +/*
  2 + * QEMU PC System Emulator
  3 + *
  4 + * Copyright (c) 2003-2004 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +#define BIOS_FILENAME "bios.bin"
  47 +#define VGABIOS_FILENAME "vgabios.bin"
  48 +#define LINUX_BOOT_FILENAME "linux_boot.bin"
  49 +
  50 +#define KERNEL_LOAD_ADDR 0x00100000
  51 +#define INITRD_LOAD_ADDR 0x00400000
  52 +#define KERNEL_PARAMS_ADDR 0x00090000
  53 +#define KERNEL_CMDLINE_ADDR 0x00099000
  54 +
  55 +int speaker_data_on;
  56 +int dummy_refresh_clock;
  57 +
  58 +static void ioport80_write(CPUState *env, uint32_t addr, uint32_t data)
  59 +{
  60 +}
  61 +
  62 +#define REG_EQUIPMENT_BYTE 0x14
  63 +
  64 +static void cmos_init(int ram_size, int boot_device)
  65 +{
  66 + RTCState *s = &rtc_state;
  67 + int val;
  68 +
  69 + /* various important CMOS locations needed by PC/Bochs bios */
  70 +
  71 + s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */
  72 + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */
  73 +
  74 + /* memory size */
  75 + val = (ram_size / 1024) - 1024;
  76 + if (val > 65535)
  77 + val = 65535;
  78 + s->cmos_data[0x17] = val;
  79 + s->cmos_data[0x18] = val >> 8;
  80 + s->cmos_data[0x30] = val;
  81 + s->cmos_data[0x31] = val >> 8;
  82 +
  83 + val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
  84 + if (val > 65535)
  85 + val = 65535;
  86 + s->cmos_data[0x34] = val;
  87 + s->cmos_data[0x35] = val >> 8;
  88 +
  89 + switch(boot_device) {
  90 + case 'a':
  91 + case 'b':
  92 + s->cmos_data[0x3d] = 0x01; /* floppy boot */
  93 + break;
  94 + default:
  95 + case 'c':
  96 + s->cmos_data[0x3d] = 0x02; /* hard drive boot */
  97 + break;
  98 + case 'd':
  99 + s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */
  100 + break;
  101 + }
  102 +}
  103 +
  104 +void cmos_register_fd (uint8_t fd0, uint8_t fd1)
  105 +{
  106 + RTCState *s = &rtc_state;
  107 + int nb = 0;
  108 +
  109 + s->cmos_data[0x10] = 0;
  110 + switch (fd0) {
  111 + case 0:
  112 + /* 1.44 Mb 3"5 drive */
  113 + s->cmos_data[0x10] |= 0x40;
  114 + break;
  115 + case 1:
  116 + /* 2.88 Mb 3"5 drive */
  117 + s->cmos_data[0x10] |= 0x60;
  118 + break;
  119 + case 2:
  120 + /* 1.2 Mb 5"5 drive */
  121 + s->cmos_data[0x10] |= 0x20;
  122 + break;
  123 + }
  124 + switch (fd1) {
  125 + case 0:
  126 + /* 1.44 Mb 3"5 drive */
  127 + s->cmos_data[0x10] |= 0x04;
  128 + break;
  129 + case 1:
  130 + /* 2.88 Mb 3"5 drive */
  131 + s->cmos_data[0x10] |= 0x06;
  132 + break;
  133 + case 2:
  134 + /* 1.2 Mb 5"5 drive */
  135 + s->cmos_data[0x10] |= 0x02;
  136 + break;
  137 + }
  138 + if (fd0 < 3)
  139 + nb++;
  140 + if (fd1 < 3)
  141 + nb++;
  142 + switch (nb) {
  143 + case 0:
  144 + break;
  145 + case 1:
  146 + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */
  147 + break;
  148 + case 2:
  149 + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */
  150 + break;
  151 + }
  152 +}
  153 +
  154 +void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  155 +{
  156 + speaker_data_on = (val >> 1) & 1;
  157 + pit_set_gate(&pit_channels[2], val & 1);
  158 +}
  159 +
  160 +uint32_t speaker_ioport_read(CPUState *env, uint32_t addr)
  161 +{
  162 + int out;
  163 + out = pit_get_out(&pit_channels[2]);
  164 + dummy_refresh_clock ^= 1;
  165 + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) |
  166 + (dummy_refresh_clock << 4);
  167 +}
  168 +
  169 +/***********************************************************/
  170 +/* PC floppy disk controler emulation glue */
  171 +#define PC_FDC_DMA 0x2
  172 +#define PC_FDC_IRQ 0x6
  173 +#define PC_FDC_BASE 0x3F0
  174 +
  175 +static void fdctrl_register (unsigned char **disknames, int ro,
  176 + char boot_device)
  177 +{
  178 + int i;
  179 +
  180 + fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device);
  181 + for (i = 0; i < MAX_FD; i++) {
  182 + if (disknames[i] != NULL)
  183 + fdctrl_disk_change(i, disknames[i], ro);
  184 + }
  185 +}
  186 +
  187 +/***********************************************************/
  188 +/* Bochs BIOS debug ports */
  189 +
  190 +void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val)
  191 +{
  192 + switch(addr) {
  193 + /* Bochs BIOS messages */
  194 + case 0x400:
  195 + case 0x401:
  196 + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
  197 + exit(1);
  198 + case 0x402:
  199 + case 0x403:
  200 +#ifdef DEBUG_BIOS
  201 + fprintf(stderr, "%c", val);
  202 +#endif
  203 + break;
  204 +
  205 + /* LGPL'ed VGA BIOS messages */
  206 + case 0x501:
  207 + case 0x502:
  208 + fprintf(stderr, "VGA BIOS panic, line %d\n", val);
  209 + exit(1);
  210 + case 0x500:
  211 + case 0x503:
  212 +#ifdef DEBUG_BIOS
  213 + fprintf(stderr, "%c", val);
  214 +#endif
  215 + break;
  216 + }
  217 +}
  218 +
  219 +void bochs_bios_init(void)
  220 +{
  221 + register_ioport_write(0x400, 1, bochs_bios_write, 2);
  222 + register_ioport_write(0x401, 1, bochs_bios_write, 2);
  223 + register_ioport_write(0x402, 1, bochs_bios_write, 1);
  224 + register_ioport_write(0x403, 1, bochs_bios_write, 1);
  225 +
  226 + register_ioport_write(0x501, 1, bochs_bios_write, 2);
  227 + register_ioport_write(0x502, 1, bochs_bios_write, 2);
  228 + register_ioport_write(0x500, 1, bochs_bios_write, 1);
  229 + register_ioport_write(0x503, 1, bochs_bios_write, 1);
  230 +}
  231 +
  232 +
  233 +int load_kernel(const char *filename, uint8_t *addr,
  234 + uint8_t *real_addr)
  235 +{
  236 + int fd, size;
  237 + int setup_sects;
  238 +
  239 + fd = open(filename, O_RDONLY);
  240 + if (fd < 0)
  241 + return -1;
  242 +
  243 + /* load 16 bit code */
  244 + if (read(fd, real_addr, 512) != 512)
  245 + goto fail;
  246 + setup_sects = real_addr[0x1F1];
  247 + if (!setup_sects)
  248 + setup_sects = 4;
  249 + if (read(fd, real_addr + 512, setup_sects * 512) !=
  250 + setup_sects * 512)
  251 + goto fail;
  252 +
  253 + /* load 32 bit code */
  254 + size = read(fd, addr, 16 * 1024 * 1024);
  255 + if (size < 0)
  256 + goto fail;
  257 + close(fd);
  258 + return size;
  259 + fail:
  260 + close(fd);
  261 + return -1;
  262 +}
  263 +
  264 +/* PC hardware initialisation */
  265 +void pc_init(int ram_size, int vga_ram_size, int boot_device,
  266 + DisplayState *ds, const char **fd_filename, int snapshot,
  267 + const char *kernel_filename, const char *kernel_cmdline,
  268 + const char *initrd_filename)
  269 +{
  270 + char buf[1024];
  271 + int ret, linux_boot, initrd_size;
  272 +
  273 + linux_boot = (kernel_filename != NULL);
  274 +
  275 + /* allocate RAM */
  276 + cpu_register_physical_memory(0, ram_size, 0);
  277 +
  278 + /* BIOS load */
  279 + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
  280 + ret = load_image(buf, phys_ram_base + 0x000f0000);
  281 + if (ret != 0x10000) {
  282 + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
  283 + exit(1);
  284 + }
  285 +
  286 + /* VGA BIOS load */
  287 + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
  288 + ret = load_image(buf, phys_ram_base + 0x000c0000);
  289 +
  290 + /* setup basic memory access */
  291 + cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM);
  292 + cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM);
  293 +
  294 + bochs_bios_init();
  295 +
  296 + if (linux_boot) {
  297 + uint8_t bootsect[512];
  298 +
  299 + if (bs_table[0] == NULL) {
  300 + fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n");
  301 + exit(1);
  302 + }
  303 + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
  304 + ret = load_image(buf, bootsect);
  305 + if (ret != sizeof(bootsect)) {
  306 + fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
  307 + buf);
  308 + exit(1);
  309 + }
  310 +
  311 + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
  312 +
  313 + /* now we can load the kernel */
  314 + ret = load_kernel(kernel_filename,
  315 + phys_ram_base + KERNEL_LOAD_ADDR,
  316 + phys_ram_base + KERNEL_PARAMS_ADDR);
  317 + if (ret < 0) {
  318 + fprintf(stderr, "qemu: could not load kernel '%s'\n",
  319 + kernel_filename);
  320 + exit(1);
  321 + }
  322 +
  323 + /* load initrd */
  324 + initrd_size = 0;
  325 + if (initrd_filename) {
  326 + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
  327 + if (initrd_size < 0) {
  328 + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
  329 + initrd_filename);
  330 + exit(1);
  331 + }
  332 + }
  333 + if (initrd_size > 0) {
  334 + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
  335 + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
  336 + }
  337 + pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
  338 + kernel_cmdline);
  339 + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F);
  340 + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22,
  341 + KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR);
  342 + /* loader type */
  343 + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
  344 + }
  345 +
  346 + /* init basic PC hardware */
  347 + register_ioport_write(0x80, 1, ioport80_write, 1);
  348 +
  349 + vga_initialize(ds, phys_ram_base + ram_size, ram_size,
  350 + vga_ram_size);
  351 +
  352 + rtc_init(0x70, 8);
  353 + cmos_init(ram_size, boot_device);
  354 + register_ioport_read(0x61, 1, speaker_ioport_read, 1);
  355 + register_ioport_write(0x61, 1, speaker_ioport_write, 1);
  356 +
  357 + pic_init();
  358 + pit_init();
  359 + serial_init(0x3f8, 4);
  360 + ne2000_init(0x300, 9);
  361 + ide_init();
  362 + kbd_init();
  363 + AUD_init();
  364 + DMA_init();
  365 + SB16_init();
  366 +
  367 + fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device);
  368 +}
... ...
hw/pckbd.c 0 → 100644
  1 +/*
  2 + * QEMU PC keyboard emulation
  3 + *
  4 + * Copyright (c) 2003 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +/* debug PC keyboard */
  47 +//#define DEBUG_KBD
  48 +
  49 +/* debug PC keyboard : only mouse */
  50 +//#define DEBUG_MOUSE
  51 +
  52 +/* Keyboard Controller Commands */
  53 +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
  54 +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
  55 +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
  56 +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
  57 +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
  58 +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
  59 +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
  60 +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
  61 +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
  62 +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
  63 +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
  64 +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
  65 +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
  66 +#define KBD_CCMD_WRITE_OBUF 0xD2
  67 +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
  68 + initiated by the auxiliary device */
  69 +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
  70 +#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
  71 +#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
  72 +#define KBD_CCMD_RESET 0xFE
  73 +
  74 +/* Keyboard Commands */
  75 +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
  76 +#define KBD_CMD_ECHO 0xEE
  77 +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
  78 +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
  79 +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
  80 +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
  81 +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
  82 +#define KBD_CMD_RESET 0xFF /* Reset */
  83 +
  84 +/* Keyboard Replies */
  85 +#define KBD_REPLY_POR 0xAA /* Power on reset */
  86 +#define KBD_REPLY_ACK 0xFA /* Command ACK */
  87 +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
  88 +
  89 +/* Status Register Bits */
  90 +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
  91 +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
  92 +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
  93 +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
  94 +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
  95 +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
  96 +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
  97 +#define KBD_STAT_PERR 0x80 /* Parity error */
  98 +
  99 +/* Controller Mode Register Bits */
  100 +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
  101 +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
  102 +#define KBD_MODE_SYS 0x04 /* The system flag (?) */
  103 +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
  104 +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
  105 +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
  106 +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
  107 +#define KBD_MODE_RFU 0x80
  108 +
  109 +/* Mouse Commands */
  110 +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
  111 +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
  112 +#define AUX_SET_RES 0xE8 /* Set resolution */
  113 +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
  114 +#define AUX_SET_STREAM 0xEA /* Set stream mode */
  115 +#define AUX_POLL 0xEB /* Poll */
  116 +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
  117 +#define AUX_SET_WRAP 0xEE /* Set wrap mode */
  118 +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
  119 +#define AUX_GET_TYPE 0xF2 /* Get type */
  120 +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
  121 +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
  122 +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
  123 +#define AUX_SET_DEFAULT 0xF6
  124 +#define AUX_RESET 0xFF /* Reset aux device */
  125 +#define AUX_ACK 0xFA /* Command byte ACK. */
  126 +
  127 +#define MOUSE_STATUS_REMOTE 0x40
  128 +#define MOUSE_STATUS_ENABLED 0x20
  129 +#define MOUSE_STATUS_SCALE21 0x10
  130 +
  131 +#define KBD_QUEUE_SIZE 256
  132 +
  133 +typedef struct {
  134 + uint8_t data[KBD_QUEUE_SIZE];
  135 + int rptr, wptr, count;
  136 +} KBDQueue;
  137 +
  138 +typedef struct KBDState {
  139 + KBDQueue queues[2];
  140 + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
  141 + uint8_t status;
  142 + uint8_t mode;
  143 + /* keyboard state */
  144 + int kbd_write_cmd;
  145 + int scan_enabled;
  146 + /* mouse state */
  147 + int mouse_write_cmd;
  148 + uint8_t mouse_status;
  149 + uint8_t mouse_resolution;
  150 + uint8_t mouse_sample_rate;
  151 + uint8_t mouse_wrap;
  152 + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
  153 + uint8_t mouse_detect_state;
  154 + int mouse_dx; /* current values, needed for 'poll' mode */
  155 + int mouse_dy;
  156 + int mouse_dz;
  157 + uint8_t mouse_buttons;
  158 +} KBDState;
  159 +
  160 +KBDState kbd_state;
  161 +int reset_requested;
  162 +
  163 +/* update irq and KBD_STAT_[MOUSE_]OBF */
  164 +/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
  165 + incorrect, but it avoids having to simulate exact delays */
  166 +static void kbd_update_irq(KBDState *s)
  167 +{
  168 + int irq12_level, irq1_level;
  169 +
  170 + irq1_level = 0;
  171 + irq12_level = 0;
  172 + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
  173 + if (s->queues[0].count != 0 ||
  174 + s->queues[1].count != 0) {
  175 + s->status |= KBD_STAT_OBF;
  176 + if (s->queues[1].count != 0) {
  177 + s->status |= KBD_STAT_MOUSE_OBF;
  178 + if (s->mode & KBD_MODE_MOUSE_INT)
  179 + irq12_level = 1;
  180 + } else {
  181 + if ((s->mode & KBD_MODE_KBD_INT) &&
  182 + !(s->mode & KBD_MODE_DISABLE_KBD))
  183 + irq1_level = 1;
  184 + }
  185 + }
  186 + pic_set_irq(1, irq1_level);
  187 + pic_set_irq(12, irq12_level);
  188 +}
  189 +
  190 +static void kbd_queue(KBDState *s, int b, int aux)
  191 +{
  192 + KBDQueue *q = &kbd_state.queues[aux];
  193 +
  194 +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
  195 + if (aux)
  196 + printf("mouse event: 0x%02x\n", b);
  197 +#ifdef DEBUG_KBD
  198 + else
  199 + printf("kbd event: 0x%02x\n", b);
  200 +#endif
  201 +#endif
  202 + if (q->count >= KBD_QUEUE_SIZE)
  203 + return;
  204 + q->data[q->wptr] = b;
  205 + if (++q->wptr == KBD_QUEUE_SIZE)
  206 + q->wptr = 0;
  207 + q->count++;
  208 + kbd_update_irq(s);
  209 +}
  210 +
  211 +void kbd_put_keycode(int keycode)
  212 +{
  213 + KBDState *s = &kbd_state;
  214 + kbd_queue(s, keycode, 0);
  215 +}
  216 +
  217 +static uint32_t kbd_read_status(CPUState *env, uint32_t addr)
  218 +{
  219 + KBDState *s = &kbd_state;
  220 + int val;
  221 + val = s->status;
  222 +#if defined(DEBUG_KBD)
  223 + printf("kbd: read status=0x%02x\n", val);
  224 +#endif
  225 + return val;
  226 +}
  227 +
  228 +static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val)
  229 +{
  230 + KBDState *s = &kbd_state;
  231 +
  232 +#ifdef DEBUG_KBD
  233 + printf("kbd: write cmd=0x%02x\n", val);
  234 +#endif
  235 + switch(val) {
  236 + case KBD_CCMD_READ_MODE:
  237 + kbd_queue(s, s->mode, 0);
  238 + break;
  239 + case KBD_CCMD_WRITE_MODE:
  240 + case KBD_CCMD_WRITE_OBUF:
  241 + case KBD_CCMD_WRITE_AUX_OBUF:
  242 + case KBD_CCMD_WRITE_MOUSE:
  243 + case KBD_CCMD_WRITE_OUTPORT:
  244 + s->write_cmd = val;
  245 + break;
  246 + case KBD_CCMD_MOUSE_DISABLE:
  247 + s->mode |= KBD_MODE_DISABLE_MOUSE;
  248 + break;
  249 + case KBD_CCMD_MOUSE_ENABLE:
  250 + s->mode &= ~KBD_MODE_DISABLE_MOUSE;
  251 + break;
  252 + case KBD_CCMD_TEST_MOUSE:
  253 + kbd_queue(s, 0x00, 0);
  254 + break;
  255 + case KBD_CCMD_SELF_TEST:
  256 + s->status |= KBD_STAT_SELFTEST;
  257 + kbd_queue(s, 0x55, 0);
  258 + break;
  259 + case KBD_CCMD_KBD_TEST:
  260 + kbd_queue(s, 0x00, 0);
  261 + break;
  262 + case KBD_CCMD_KBD_DISABLE:
  263 + s->mode |= KBD_MODE_DISABLE_KBD;
  264 + kbd_update_irq(s);
  265 + break;
  266 + case KBD_CCMD_KBD_ENABLE:
  267 + s->mode &= ~KBD_MODE_DISABLE_KBD;
  268 + kbd_update_irq(s);
  269 + break;
  270 + case KBD_CCMD_READ_INPORT:
  271 + kbd_queue(s, 0x00, 0);
  272 + break;
  273 + case KBD_CCMD_READ_OUTPORT:
  274 + /* XXX: check that */
  275 +#ifdef TARGET_I386
  276 + val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
  277 +#else
  278 + val = 0x01;
  279 +#endif
  280 + if (s->status & KBD_STAT_OBF)
  281 + val |= 0x10;
  282 + if (s->status & KBD_STAT_MOUSE_OBF)
  283 + val |= 0x20;
  284 + kbd_queue(s, val, 0);
  285 + break;
  286 +#ifdef TARGET_I386
  287 + case KBD_CCMD_ENABLE_A20:
  288 + cpu_x86_set_a20(env, 1);
  289 + break;
  290 + case KBD_CCMD_DISABLE_A20:
  291 + cpu_x86_set_a20(env, 0);
  292 + break;
  293 +#endif
  294 + case KBD_CCMD_RESET:
  295 + reset_requested = 1;
  296 + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
  297 + break;
  298 + case 0xff:
  299 + /* ignore that - I don't know what is its use */
  300 + break;
  301 + default:
  302 + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
  303 + break;
  304 + }
  305 +}
  306 +
  307 +static uint32_t kbd_read_data(CPUState *env, uint32_t addr)
  308 +{
  309 + KBDState *s = &kbd_state;
  310 + KBDQueue *q;
  311 + int val, index;
  312 +
  313 + q = &s->queues[0]; /* first check KBD data */
  314 + if (q->count == 0)
  315 + q = &s->queues[1]; /* then check AUX data */
  316 + if (q->count == 0) {
  317 + /* NOTE: if no data left, we return the last keyboard one
  318 + (needed for EMM386) */
  319 + /* XXX: need a timer to do things correctly */
  320 + q = &s->queues[0];
  321 + index = q->rptr - 1;
  322 + if (index < 0)
  323 + index = KBD_QUEUE_SIZE - 1;
  324 + val = q->data[index];
  325 + } else {
  326 + val = q->data[q->rptr];
  327 + if (++q->rptr == KBD_QUEUE_SIZE)
  328 + q->rptr = 0;
  329 + q->count--;
  330 + /* reading deasserts IRQ */
  331 + if (q == &s->queues[0])
  332 + pic_set_irq(1, 0);
  333 + else
  334 + pic_set_irq(12, 0);
  335 + }
  336 + /* reassert IRQs if data left */
  337 + kbd_update_irq(s);
  338 +#ifdef DEBUG_KBD
  339 + printf("kbd: read data=0x%02x\n", val);
  340 +#endif
  341 + return val;
  342 +}
  343 +
  344 +static void kbd_reset_keyboard(KBDState *s)
  345 +{
  346 + s->scan_enabled = 1;
  347 +}
  348 +
  349 +static void kbd_write_keyboard(KBDState *s, int val)
  350 +{
  351 + switch(s->kbd_write_cmd) {
  352 + default:
  353 + case -1:
  354 + switch(val) {
  355 + case 0x00:
  356 + kbd_queue(s, KBD_REPLY_ACK, 0);
  357 + break;
  358 + case 0x05:
  359 + kbd_queue(s, KBD_REPLY_RESEND, 0);
  360 + break;
  361 + case KBD_CMD_GET_ID:
  362 + kbd_queue(s, KBD_REPLY_ACK, 0);
  363 + kbd_queue(s, 0xab, 0);
  364 + kbd_queue(s, 0x83, 0);
  365 + break;
  366 + case KBD_CMD_ECHO:
  367 + kbd_queue(s, KBD_CMD_ECHO, 0);
  368 + break;
  369 + case KBD_CMD_ENABLE:
  370 + s->scan_enabled = 1;
  371 + kbd_queue(s, KBD_REPLY_ACK, 0);
  372 + break;
  373 + case KBD_CMD_SET_LEDS:
  374 + case KBD_CMD_SET_RATE:
  375 + s->kbd_write_cmd = val;
  376 + kbd_queue(s, KBD_REPLY_ACK, 0);
  377 + break;
  378 + case KBD_CMD_RESET_DISABLE:
  379 + kbd_reset_keyboard(s);
  380 + s->scan_enabled = 0;
  381 + kbd_queue(s, KBD_REPLY_ACK, 0);
  382 + break;
  383 + case KBD_CMD_RESET_ENABLE:
  384 + kbd_reset_keyboard(s);
  385 + s->scan_enabled = 1;
  386 + kbd_queue(s, KBD_REPLY_ACK, 0);
  387 + break;
  388 + case KBD_CMD_RESET:
  389 + kbd_reset_keyboard(s);
  390 + kbd_queue(s, KBD_REPLY_ACK, 0);
  391 + kbd_queue(s, KBD_REPLY_POR, 0);
  392 + break;
  393 + default:
  394 + kbd_queue(s, KBD_REPLY_ACK, 0);
  395 + break;
  396 + }
  397 + break;
  398 + case KBD_CMD_SET_LEDS:
  399 + kbd_queue(s, KBD_REPLY_ACK, 0);
  400 + s->kbd_write_cmd = -1;
  401 + break;
  402 + case KBD_CMD_SET_RATE:
  403 + kbd_queue(s, KBD_REPLY_ACK, 0);
  404 + s->kbd_write_cmd = -1;
  405 + break;
  406 + }
  407 +}
  408 +
  409 +static void kbd_mouse_send_packet(KBDState *s)
  410 +{
  411 + unsigned int b;
  412 + int dx1, dy1, dz1;
  413 +
  414 + dx1 = s->mouse_dx;
  415 + dy1 = s->mouse_dy;
  416 + dz1 = s->mouse_dz;
  417 + /* XXX: increase range to 8 bits ? */
  418 + if (dx1 > 127)
  419 + dx1 = 127;
  420 + else if (dx1 < -127)
  421 + dx1 = -127;
  422 + if (dy1 > 127)
  423 + dy1 = 127;
  424 + else if (dy1 < -127)
  425 + dy1 = -127;
  426 + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
  427 + kbd_queue(s, b, 1);
  428 + kbd_queue(s, dx1 & 0xff, 1);
  429 + kbd_queue(s, dy1 & 0xff, 1);
  430 + /* extra byte for IMPS/2 or IMEX */
  431 + switch(s->mouse_type) {
  432 + default:
  433 + break;
  434 + case 3:
  435 + if (dz1 > 127)
  436 + dz1 = 127;
  437 + else if (dz1 < -127)
  438 + dz1 = -127;
  439 + kbd_queue(s, dz1 & 0xff, 1);
  440 + break;
  441 + case 4:
  442 + if (dz1 > 7)
  443 + dz1 = 7;
  444 + else if (dz1 < -7)
  445 + dz1 = -7;
  446 + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
  447 + kbd_queue(s, b, 1);
  448 + break;
  449 + }
  450 +
  451 + /* update deltas */
  452 + s->mouse_dx -= dx1;
  453 + s->mouse_dy -= dy1;
  454 + s->mouse_dz -= dz1;
  455 +}
  456 +
  457 +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
  458 +{
  459 + KBDState *s = &kbd_state;
  460 +
  461 + /* check if deltas are recorded when disabled */
  462 + if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
  463 + return;
  464 +
  465 + s->mouse_dx += dx;
  466 + s->mouse_dy -= dy;
  467 + s->mouse_dz += dz;
  468 + s->mouse_buttons = buttons_state;
  469 +
  470 + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
  471 + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) {
  472 + for(;;) {
  473 + /* if not remote, send event. Multiple events are sent if
  474 + too big deltas */
  475 + kbd_mouse_send_packet(s);
  476 + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
  477 + break;
  478 + }
  479 + }
  480 +}
  481 +
  482 +static void kbd_write_mouse(KBDState *s, int val)
  483 +{
  484 +#ifdef DEBUG_MOUSE
  485 + printf("kbd: write mouse 0x%02x\n", val);
  486 +#endif
  487 + switch(s->mouse_write_cmd) {
  488 + default:
  489 + case -1:
  490 + /* mouse command */
  491 + if (s->mouse_wrap) {
  492 + if (val == AUX_RESET_WRAP) {
  493 + s->mouse_wrap = 0;
  494 + kbd_queue(s, AUX_ACK, 1);
  495 + return;
  496 + } else if (val != AUX_RESET) {
  497 + kbd_queue(s, val, 1);
  498 + return;
  499 + }
  500 + }
  501 + switch(val) {
  502 + case AUX_SET_SCALE11:
  503 + s->mouse_status &= ~MOUSE_STATUS_SCALE21;
  504 + kbd_queue(s, AUX_ACK, 1);
  505 + break;
  506 + case AUX_SET_SCALE21:
  507 + s->mouse_status |= MOUSE_STATUS_SCALE21;
  508 + kbd_queue(s, AUX_ACK, 1);
  509 + break;
  510 + case AUX_SET_STREAM:
  511 + s->mouse_status &= ~MOUSE_STATUS_REMOTE;
  512 + kbd_queue(s, AUX_ACK, 1);
  513 + break;
  514 + case AUX_SET_WRAP:
  515 + s->mouse_wrap = 1;
  516 + kbd_queue(s, AUX_ACK, 1);
  517 + break;
  518 + case AUX_SET_REMOTE:
  519 + s->mouse_status |= MOUSE_STATUS_REMOTE;
  520 + kbd_queue(s, AUX_ACK, 1);
  521 + break;
  522 + case AUX_GET_TYPE:
  523 + kbd_queue(s, AUX_ACK, 1);
  524 + kbd_queue(s, s->mouse_type, 1);
  525 + break;
  526 + case AUX_SET_RES:
  527 + case AUX_SET_SAMPLE:
  528 + s->mouse_write_cmd = val;
  529 + kbd_queue(s, AUX_ACK, 1);
  530 + break;
  531 + case AUX_GET_SCALE:
  532 + kbd_queue(s, AUX_ACK, 1);
  533 + kbd_queue(s, s->mouse_status, 1);
  534 + kbd_queue(s, s->mouse_resolution, 1);
  535 + kbd_queue(s, s->mouse_sample_rate, 1);
  536 + break;
  537 + case AUX_POLL:
  538 + kbd_queue(s, AUX_ACK, 1);
  539 + kbd_mouse_send_packet(s);
  540 + break;
  541 + case AUX_ENABLE_DEV:
  542 + s->mouse_status |= MOUSE_STATUS_ENABLED;
  543 + kbd_queue(s, AUX_ACK, 1);
  544 + break;
  545 + case AUX_DISABLE_DEV:
  546 + s->mouse_status &= ~MOUSE_STATUS_ENABLED;
  547 + kbd_queue(s, AUX_ACK, 1);
  548 + break;
  549 + case AUX_SET_DEFAULT:
  550 + s->mouse_sample_rate = 100;
  551 + s->mouse_resolution = 2;
  552 + s->mouse_status = 0;
  553 + kbd_queue(s, AUX_ACK, 1);
  554 + break;
  555 + case AUX_RESET:
  556 + s->mouse_sample_rate = 100;
  557 + s->mouse_resolution = 2;
  558 + s->mouse_status = 0;
  559 + kbd_queue(s, AUX_ACK, 1);
  560 + kbd_queue(s, 0xaa, 1);
  561 + kbd_queue(s, s->mouse_type, 1);
  562 + break;
  563 + default:
  564 + break;
  565 + }
  566 + break;
  567 + case AUX_SET_SAMPLE:
  568 + s->mouse_sample_rate = val;
  569 +#if 0
  570 + /* detect IMPS/2 or IMEX */
  571 + switch(s->mouse_detect_state) {
  572 + default:
  573 + case 0:
  574 + if (val == 200)
  575 + s->mouse_detect_state = 1;
  576 + break;
  577 + case 1:
  578 + if (val == 100)
  579 + s->mouse_detect_state = 2;
  580 + else if (val == 200)
  581 + s->mouse_detect_state = 3;
  582 + else
  583 + s->mouse_detect_state = 0;
  584 + break;
  585 + case 2:
  586 + if (val == 80)
  587 + s->mouse_type = 3; /* IMPS/2 */
  588 + s->mouse_detect_state = 0;
  589 + break;
  590 + case 3:
  591 + if (val == 80)
  592 + s->mouse_type = 4; /* IMEX */
  593 + s->mouse_detect_state = 0;
  594 + break;
  595 + }
  596 +#endif
  597 + kbd_queue(s, AUX_ACK, 1);
  598 + s->mouse_write_cmd = -1;
  599 + break;
  600 + case AUX_SET_RES:
  601 + s->mouse_resolution = val;
  602 + kbd_queue(s, AUX_ACK, 1);
  603 + s->mouse_write_cmd = -1;
  604 + break;
  605 + }
  606 +}
  607 +
  608 +void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val)
  609 +{
  610 + KBDState *s = &kbd_state;
  611 +
  612 +#ifdef DEBUG_KBD
  613 + printf("kbd: write data=0x%02x\n", val);
  614 +#endif
  615 +
  616 + switch(s->write_cmd) {
  617 + case 0:
  618 + kbd_write_keyboard(s, val);
  619 + break;
  620 + case KBD_CCMD_WRITE_MODE:
  621 + s->mode = val;
  622 + kbd_update_irq(s);
  623 + break;
  624 + case KBD_CCMD_WRITE_OBUF:
  625 + kbd_queue(s, val, 0);
  626 + break;
  627 + case KBD_CCMD_WRITE_AUX_OBUF:
  628 + kbd_queue(s, val, 1);
  629 + break;
  630 + case KBD_CCMD_WRITE_OUTPORT:
  631 +#ifdef TARGET_I386
  632 + cpu_x86_set_a20(env, (val >> 1) & 1);
  633 +#endif
  634 + if (!(val & 1)) {
  635 + reset_requested = 1;
  636 + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
  637 + }
  638 + break;
  639 + case KBD_CCMD_WRITE_MOUSE:
  640 + kbd_write_mouse(s, val);
  641 + break;
  642 + default:
  643 + break;
  644 + }
  645 + s->write_cmd = 0;
  646 +}
  647 +
  648 +void kbd_reset(KBDState *s)
  649 +{
  650 + KBDQueue *q;
  651 + int i;
  652 +
  653 + s->kbd_write_cmd = -1;
  654 + s->mouse_write_cmd = -1;
  655 + s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
  656 + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
  657 + for(i = 0; i < 2; i++) {
  658 + q = &s->queues[i];
  659 + q->rptr = 0;
  660 + q->wptr = 0;
  661 + q->count = 0;
  662 + }
  663 +}
  664 +
  665 +void kbd_init(void)
  666 +{
  667 + kbd_reset(&kbd_state);
  668 + register_ioport_read(0x60, 1, kbd_read_data, 1);
  669 + register_ioport_write(0x60, 1, kbd_write_data, 1);
  670 + register_ioport_read(0x64, 1, kbd_read_status, 1);
  671 + register_ioport_write(0x64, 1, kbd_write_command, 1);
  672 +}
... ...
hw/serial.c 0 → 100644
  1 +/*
  2 + * QEMU 16450 UART emulation
  3 + *
  4 + * Copyright (c) 2003-2004 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 <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <sys/wait.h>
  41 +#include <netinet/in.h>
  42 +
  43 +#include "cpu.h"
  44 +#include "vl.h"
  45 +
  46 +//#define DEBUG_SERIAL
  47 +
  48 +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
  49 +
  50 +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
  51 +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
  52 +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
  53 +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
  54 +
  55 +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
  56 +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
  57 +
  58 +#define UART_IIR_MSI 0x00 /* Modem status interrupt */
  59 +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
  60 +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
  61 +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
  62 +
  63 +/*
  64 + * These are the definitions for the Modem Control Register
  65 + */
  66 +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
  67 +#define UART_MCR_OUT2 0x08 /* Out2 complement */
  68 +#define UART_MCR_OUT1 0x04 /* Out1 complement */
  69 +#define UART_MCR_RTS 0x02 /* RTS complement */
  70 +#define UART_MCR_DTR 0x01 /* DTR complement */
  71 +
  72 +/*
  73 + * These are the definitions for the Modem Status Register
  74 + */
  75 +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
  76 +#define UART_MSR_RI 0x40 /* Ring Indicator */
  77 +#define UART_MSR_DSR 0x20 /* Data Set Ready */
  78 +#define UART_MSR_CTS 0x10 /* Clear to Send */
  79 +#define UART_MSR_DDCD 0x08 /* Delta DCD */
  80 +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
  81 +#define UART_MSR_DDSR 0x02 /* Delta DSR */
  82 +#define UART_MSR_DCTS 0x01 /* Delta CTS */
  83 +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
  84 +
  85 +#define UART_LSR_TEMT 0x40 /* Transmitter empty */
  86 +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
  87 +#define UART_LSR_BI 0x10 /* Break interrupt indicator */
  88 +#define UART_LSR_FE 0x08 /* Frame error indicator */
  89 +#define UART_LSR_PE 0x04 /* Parity error indicator */
  90 +#define UART_LSR_OE 0x02 /* Overrun error indicator */
  91 +#define UART_LSR_DR 0x01 /* Receiver data ready */
  92 +
  93 +typedef struct SerialState {
  94 + uint8_t divider;
  95 + uint8_t rbr; /* receive register */
  96 + uint8_t ier;
  97 + uint8_t iir; /* read only */
  98 + uint8_t lcr;
  99 + uint8_t mcr;
  100 + uint8_t lsr; /* read only */
  101 + uint8_t msr;
  102 + uint8_t scr;
  103 + /* NOTE: this hidden state is necessary for tx irq generation as
  104 + it can be reset while reading iir */
  105 + int thr_ipending;
  106 + int irq;
  107 +} SerialState;
  108 +
  109 +SerialState serial_ports[1];
  110 +
  111 +void serial_update_irq(void)
  112 +{
  113 + SerialState *s = &serial_ports[0];
  114 +
  115 + if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
  116 + s->iir = UART_IIR_RDI;
  117 + } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
  118 + s->iir = UART_IIR_THRI;
  119 + } else {
  120 + s->iir = UART_IIR_NO_INT;
  121 + }
  122 + if (s->iir != UART_IIR_NO_INT) {
  123 + pic_set_irq(s->irq, 1);
  124 + } else {
  125 + pic_set_irq(s->irq, 0);
  126 + }
  127 +}
  128 +
  129 +void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
  130 +{
  131 + SerialState *s = &serial_ports[0];
  132 + unsigned char ch;
  133 + int ret;
  134 +
  135 + addr &= 7;
  136 +#ifdef DEBUG_SERIAL
  137 + printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
  138 +#endif
  139 + switch(addr) {
  140 + default:
  141 + case 0:
  142 + if (s->lcr & UART_LCR_DLAB) {
  143 + s->divider = (s->divider & 0xff00) | val;
  144 + } else {
  145 + s->thr_ipending = 0;
  146 + s->lsr &= ~UART_LSR_THRE;
  147 + serial_update_irq();
  148 +
  149 + ch = val;
  150 + do {
  151 + ret = write(1, &ch, 1);
  152 + } while (ret != 1);
  153 + s->thr_ipending = 1;
  154 + s->lsr |= UART_LSR_THRE;
  155 + s->lsr |= UART_LSR_TEMT;
  156 + serial_update_irq();
  157 + }
  158 + break;
  159 + case 1:
  160 + if (s->lcr & UART_LCR_DLAB) {
  161 + s->divider = (s->divider & 0x00ff) | (val << 8);
  162 + } else {
  163 + s->ier = val;
  164 + serial_update_irq();
  165 + }
  166 + break;
  167 + case 2:
  168 + break;
  169 + case 3:
  170 + s->lcr = val;
  171 + break;
  172 + case 4:
  173 + s->mcr = val;
  174 + break;
  175 + case 5:
  176 + break;
  177 + case 6:
  178 + s->msr = val;
  179 + break;
  180 + case 7:
  181 + s->scr = val;
  182 + break;
  183 + }
  184 +}
  185 +
  186 +uint32_t serial_ioport_read(CPUState *env, uint32_t addr)
  187 +{
  188 + SerialState *s = &serial_ports[0];
  189 + uint32_t ret;
  190 +
  191 + addr &= 7;
  192 + switch(addr) {
  193 + default:
  194 + case 0:
  195 + if (s->lcr & UART_LCR_DLAB) {
  196 + ret = s->divider & 0xff;
  197 + } else {
  198 + ret = s->rbr;
  199 + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
  200 + serial_update_irq();
  201 + }
  202 + break;
  203 + case 1:
  204 + if (s->lcr & UART_LCR_DLAB) {
  205 + ret = (s->divider >> 8) & 0xff;
  206 + } else {
  207 + ret = s->ier;
  208 + }
  209 + break;
  210 + case 2:
  211 + ret = s->iir;
  212 + /* reset THR pending bit */
  213 + if ((ret & 0x7) == UART_IIR_THRI)
  214 + s->thr_ipending = 0;
  215 + serial_update_irq();
  216 + break;
  217 + case 3:
  218 + ret = s->lcr;
  219 + break;
  220 + case 4:
  221 + ret = s->mcr;
  222 + break;
  223 + case 5:
  224 + ret = s->lsr;
  225 + break;
  226 + case 6:
  227 + if (s->mcr & UART_MCR_LOOP) {
  228 + /* in loopback, the modem output pins are connected to the
  229 + inputs */
  230 + ret = (s->mcr & 0x0c) << 4;
  231 + ret |= (s->mcr & 0x02) << 3;
  232 + ret |= (s->mcr & 0x01) << 5;
  233 + } else {
  234 + ret = s->msr;
  235 + }
  236 + break;
  237 + case 7:
  238 + ret = s->scr;
  239 + break;
  240 + }
  241 +#ifdef DEBUG_SERIAL
  242 + printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
  243 +#endif
  244 + return ret;
  245 +}
  246 +
  247 +int serial_can_receive(void)
  248 +{
  249 + SerialState *s = &serial_ports[0];
  250 + return !(s->lsr & UART_LSR_DR);
  251 +}
  252 +
  253 +void serial_receive_byte(int ch)
  254 +{
  255 + SerialState *s = &serial_ports[0];
  256 +
  257 + s->rbr = ch;
  258 + s->lsr |= UART_LSR_DR;
  259 + serial_update_irq();
  260 +}
  261 +
  262 +void serial_receive_break(void)
  263 +{
  264 + SerialState *s = &serial_ports[0];
  265 +
  266 + s->rbr = 0;
  267 + s->lsr |= UART_LSR_BI | UART_LSR_DR;
  268 + serial_update_irq();
  269 +}
  270 +
  271 +void serial_init(int base, int irq)
  272 +{
  273 + SerialState *s = &serial_ports[0];
  274 +
  275 + s->irq = irq;
  276 + s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
  277 + s->iir = UART_IIR_NO_INT;
  278 +
  279 + register_ioport_write(base, 8, serial_ioport_write, 1);
  280 + register_ioport_read(base, 8, serial_ioport_read, 1);
  281 +}
... ...