Files
qemu-ios/hw/arm/ipod_touch_lcd.c
T

218 lines
6.2 KiB
C

#include "hw/arm/ipod_touch_lcd.h"
#include "ui/pixel_ops.h"
#include "ui/console.h"
#include "hw/display/framebuffer.h"
static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size)
{
//printf("%s: read from location 0x%08x\n", __func__, addr);
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
switch(addr)
{
case 0x0:
return 2;
case 0x4:
return s->lcd_con;
case 0xC:
return 0x1; //s->unknown1;
case 0x20:
return s->w1_display_depth_info;
case 0x24:
return s->w1_framebuffer_base;
case 0x28:
return s->w1_hspan;
case 0x30:
return s->w1_display_resolution_info;
case 0x1b10:
return 2;
default:
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
break;
}
return 0;
}
static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
//printf("%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
switch(addr) {
case 0x4:
s->lcd_con = val;
break;
case 0xC:
s->unknown1 = val;
qemu_irq_lower(s->irq);
break;
case 0x20:
s->w1_display_depth_info = val;
break;
case 0x24:
s->w1_framebuffer_base = val;
break;
case 0x28:
s->w1_hspan = val;
break;
case 0x30:
s->w1_display_resolution_info = val;
break;
}
}
static void lcd_invalidate(void *opaque)
{
IPodTouchLCDState *s = opaque;
s->invalidate = 1;
}
static void draw_line32_32(void *opaque, uint8_t *d, const uint8_t *s, int width, int deststep)
{
uint8_t r, g, b;
do {
//v = lduw_le_p((void *) s);
//printf("V: %d\n", *s);
b = s[0];
g = s[1];
r = s[2];
//printf("R: %d, G: %d, B: %d\n", r, g, b);
((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
s += 4;
d += 4;
} while (-- width != 0);
}
static void lcd_refresh(void *opaque)
{
//fprintf(stderr, "%s: refreshing LCD screen\n", __func__);
IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque;
DisplaySurface *surface = qemu_console_surface(lcd->con);
drawfn draw_line;
int src_width, dest_width;
int height, first, last;
int width, linesize;
if (!lcd || !lcd->con || !surface_bits_per_pixel(surface))
return;
dest_width = 4;
draw_line = draw_line32_32;
/* Resolution */
first = last = 0;
width = 320;
height = 480;
lcd->invalidate = 1;
src_width = 4 * width;
linesize = surface_stride(surface);
if(lcd->invalidate) {
framebuffer_update_memory_section(&lcd->fbsection, lcd->sysmem, lcd->w1_framebuffer_base, height, 4 * width);
}
framebuffer_update_display(surface, &lcd->fbsection,
width, height,
src_width, /* Length of source line, in bytes. */
linesize, /* Bytes between adjacent horizontal output pixels. */
dest_width, /* Bytes between adjacent vertical output pixels. */
lcd->invalidate,
draw_line, NULL,
&first, &last);
if (first >= 0) {
dpy_gfx_update(lcd->con, 0, first, width, last - first + 1);
}
lcd->invalidate = 0;
}
static const MemoryRegionOps lcd_ops = {
.read = ipod_touch_lcd_read,
.write = ipod_touch_lcd_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static const GraphicHwOps gfx_ops = {
.invalidate = lcd_invalidate,
.gfx_update = lcd_refresh,
};
static void ipod_touch_lcd_mouse_event(void *opaque, int x, int y, int z, int buttons_state)
{
//printf("CLICKY %d %d %d %d\n", x, y, z, buttons_state);
// convert x and y to fractional numbers
float fx = x / pow(2, 15);
float fy = 1 - y / pow(2, 15);
IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque;
lcd->mt->prev_touch_x = lcd->mt->touch_x;
lcd->mt->prev_touch_y = lcd->mt->touch_y;
lcd->mt->touch_x = fx;
lcd->mt->touch_y = fy;
if(buttons_state && !lcd->mt->touch_down) {
ipod_touch_multitouch_on_touch(lcd->mt);
}
else if(!buttons_state && lcd->mt->touch_down) {
ipod_touch_multitouch_on_release(lcd->mt);
}
}
static void refresh_timer_tick(void *opaque)
{
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
qemu_irq_raise(s->irq);
timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY);
}
static void ipod_touch_lcd_realize(DeviceState *dev, Error **errp)
{
IPodTouchLCDState *s = IPOD_TOUCH_LCD(dev);
s->con = graphic_console_init(dev, 0, &gfx_ops, s);
qemu_console_resize(s->con, 320, 480);
// add mouse handler
qemu_add_mouse_event_handler(ipod_touch_lcd_mouse_event, s, 1, "iPod Touch Touchscreen");
// initialize the refresh timer
s->refresh_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, refresh_timer_tick, s);
timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY);
}
static void ipod_touch_lcd_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
DeviceState *dev = DEVICE(sbd);
IPodTouchLCDState *s = IPOD_TOUCH_LCD(dev);
memory_region_init_io(&s->iomem, obj, &lcd_ops, s, "lcd", 0x10000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
}
static void ipod_touch_lcd_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ipod_touch_lcd_realize;
}
static const TypeInfo ipod_touch_lcd_info = {
.name = TYPE_IPOD_TOUCH_LCD,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IPodTouchLCDState),
.instance_init = ipod_touch_lcd_init,
.class_init = ipod_touch_lcd_class_init,
};
static void ipod_touch_machine_types(void)
{
type_register_static(&ipod_touch_lcd_info);
}
type_init(ipod_touch_machine_types)