[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 10/14] NEC PC-9821 family mouse
From: |
武田 俊也 |
Subject: |
[Qemu-devel] [PATCH 10/14] NEC PC-9821 family mouse |
Date: |
Thu, 10 Sep 2009 00:42:38 +0900 |
hw/pc98mouse.c
/*
* QEMU NEC PC-98x1 mouse
*
* Copyright (c) 2009 TAKEDA, toshiya
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "isa.h"
#include "pc.h"
#include "console.h"
#include "qemu-timer.h"
static const int64_t mouse_expire[4] = {
1000000000LL / 120,
1000000000LL / 60,
1000000000LL / 30,
1000000000LL / 15
};
typedef struct MouseState {
int button;
int dx, dy;
int lx, ly;
uint8_t freq;
uint8_t portc;
QEMUTimer *irq_timer;
qemu_irq irq;
} MouseState;
static MouseState mouse_state;
/* mouse */
static void mouse_irq_timer(void *opaque)
{
MouseState *s = opaque;
if (!(s->portc & 0x10)) {
/* pulse ??? */
qemu_set_irq(s->irq, 1);
qemu_set_irq(s->irq, 0);
}
/* set next irq */
qemu_mod_timer(s->irq_timer, qemu_get_clock(vm_clock) +
mouse_expire[s->freq & 3]);
}
static void mouse_event_handler(void *opaque, int dx, int dy, int dz, int
buttons_state)
{
MouseState *s = opaque;
s->button = buttons_state;
s->dx += dx;
s->dy -= dy;
}
static void mouse_freq_write(void *opaque, uint32_t addr, uint32_t value)
{
MouseState *s = opaque;
if(!(value & 0xfc)) {
s->freq = value;
}
}
static uint32_t mouse_freq_read(void *opaque, uint32_t addr)
{
MouseState *s = opaque;
return s->freq & 3;
}
/* pio */
static uint32_t pio_porta_read(void *opaque, uint32_t addr)
{
MouseState *s = opaque;
uint32_t val = 0;
if (!(s->button & 1)) {
val |= 0x80;
}
if (!(s->button & 2)) {
val |= 0x40;
}
if (!(s->button & 4)) {
val |= 0x20;
}
switch (s->portc & 0xe0) {
case 0x00:
val |= (s->dx >> 0) & 0x0f;
break;
case 0x20:
val |= (s->dx >> 4) & 0x0f;
break;
case 0x40:
val |= (s->dy >> 0) & 0x0f;
break;
case 0x60:
val |= (s->dy >> 4) & 0x0f;
break;
case 0x80:
val |= (s->lx >> 0) & 0x0f;
break;
case 0xa0:
val |= (s->lx >> 4) & 0x0f;
break;
case 0xc0:
val |= (s->ly >> 0) & 0x0f;
break;
case 0xe0:
val |= (s->ly >> 4) & 0x0f;
break;
}
return val;
}
static uint32_t pio_portb_read(void *opaque, uint32_t addr)
{
return 0xff;
}
static void pio_portc_write(void *opaque, uint32_t addr, uint32_t value)
{
MouseState *s = opaque;
if (!(s->portc & 0x80) && (value & 0x80)) {
/* latch mouse count */
s->lx = s->dx;
s->ly = s->dy;
s->dx = s->dy = 0;
}
s->portc = (uint8_t)value;
}
static uint32_t pio_portc_read(void *opaque, uint32_t addr)
{
MouseState *s = opaque;
return (s->portc & 0xf0) | 0x08;
}
static void pio_ctrl_write(void *opaque, uint32_t addr, uint32_t value)
{
MouseState *s = opaque;
if (!(value & 0x80)) {
/* set/reset portc bit */
uint8_t portc = s->portc;
uint8_t bit = 1 << ((value >> 1) & 7);
if (value & 1) {
portc |= bit;
} else {
portc &= ~bit;
}
pio_portc_write(s, 0, portc);
}
}
/* interface */
static void pc98_mouse_reset(void *opaque)
{
MouseState *s = opaque;
s->button = 0;
s->dx = s->dy = 0;
s->lx = s->ly = -1;
s->freq = 0;
s->portc = 0xf0;
}
static void pc98_mouse_save(QEMUFile* f, void* opaque)
{
MouseState *s = opaque;
qemu_put_be32s(f, &s->lx);
qemu_put_be32s(f, &s->ly);
qemu_put_8s(f, &s->freq);
qemu_put_8s(f, &s->portc);
}
static int pc98_mouse_load(QEMUFile* f, void* opaque, int version_id)
{
MouseState *s = opaque;
if (version_id != 1)
return -EINVAL;
pc98_mouse_reset(s);
qemu_get_be32s(f, &s->lx);
qemu_get_be32s(f, &s->ly);
qemu_get_8s(f, &s->freq);
qemu_get_8s(f, &s->portc);
return 0;
}
void pc98_mouse_init(qemu_irq irq)
{
MouseState *s = &mouse_state;
s->irq_timer = qemu_new_timer(vm_clock, mouse_irq_timer, s);
s->irq = irq;
qemu_mod_timer(s->irq_timer, qemu_get_clock(vm_clock) + mouse_expire[0]);
register_ioport_read(0x7fd9, 1, 1, pio_porta_read, s);
register_ioport_read(0x7fdb, 1, 1, pio_portb_read, s);
register_ioport_write(0x7fdd, 1, 1, pio_portc_write, s);
register_ioport_read(0x7fdd, 1, 1, pio_portc_read, s);
register_ioport_write(0x7fdf, 1, 1, pio_ctrl_write, s);
register_ioport_write(0xbfdb, 1, 1, mouse_freq_write, s);
register_ioport_read(0xbfdb, 1, 1, mouse_freq_read, s);
qemu_add_mouse_event_handler(mouse_event_handler, s, 0, "QEMU PC-98x1
Mouse");
qemu_register_reset(pc98_mouse_reset, s);
register_savevm("pc98mouse", 0, 1, pc98_mouse_save, pc98_mouse_load, s);
pc98_mouse_reset(s);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH 10/14] NEC PC-9821 family mouse,
武田 俊也 <=