Several fixes and changes
This commit is contained in:
1 parent
9a2d42ca33
commit
6c4f881436
18 files changed
+861
-56
No files matched your search
+26
-11
@@ -88,7 +88,6 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem,
|
||||
allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000);
|
||||
allocate_ram(sysmem, "llb", 0x22000000, 0x100000);
|
||||
allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000);
|
||||
allocate_ram(sysmem, "mbx2", MBX2_MEM_BASE, 0x1000);
|
||||
allocate_ram(sysmem, "tvout1", TVOUT1_MEM_BASE, 0x1000);
|
||||
allocate_ram(sysmem, "tvout2", TVOUT2_MEM_BASE, 0x1000);
|
||||
allocate_ram(sysmem, "tvout3", TVOUT3_MEM_BASE, 0x1000);
|
||||
@@ -260,7 +259,9 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
sysbus_create_simple("ipodtouch.spi", SPI3_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI3_IRQ));
|
||||
|
||||
set_spi_base(4);
|
||||
sysbus_create_simple("ipodtouch.spi", SPI4_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI4_IRQ));
|
||||
dev = sysbus_create_simple("ipodtouch.spi", SPI4_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI4_IRQ));
|
||||
IPodTouchSPIState *spi4_state = IPOD_TOUCH_SPI(dev);
|
||||
nms->spi4_state = spi4_state;
|
||||
|
||||
// init the chip ID module
|
||||
dev = qdev_new("ipodtouch.chipid");
|
||||
@@ -283,7 +284,7 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
dev = qdev_new("pl080");
|
||||
PL080State *pl080_1 = PL080(dev);
|
||||
object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal);
|
||||
memory_region_add_subregion(sysmem, DMAC0_MEM_BASE, &pl080_1->iomem);
|
||||
memory_region_add_subregion(sysmem, DMAC0_MEM_BASE, &pl080_1->iomem1);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ));
|
||||
@@ -291,10 +292,11 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
dev = qdev_new("pl080");
|
||||
PL080State *pl080_2 = PL080(dev);
|
||||
object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal);
|
||||
memory_region_add_subregion(sysmem, DMAC1_MEM_BASE, &pl080_2->iomem);
|
||||
memory_region_add_subregion(sysmem, DMAC1_0_MEM_BASE, &pl080_2->iomem1);
|
||||
memory_region_add_subregion(sysmem, DMAC1_1_MEM_BASE, &pl080_2->iomem2);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ));
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC1_IRQ));
|
||||
|
||||
// Init I2C0
|
||||
dev = qdev_new("ipodtouch.i2c");
|
||||
@@ -302,11 +304,12 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
i2c_state->base = 0;
|
||||
nms->i2c0_state = i2c_state;
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C0_IRQ));
|
||||
memory_region_add_subregion(sysmem, I2C0_MEM_BASE, &i2c_state->iomem);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C0_IRQ));
|
||||
|
||||
// init the PMU
|
||||
i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73);
|
||||
I2CSlave * pmu = i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73);
|
||||
|
||||
// init the accelerometer
|
||||
I2CSlave *accelerometer = i2c_slave_create_simple(i2c_state->bus, "lis302dl", 0x1D);
|
||||
@@ -317,19 +320,21 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
nms->i2c1_state = i2c_state;
|
||||
i2c_state->base = 1;
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C1_IRQ));
|
||||
memory_region_add_subregion(sysmem, I2C1_MEM_BASE, &i2c_state->iomem);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C1_IRQ));
|
||||
|
||||
// init the Mikey
|
||||
i2c_slave_create_simple(i2c_state->bus, "cd3272mikey", 0x39);
|
||||
I2CSlave *cd327mikey = i2c_slave_create_simple(i2c_state->bus, "cd3272mikey", 0x39);
|
||||
|
||||
// init the FMSS flash controller
|
||||
dev = qdev_new("ipodtouch.fmss");
|
||||
IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev);
|
||||
nms->fmss_state = fmss_state;
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ));
|
||||
memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ));
|
||||
|
||||
// init the chip ID module
|
||||
dev = qdev_new("ipodtouch.usbphys");
|
||||
@@ -348,10 +353,20 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
// init LCD
|
||||
dev = qdev_new("ipodtouch.lcd");
|
||||
IPodTouchLCDState *lcd_state = IPOD_TOUCH_LCD(dev);
|
||||
lcd_state->sysmem = sysmem;
|
||||
nms->lcd_state = lcd_state;
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_LCD_IRQ));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
memory_region_add_subregion(sysmem, DISPLAY_MEM_BASE, &lcd_state->iomem);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_LCD_IRQ));
|
||||
|
||||
// init scaler / CSC
|
||||
dev = qdev_new("ipodtouch.scalercsc");
|
||||
IPodTouchScalerCSCState *scaler_csc_state = IPOD_TOUCH_SCALER_CSC(dev);
|
||||
nms->scaler_csc_state = scaler_csc_state;
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
memory_region_add_subregion(sysmem, SCALER_CSC_MEM_BASE, &scaler_csc_state->iomem);
|
||||
sysbus_realize(busdev, &error_fatal);
|
||||
|
||||
// init SHA1 engine
|
||||
dev = qdev_new("ipodtouch.sha1");
|
||||
|
||||
+19
-3
@@ -23,9 +23,13 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
uint8_t *buf;
|
||||
|
||||
// fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value);
|
||||
uint32_t *data = malloc(sizeof(uint16_t) * 9);
|
||||
|
||||
switch(offset) {
|
||||
case AES_GO:
|
||||
// PATCH OUT
|
||||
// in iBoot, we also patch the length check after LZSS compression since that can lead to issues
|
||||
|
||||
inbuf = (uint8_t *)malloc(aesop->insize);
|
||||
cpu_physical_memory_read((aesop->inaddr), inbuf, aesop->insize);
|
||||
|
||||
@@ -62,14 +66,26 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
};
|
||||
for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; }
|
||||
}
|
||||
else if(aesop->gid_encryption_count == 2) { // kernelcache
|
||||
else if(aesop->gid_encryption_count == 2) { // apple logo
|
||||
|
||||
// very ugly - we patch out here the LZSS check
|
||||
data[0] = 0x0; // NOP
|
||||
cpu_physical_memory_write(0x0ff119f0, (uint8_t *)data, 4);
|
||||
|
||||
char key[] = {
|
||||
0x64, 0x23, 0x8f, 0xb0, 0x32, 0x91, 0x42, 0x25, 0x22, 0xb5, 0xdd, 0x28, 0x3f, 0xc3, 0x89, 0x5c, // IV
|
||||
0x85, 0x9f, 0xd4, 0xd3, 0x82, 0xb8, 0x38, 0x51, 0x56, 0xfc, 0x58, 0x1a, 0x7f, 0x1d, 0x97, 0x22, // key
|
||||
};
|
||||
for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; }
|
||||
}
|
||||
else if(aesop->gid_encryption_count == 3) { // kernelcache
|
||||
char key[] = {
|
||||
0xa1, 0x91, 0x29, 0x12, 0x90, 0xd4, 0x87, 0xff, 0x07, 0x31, 0x96, 0x9c, 0x5f, 0xc8, 0xd9, 0x18, // IV
|
||||
0x0e, 0x4d, 0x23, 0xfa, 0x67, 0x59, 0x99, 0xd5, 0x95, 0x9d, 0xd1, 0x0c, 0x8d, 0xd7, 0x3d, 0x20, // key
|
||||
};
|
||||
for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; }
|
||||
}
|
||||
else if(aesop->gid_encryption_count == 3) { // device tree
|
||||
else if(aesop->gid_encryption_count == 4) { // device tree
|
||||
char key[] = {
|
||||
0xcc, 0xff, 0x63, 0x4e, 0xe1, 0x27, 0x35, 0xf0, 0x19, 0x16, 0xc4, 0xa6, 0xb2, 0x0f, 0xf1, 0x45, // IV
|
||||
0xe1, 0x7b, 0xcd, 0x56, 0x8d, 0xf1, 0xcd, 0xdc, 0x8f, 0xec, 0xbf, 0x54, 0x87, 0xd5, 0xc3, 0xce, // key
|
||||
@@ -83,7 +99,7 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, AES_DECRYPT);
|
||||
}
|
||||
|
||||
if(aesop->outaddr != 0x220100ac && aesop->outaddr != 0x0bf08468) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key??
|
||||
if(aesop->outaddr != 0x220100ac && aesop->outaddr != 0x0bf08468 && aesop->outaddr != 0x0fb9bcdc) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key??
|
||||
// BUG: after decrypting the kernel, we update the Adler CRC code and number of expected bytes.
|
||||
if(aesop->outaddr == 0x0b000020) {
|
||||
uint32_t *cast_buf = (uint32_t *)buf;
|
||||
|
||||
@@ -83,14 +83,13 @@ static void read_nand_pages(IPodTouchFMSSState *s)
|
||||
cpu_physical_memory_read(s->reg_pages_in_addr + page_ind, &page_nr, 0x4);
|
||||
cpu_physical_memory_read(s->reg_pages_out_addr + page_ind, &page_out_addr, 0x4);
|
||||
|
||||
printf("Will read page %d into address 0x%08x and spare into address 0x%08x\n", page_nr, page_out_addr, s->reg_page_spare_out_addr);
|
||||
//printf("Will read page %d into address 0x%08x and spare into address 0x%08x\n", page_nr, page_out_addr, s->reg_page_spare_out_addr);
|
||||
|
||||
// prepare the page
|
||||
char filename[200];
|
||||
sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/%d.page", page_nr);
|
||||
struct stat st = {0};
|
||||
if (stat(filename, &st) == -1) {
|
||||
printf("Will preparing empty page %d", page_nr);
|
||||
// page storage does not exist - initialize an empty buffer
|
||||
memset(s->page_buffer, 0, NAND_BYTES_PER_PAGE);
|
||||
memset(s->page_spare_buffer, 0, NAND_BYTES_PER_SPARE);
|
||||
|
||||
+126
-2
@@ -1,4 +1,7 @@
|
||||
#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)
|
||||
{
|
||||
@@ -9,6 +12,16 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
case 0x0:
|
||||
return 2;
|
||||
case 0x4:
|
||||
return s->lcd_con;
|
||||
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:
|
||||
@@ -21,7 +34,95 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size)
|
||||
static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
{
|
||||
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
|
||||
// fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
|
||||
fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
|
||||
|
||||
switch(addr) {
|
||||
case 0x4:
|
||||
s->lcd_con = val;
|
||||
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;
|
||||
case 0xC:
|
||||
qemu_irq_lower(s->irq);
|
||||
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 = {
|
||||
@@ -30,9 +131,32 @@ static const MemoryRegionOps lcd_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const GraphicHwOps gfx_ops = {
|
||||
.invalidate = lcd_invalidate,
|
||||
.gfx_update = lcd_refresh,
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
@@ -12,7 +12,6 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz
|
||||
case REG_INTSRC:
|
||||
return rDSIM_INTSRC_RxDatDone;
|
||||
case REG_RXFIFO:
|
||||
return 0;
|
||||
if(!s->return_panel_id) {
|
||||
s->return_panel_id = true;
|
||||
// TODO this should be rewritten as a proper queue!
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
#include "hw/arm/ipod_touch_multitouch.h"
|
||||
|
||||
static void prepare_interface_version_response(IPodTouchMultitouchState *s) {
|
||||
memset(s->out_buffer + 1, 0, 15);
|
||||
|
||||
// set the interface version
|
||||
s->out_buffer[2] = MT_INTERFACE_VERSION;
|
||||
|
||||
// set the max packet size
|
||||
s->out_buffer[3] = (MT_MAX_PACKET_SIZE & 0xFF);
|
||||
s->out_buffer[4] = (MT_MAX_PACKET_SIZE >> 8) & 0xFF;
|
||||
|
||||
// compute and set the checksum
|
||||
uint32_t checksum = 0;
|
||||
for(int i = 0; i < 14; i++) {
|
||||
checksum += s->out_buffer[i];
|
||||
}
|
||||
|
||||
s->out_buffer[14] = (checksum & 0xFF);
|
||||
s->out_buffer[15] = (checksum >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static void prepare_cmd_status_response(IPodTouchMultitouchState *s) {
|
||||
memset(s->out_buffer + 1, 0, 15);
|
||||
|
||||
// TODO we should probably set some CMD status here
|
||||
|
||||
// compute and set the checksum
|
||||
uint32_t checksum = 0;
|
||||
for(int i = 0; i < 14; i++) {
|
||||
checksum += s->out_buffer[i];
|
||||
}
|
||||
|
||||
s->out_buffer[14] = (checksum & 0xFF);
|
||||
s->out_buffer[15] = (checksum >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static void prepare_report_info_response(IPodTouchMultitouchState *s, uint8_t report_id) {
|
||||
memset(s->out_buffer + 1, 0, 15);
|
||||
|
||||
// set the error
|
||||
s->out_buffer[2] = 0;
|
||||
|
||||
// set the report length
|
||||
uint32_t report_length = 0;
|
||||
if(report_id == MT_REPORT_UNKNOWN1) {
|
||||
report_length = MT_REPORT_UNKNOWN1_SIZE;
|
||||
}
|
||||
else if(report_id == MT_REPORT_FAMILY_ID) {
|
||||
report_length = MT_REPORT_FAMILY_ID_SIZE;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_INFO) {
|
||||
report_length = MT_REPORT_SENSOR_INFO_SIZE;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_REGION_DESC) {
|
||||
report_length = MT_REPORT_SENSOR_REGION_DESC_SIZE;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_REGION_PARAM) {
|
||||
report_length = MT_REPORT_SENSOR_REGION_PARAM_SIZE;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_DIMENSIONS) {
|
||||
report_length = MT_REPORT_SENSOR_DIMENSIONS_SIZE;
|
||||
}
|
||||
else {
|
||||
hw_error("Unknown report ID 0x%02x\n", report_id);
|
||||
}
|
||||
|
||||
s->out_buffer[3] = (report_length & 0xFF);
|
||||
s->out_buffer[4] = (report_length >> 8) & 0xFF;
|
||||
|
||||
// compute and set the checksum
|
||||
uint32_t checksum = 0;
|
||||
for(int i = 0; i < 14; i++) {
|
||||
checksum += s->out_buffer[i];
|
||||
}
|
||||
|
||||
s->out_buffer[14] = (checksum & 0xFF);
|
||||
s->out_buffer[15] = (checksum >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static void prepare_short_control_response(IPodTouchMultitouchState *s, uint8_t report_id) {
|
||||
memset(s->out_buffer + 1, 0, 15);
|
||||
|
||||
if(report_id == MT_REPORT_FAMILY_ID) {
|
||||
s->out_buffer[3] = MT_FAMILY_ID;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_INFO) {
|
||||
s->out_buffer[3] = MT_ENDIANNESS;
|
||||
s->out_buffer[4] = MT_SENSOR_ROWS;
|
||||
s->out_buffer[5] = MT_SENSOR_COLUMNS;
|
||||
s->out_buffer[6] = (MT_BCD_VERSION & 0xFF);
|
||||
s->out_buffer[7] = (MT_BCD_VERSION >> 8) & 0xFF;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_REGION_DESC) {
|
||||
s->out_buffer[3] = MT_SENSOR_REGION_DESC;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_REGION_PARAM) {
|
||||
s->out_buffer[3] = MT_SENSOR_REGION_PARAM;
|
||||
}
|
||||
else if(report_id == MT_REPORT_SENSOR_DIMENSIONS) {
|
||||
uint32_t *ob_int32 = (uint32_t *)&s->out_buffer[3];
|
||||
ob_int32[0] = MT_SENSOR_SURFACE_WIDTH;
|
||||
ob_int32[1] = MT_SENSOR_SURFACE_HEIGHT;
|
||||
}
|
||||
else {
|
||||
hw_error("Unknown report ID 0x%02x\n", report_id);
|
||||
}
|
||||
|
||||
// compute and set the checksum
|
||||
uint32_t checksum = 0;
|
||||
for(int i = 0; i < 14; i++) {
|
||||
checksum += s->out_buffer[i];
|
||||
}
|
||||
|
||||
s->out_buffer[14] = (checksum & 0xFF);
|
||||
s->out_buffer[15] = (checksum >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static uint32_t ipod_touch_multitouch_transfer(SSIPeripheral *dev, uint32_t value)
|
||||
{
|
||||
IPodTouchMultitouchState *s = IPOD_TOUCH_MULTITOUCH(dev);
|
||||
|
||||
//printf("<MULTITOUCH> Got value: 0x%02x\n", value);
|
||||
|
||||
if(s->cur_cmd == 0) {
|
||||
//printf("Starting command 0x%02x\n", value);
|
||||
// we're currently not in a command - start a new command
|
||||
s->cur_cmd = value;
|
||||
s->out_buffer = malloc(0x100);
|
||||
s->out_buffer[0] = value; // the response header
|
||||
s->buf_ind = 0;
|
||||
s->in_buffer = malloc(0x100);
|
||||
s->in_buffer_ind = 0;
|
||||
|
||||
if(value == 0x18) { // filler packet??
|
||||
s->buf_size = 2;
|
||||
s->out_buffer[1] = 0xE1;
|
||||
}
|
||||
else if(value == 0x1A) { // HBPP ACK
|
||||
s->buf_size = 2;
|
||||
if(s->hbpp_atn_ack_response[0] == 0 && s->hbpp_atn_ack_response[1] == 0) {
|
||||
// return the default ACK response
|
||||
s->out_buffer[0] = 0x4B;
|
||||
s->out_buffer[1] = 0xC1;
|
||||
}
|
||||
else {
|
||||
s->out_buffer[0] = s->hbpp_atn_ack_response[0];
|
||||
s->out_buffer[1] = s->hbpp_atn_ack_response[1];
|
||||
}
|
||||
|
||||
}
|
||||
else if(value == 0x1C) { // read register
|
||||
s->buf_size = 8;
|
||||
memset(s->out_buffer, 0, 8); // just return zeros
|
||||
}
|
||||
else if(value == 0x1D) { // execute
|
||||
s->buf_size = 12;
|
||||
memset(s->out_buffer, 0, 12); // just return zeros
|
||||
}
|
||||
else if(value == 0x1F) { // calibration
|
||||
s->buf_size = 2;
|
||||
s->out_buffer[1] = 0x0;
|
||||
}
|
||||
else if(value == 0x1E) { // write register
|
||||
s->buf_size = 16;
|
||||
memset(s->out_buffer, 0, 16); // just return zeros
|
||||
}
|
||||
else if(value == 0x1F) { // calibration
|
||||
s->buf_size = 2;
|
||||
s->out_buffer[1] = 0x0;
|
||||
}
|
||||
else if(value == MT_CMD_HBPP_DATA_PACKET) {
|
||||
s->buf_size = 20; // should be enough initially, until we get the packet length
|
||||
memset(s->out_buffer + 1, 0, 20 - 1); // just return zeros
|
||||
}
|
||||
else if(value == 0x47) { // unknown command, probably used to clear the interrupt
|
||||
s->buf_size = 2;
|
||||
}
|
||||
else if(value == MT_CMD_GET_CMD_STATUS) {
|
||||
s->buf_size = 16;
|
||||
prepare_cmd_status_response(s);
|
||||
}
|
||||
else if(value == MT_CMD_GET_INTERFACE_VERSION) {
|
||||
s->buf_size = 16;
|
||||
prepare_interface_version_response(s);
|
||||
}
|
||||
else if(value == MT_CMD_GET_REPORT_INFO) {
|
||||
s->buf_size = 16;
|
||||
}
|
||||
else if(value == MT_CMD_SHORT_CONTROL_WRITE) {
|
||||
s->buf_size = 16;
|
||||
}
|
||||
else if(value == MT_CMD_SHORT_CONTROL_READ) {
|
||||
s->buf_size = 16;
|
||||
}
|
||||
else if(value == MT_CMD_FRAME_READ) {
|
||||
printf("Will read frame!\n");
|
||||
s->buf_size = sizeof(MTFrame);
|
||||
free(s->out_buffer);
|
||||
s->out_buffer = (uint8_t *) s->next_frame;
|
||||
}
|
||||
else {
|
||||
hw_error("Unknown command 0x%02x!", value);
|
||||
}
|
||||
}
|
||||
|
||||
s->in_buffer[s->in_buffer_ind] = value;
|
||||
s->in_buffer_ind++;
|
||||
|
||||
if(s->cur_cmd == MT_CMD_HBPP_DATA_PACKET && s->in_buffer_ind == 10) {
|
||||
// verify the header checksum
|
||||
uint32_t checksum = 0;
|
||||
for(int i = 2; i < 8; i++) {
|
||||
checksum += s->in_buffer[i];
|
||||
}
|
||||
|
||||
if(checksum != (s->in_buffer[8] << 8 | s->in_buffer[9])) {
|
||||
hw_error("HBPP data header checksum doesn't match!");
|
||||
}
|
||||
|
||||
uint32_t data_len = (s->in_buffer[2] << 10) | (s->in_buffer[3] << 2) + 5;
|
||||
// extend the lengths of the in/out buffers
|
||||
free(s->in_buffer);
|
||||
s->in_buffer = malloc(data_len + 0x10);
|
||||
|
||||
free(s->out_buffer);
|
||||
s->out_buffer = malloc(data_len);
|
||||
memset(s->out_buffer, 0, data_len);
|
||||
s->buf_size = data_len;
|
||||
s->buf_ind = 0;
|
||||
}
|
||||
else if(s->cur_cmd == MT_CMD_GET_REPORT_INFO && s->in_buffer_ind == 2) {
|
||||
prepare_report_info_response(s, s->in_buffer[1]);
|
||||
}
|
||||
else if(s->cur_cmd == MT_CMD_SHORT_CONTROL_WRITE && s->in_buffer_ind == 16) {
|
||||
// TODO we should persist the report here!
|
||||
}
|
||||
else if(s->cur_cmd == MT_CMD_SHORT_CONTROL_READ && s->in_buffer_ind == 2) {
|
||||
prepare_short_control_response(s, s->in_buffer[1]);
|
||||
}
|
||||
|
||||
// TODO process register writes!
|
||||
|
||||
uint8_t ret_val = s->out_buffer[s->buf_ind];
|
||||
s->buf_ind++;
|
||||
|
||||
//printf("<MULTITOUCH> Got value: 0x%02x, returning 0x%02x (index: %d, buffer length: %d)\n", value, ret_val, s->buf_ind, s->buf_size);
|
||||
|
||||
if(s->buf_ind == s->buf_size) {
|
||||
//printf("Finished command 0x%02x\n", s->cur_cmd);
|
||||
|
||||
if(s->cur_cmd == 0x1E) {
|
||||
// make sure we return a success status on the next HBPP ACK
|
||||
s->hbpp_atn_ack_response[0] = 0x4A;
|
||||
s->hbpp_atn_ack_response[1] = 0xD1;
|
||||
}
|
||||
|
||||
// we're done with the command
|
||||
s->cur_cmd = 0;
|
||||
s->buf_size = 0;
|
||||
//free(s->out_buffer);
|
||||
//free(s->in_buffer);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static MTFrame *get_frame(IPodTouchMultitouchState *s, uint8_t event, float x, float y, uint16_t radius1, uint16_t radius2, uint16_t radius3, uint16_t contactDensity) {
|
||||
MTFrame *frame = calloc(sizeof(MTFrame), sizeof(uint8_t *));
|
||||
|
||||
uint16_t data_len = sizeof(MTFrameHeader) + sizeof(FingerData) + 2;
|
||||
|
||||
/// create the frame length packet
|
||||
frame->frame_length.cmd = MT_CMD_FRAME_READ;
|
||||
frame->frame_length.length1 = (data_len & 0xFF);
|
||||
frame->frame_length.length2 = (data_len >> 8) & 0xFF;
|
||||
|
||||
uint16_t checksum = 0;
|
||||
for(int i = 0; i < 14; i++) {
|
||||
checksum += ((uint8_t *) &frame->frame_length)[i];
|
||||
}
|
||||
frame->frame_length.checksum1 = (checksum & 0xFF);
|
||||
frame->frame_length.checksum2 = (checksum >> 8) & 0xFF;
|
||||
|
||||
// create the frame packet
|
||||
frame->frame_packet.cmd = MT_CMD_FRAME_READ;
|
||||
frame->frame_packet.length1 = (data_len & 0xFF);
|
||||
frame->frame_packet.length2 = (data_len >> 8) & 0xFF;
|
||||
|
||||
checksum = 0;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
checksum += ((uint8_t *) &frame->frame_length)[i];
|
||||
}
|
||||
|
||||
// the first five bytes have to sum up to 0.
|
||||
frame->frame_packet.checksum_pad = 0xFF - (checksum & 0xFF) + 1;
|
||||
|
||||
frame->frame_packet.header.type = MT_FRAME_TYPE_PATH;
|
||||
frame->frame_packet.header.frameNum = s->frame_counter;
|
||||
frame->frame_packet.header.headerLen = sizeof(MTFrameHeader);
|
||||
uint64_t elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 1000000;
|
||||
frame->frame_packet.header.timestamp = elapsed_ns;
|
||||
frame->frame_packet.header.numFingers = 1;
|
||||
frame->frame_packet.header.fingerDataLen = sizeof(FingerData);
|
||||
|
||||
// create the finger data
|
||||
frame->finger_data.id = 1;
|
||||
frame->finger_data.event = event;
|
||||
frame->finger_data.unk_2 = 2;
|
||||
frame->finger_data.unk_3 = 1;
|
||||
|
||||
// compute the velocity
|
||||
int diff_x = (int)((x - s->prev_touch_x) * MT_INTERNAL_SENSOR_SURFACE_WIDTH);
|
||||
int diff_y = (int)((x - s->prev_touch_y) * MT_INTERNAL_SENSOR_SURFACE_HEIGHT);
|
||||
frame->finger_data.velX = diff_x / (elapsed_ns - s->last_frame_timestamp) * 1000;
|
||||
frame->finger_data.velY = diff_y / (elapsed_ns - s->last_frame_timestamp) * 1000;
|
||||
|
||||
frame->finger_data.x = (int)(x * MT_INTERNAL_SENSOR_SURFACE_WIDTH);
|
||||
frame->finger_data.y = (int)(y * MT_INTERNAL_SENSOR_SURFACE_HEIGHT);
|
||||
frame->finger_data.radius1 = radius1;
|
||||
frame->finger_data.radius2 = radius2;
|
||||
frame->finger_data.radius3 = radius3;
|
||||
frame->finger_data.angle = 19317;
|
||||
frame->finger_data.contactDensity = contactDensity; // seems to be a medium press
|
||||
|
||||
// compute the checksum over the frame data.
|
||||
checksum = 0;
|
||||
for(int i = 0; i < data_len - 2; i++) {
|
||||
checksum += ((uint8_t *) &frame->frame_packet.header)[i];
|
||||
}
|
||||
frame->checksum1 = (checksum & 0xFF);
|
||||
frame->checksum2 = (checksum >> 8) & 0xFF;
|
||||
|
||||
s->last_frame_timestamp = elapsed_ns;
|
||||
s->frame_counter += 1;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static void ipod_touch_multitouch_inform_frame_ready(IPodTouchMultitouchState *s) {
|
||||
s->sysic->gpio_int_status[4] |= (1 << 27); // the multitouch interrupt bit is in group 4 (32 interrupts per group), and the 27th of the 4th group
|
||||
qemu_irq_raise(s->sysic->gpio_irqs[4]);
|
||||
}
|
||||
|
||||
void ipod_touch_multitouch_on_touch(IPodTouchMultitouchState *s) {
|
||||
s->touch_down = true;
|
||||
|
||||
s->next_frame = get_frame(s, MT_EVENT_TOUCH_START, s->touch_x, s->touch_y, 100, 660, 580, 150);
|
||||
ipod_touch_multitouch_inform_frame_ready(s);
|
||||
|
||||
timer_mod(s->touch_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10);
|
||||
}
|
||||
|
||||
void ipod_touch_multitouch_on_release(IPodTouchMultitouchState *s) {
|
||||
s->next_frame = get_frame(s, MT_EVENT_TOUCH_ENDED, s->touch_x, s->touch_y, 0, 0, 0, 0);
|
||||
s->touch_down = false;
|
||||
ipod_touch_multitouch_inform_frame_ready(s);
|
||||
|
||||
timer_del(s->touch_timer);
|
||||
timer_mod(s->touch_end_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10);
|
||||
}
|
||||
|
||||
static void touch_timer_tick(void *opaque)
|
||||
{
|
||||
IPodTouchMultitouchState *s = (IPodTouchMultitouchState *)opaque;
|
||||
|
||||
s->next_frame = get_frame(s, MT_EVENT_TOUCH_MOVED, s->touch_x, s->touch_y, 100, 660, 580, 150);
|
||||
ipod_touch_multitouch_inform_frame_ready(s);
|
||||
|
||||
if(s->touch_down) {
|
||||
// reschedule the timer
|
||||
timer_mod(s->touch_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_end_timer_tick(void *opaque)
|
||||
{
|
||||
IPodTouchMultitouchState *s = (IPodTouchMultitouchState *)opaque;
|
||||
s->next_frame = get_frame(s, MT_EVENT_TOUCH_FULL_END, s->touch_x, s->touch_y, 0, 0, 0, 0);
|
||||
s->touch_down = false;
|
||||
ipod_touch_multitouch_inform_frame_ready(s);
|
||||
}
|
||||
|
||||
static void ipod_touch_multitouch_realize(SSIPeripheral *d, Error **errp)
|
||||
{
|
||||
IPodTouchMultitouchState *s = IPOD_TOUCH_MULTITOUCH(d);
|
||||
memset(s->hbpp_atn_ack_response, 0, 2);
|
||||
s->touch_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, touch_timer_tick, s);
|
||||
s->touch_end_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, touch_end_timer_tick, s);
|
||||
|
||||
s->prev_touch_x = 0;
|
||||
s->prev_touch_y = 0;
|
||||
s->last_frame_timestamp = 0;
|
||||
}
|
||||
|
||||
static void ipod_touch_multitouch_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
|
||||
k->realize = ipod_touch_multitouch_realize;
|
||||
k->transfer = ipod_touch_multitouch_transfer;
|
||||
}
|
||||
|
||||
static const TypeInfo ipod_touch_multitouch_type_info = {
|
||||
.name = TYPE_IPOD_TOUCH_MULTITOUCH,
|
||||
.parent = TYPE_SSI_PERIPHERAL,
|
||||
.instance_size = sizeof(IPodTouchMultitouchState),
|
||||
.class_init = ipod_touch_multitouch_class_init,
|
||||
};
|
||||
|
||||
static void ipod_touch_multitouch_register_types(void)
|
||||
{
|
||||
type_register_static(&ipod_touch_multitouch_type_info);
|
||||
}
|
||||
|
||||
type_init(ipod_touch_multitouch_register_types)
|
||||
@@ -13,7 +13,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value)
|
||||
{
|
||||
IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev);
|
||||
|
||||
printf("NOR SPI received value 0x%08x\n", value);
|
||||
if(value == NOR_GET_JEDECID) {
|
||||
printf("RECEIVED JEDCID VALUE\n");
|
||||
}
|
||||
|
||||
+2
-22
@@ -71,7 +71,6 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
s->num_started = 0;
|
||||
break;
|
||||
case 0x10:
|
||||
printf("Seg sign: %d\n", value);
|
||||
break;
|
||||
case REG_PKE_SEG_START ... (REG_PKE_SEG_START + 1024):
|
||||
{
|
||||
@@ -83,22 +82,6 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
{
|
||||
s->num_started++;
|
||||
|
||||
if(s->num_started == 5) {
|
||||
printf("Base: 0x");
|
||||
uint32_t *cast = (uint32_t *)(&s->segments[s->segment_size]); // segment 1
|
||||
for(int i = (s->segment_size / 4 - 1); i >= 0; i--) {
|
||||
printf("%08x", cast[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Mod: 0x");
|
||||
cast = (uint32_t *)s->segments; // segment 0
|
||||
for(int i = (s->segment_size / 4 - 1); i >= 0; i--) {
|
||||
printf("%08x", cast[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
if(s->num_started == 5) { // TODO this is arbitrary!
|
||||
|
||||
|
||||
@@ -112,8 +95,8 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
BIGNUM *res = BN_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_mod_exp(res, base_bn, exp_bn, mod_bn, ctx);
|
||||
BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res);
|
||||
printf("\n\n");
|
||||
// BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res);
|
||||
// printf("\n\n");
|
||||
|
||||
char *res_hex = datahex(BN_bn2hex(res));
|
||||
|
||||
@@ -124,14 +107,11 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un
|
||||
break;
|
||||
}
|
||||
case REG_PKE_SEG_SIZE:
|
||||
printf("Setting size: %d\n", value);
|
||||
s->seg_size_reg = value;
|
||||
uint32_t size_bit = (s->seg_size_reg >> 6);
|
||||
if(size_bit == 0) { s->segment_size = 256; }
|
||||
else if(size_bit == 1) { s->segment_size = 128; }
|
||||
else { }
|
||||
printf("Segment size: %d\n", s->segment_size);
|
||||
|
||||
break;
|
||||
case REG_PKE_SWRESET:
|
||||
s->num_started = 0;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "hw/arm/ipod_touch_scaler_csc.h"
|
||||
|
||||
static uint64_t ipod_touch_scaler_csc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
|
||||
|
||||
switch (addr) {
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipod_touch_scaler_csc_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
|
||||
{
|
||||
IPodTouchScalerCSCState *s = IPOD_TOUCH_SCALER_CSC(opaque);
|
||||
//printf("%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ipod_touch_scaler_csc_ops = {
|
||||
.read = ipod_touch_scaler_csc_read,
|
||||
.write = ipod_touch_scaler_csc_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ipod_touch_scaler_csc_init(Object *obj)
|
||||
{
|
||||
IPodTouchScalerCSCState *s = IPOD_TOUCH_SCALER_CSC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &ipod_touch_scaler_csc_ops, s, TYPE_IPOD_TOUCH_SCALER_CSC, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void ipod_touch_scaler_csc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo ipod_touch_scaler_csc_type_info = {
|
||||
.name = TYPE_IPOD_TOUCH_SCALER_CSC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IPodTouchScalerCSCState),
|
||||
.instance_init = ipod_touch_scaler_csc_init,
|
||||
.class_init = ipod_touch_scaler_csc_class_init,
|
||||
};
|
||||
|
||||
static void ipod_touch_scaler_csc_register_types(void)
|
||||
{
|
||||
type_register_static(&ipod_touch_scaler_csc_type_info);
|
||||
}
|
||||
|
||||
type_init(ipod_touch_scaler_csc_register_types)
|
||||
@@ -280,8 +280,8 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp)
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
s->base = base_addr;
|
||||
|
||||
fifo8_create(&s->tx_fifo, R_FIFO_DEPTH);
|
||||
fifo8_create(&s->rx_fifo, R_FIFO_DEPTH);
|
||||
fifo8_create(&s->tx_fifo, R_FIFO_TX_DEPTH);
|
||||
fifo8_create(&s->rx_fifo, R_FIFO_RX_DEPTH);
|
||||
|
||||
// create the peripheral
|
||||
IPodTouchNORSPIState *nor;
|
||||
@@ -296,11 +296,11 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp)
|
||||
nor = IPOD_TOUCH_NOR_SPI(dev);
|
||||
s->nor = nor;
|
||||
break;
|
||||
case 2:
|
||||
case 4:
|
||||
{
|
||||
// DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_MULTITOUCH);
|
||||
// IPodTouchMultitouchState *mt = IPOD_TOUCH_MULTITOUCH(dev);
|
||||
// s->mt = mt;
|
||||
DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_MULTITOUCH);
|
||||
IPodTouchMultitouchState *mt = IPOD_TOUCH_MULTITOUCH(dev);
|
||||
s->mt = mt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.
|
||||
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c'))
|
||||
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
|
||||
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
|
||||
arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c'))
|
||||
arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c'))
|
||||
|
||||
hw_arch += {'arm': arm_ss}
|
||||
+4
-2
@@ -391,8 +391,10 @@ static void pl080_init(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
PL080State *s = PL080(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
memory_region_init_io(&s->iomem1, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem1);
|
||||
memory_region_init_io(&s->iomem2, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem2);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
sysbus_init_irq(sbd, &s->interr);
|
||||
sysbus_init_irq(sbd, &s->inttc);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "hw/arm/ipod_touch_fmss.h"
|
||||
#include "hw/arm/ipod_touch_block_device.h"
|
||||
#include "hw/arm/ipod_touch_mbx.h"
|
||||
#include "hw/arm/ipod_touch_scaler_csc.h"
|
||||
|
||||
#define TYPE_IPOD_TOUCH "iPod-Touch"
|
||||
|
||||
@@ -62,6 +63,7 @@
|
||||
#define SHA1_MEM_BASE 0x38000000
|
||||
#define DMAC0_MEM_BASE 0x38200000
|
||||
#define USBOTG_MEM_BASE 0x38400000
|
||||
#define DMAC1_0_MEM_BASE 0x38700000
|
||||
#define DISPLAY_MEM_BASE 0x38900000
|
||||
#define FMSS_MEM_BASE 0x38A00000
|
||||
#define BLOCK_DEVICE_MEM_BASE 0x38A00F00
|
||||
@@ -71,12 +73,13 @@
|
||||
#define VIC1_MEM_BASE 0x38E01000
|
||||
#define EDGEIC_MEM_BASE 0x38E02000
|
||||
#define H264_MEM_BASE 0x38F00000
|
||||
#define SCALER_CSC_MEM_BASE 0x39000000
|
||||
#define TVOUT1_MEM_BASE 0x39100000
|
||||
#define TVOUT2_MEM_BASE 0x39200000
|
||||
#define TVOUT3_MEM_BASE 0x39300000
|
||||
//#define BLOCK_DEVICE_MEM_BASE 0x39400000
|
||||
#define SYSIC_MEM_BASE 0x39700000
|
||||
#define DMAC1_MEM_BASE 0x39900000
|
||||
#define DMAC1_1_MEM_BASE 0x39900000
|
||||
#define MBX1_MEM_BASE 0x3B000000
|
||||
#define MBX2_MEM_BASE 0x39400000
|
||||
#define SPI0_MEM_BASE 0x3C300000
|
||||
@@ -117,6 +120,7 @@ typedef struct {
|
||||
IPodTouchTimerState *timer1;
|
||||
IPodTouchSPIState *spi0_state;
|
||||
IPodTouchSPIState *spi1_state;
|
||||
IPodTouchSPIState *spi4_state;
|
||||
IPodTouchChipIDState *chipid_state;
|
||||
IPodTouchGPIOState *gpio_state;
|
||||
IPodTouchSYSICState *sysic;
|
||||
@@ -132,6 +136,7 @@ typedef struct {
|
||||
IPodTouchFMSSState *fmss_state;
|
||||
IPodTouchBlockDeviceState *bdev_state;
|
||||
IPodTouchMBXState *mbx_state;
|
||||
IPodTouchScalerCSCState *scaler_csc_state;
|
||||
Clock *sysclk;
|
||||
char nor_path[1024];
|
||||
IT2G_CPREG_VAR_DEF(REG0);
|
||||
|
||||
@@ -11,11 +11,25 @@
|
||||
#define TYPE_IPOD_TOUCH_LCD "ipodtouch.lcd"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchLCDState, IPOD_TOUCH_LCD)
|
||||
|
||||
#define LCD_REFRESH_RATE_FREQUENCY 10
|
||||
|
||||
typedef struct IPodTouchLCDState
|
||||
{
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion *sysmem;
|
||||
MemoryRegion iomem;
|
||||
QemuConsole *con;
|
||||
int invalidate;
|
||||
MemoryRegionSection fbsection;
|
||||
qemu_irq irq;
|
||||
uint32_t lcd_con;
|
||||
|
||||
uint32_t w1_display_resolution_info;
|
||||
uint32_t w1_framebuffer_base;
|
||||
uint32_t w1_hspan;
|
||||
uint32_t w1_display_depth_info;
|
||||
|
||||
QEMUTimer *refresh_timer;
|
||||
} IPodTouchLCDState;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
#ifndef IPOD_TOUCH_MULTITOUCH_H
|
||||
#define IPOD_TOUCH_MULTITOUCH_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/arm/ipod_touch_sysic.h"
|
||||
#include "hw/arm/ipod_touch_gpio.h"
|
||||
|
||||
#define TYPE_IPOD_TOUCH_MULTITOUCH "ipodtouch.multitouch"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMultitouchState, IPOD_TOUCH_MULTITOUCH)
|
||||
|
||||
#define MT_INTERFACE_VERSION 0x1
|
||||
#define MT_FAMILY_ID 81
|
||||
#define MT_ENDIANNESS 0x1
|
||||
#define MT_SENSOR_ROWS 15
|
||||
#define MT_SENSOR_COLUMNS 10
|
||||
#define MT_BCD_VERSION 51
|
||||
#define MT_SENSOR_REGION_DESC 0x0
|
||||
#define MT_SENSOR_REGION_PARAM 0x0
|
||||
#define MT_MAX_PACKET_SIZE 0x294 // 660
|
||||
#define MT_SENSOR_SURFACE_WIDTH 5000
|
||||
#define MT_SENSOR_SURFACE_HEIGHT 7500
|
||||
|
||||
// internal surface width/height
|
||||
#define MT_INTERNAL_SENSOR_SURFACE_WIDTH (9000 - MT_SENSOR_SURFACE_WIDTH) * 84 / 73
|
||||
#define MT_INTERNAL_SENSOR_SURFACE_HEIGHT (13850 - MT_SENSOR_SURFACE_HEIGHT) * 84 / 73
|
||||
|
||||
// report IDs
|
||||
#define MT_REPORT_UNKNOWN1 0x70
|
||||
#define MT_REPORT_FAMILY_ID 0xD1
|
||||
#define MT_REPORT_SENSOR_INFO 0xD3
|
||||
#define MT_REPORT_SENSOR_REGION_DESC 0xD0
|
||||
#define MT_REPORT_SENSOR_REGION_PARAM 0xA1
|
||||
#define MT_REPORT_SENSOR_DIMENSIONS 0xD9
|
||||
|
||||
// report sizes
|
||||
#define MT_REPORT_UNKNOWN1_SIZE 0x1
|
||||
#define MT_REPORT_FAMILY_ID_SIZE 0x1
|
||||
#define MT_REPORT_SENSOR_INFO_SIZE 0x5
|
||||
#define MT_REPORT_SENSOR_REGION_DESC_SIZE 0x1
|
||||
#define MT_REPORT_SENSOR_REGION_PARAM_SIZE 0x1
|
||||
#define MT_REPORT_SENSOR_DIMENSIONS_SIZE 0x8
|
||||
|
||||
#define MT_CMD_HBPP_DATA_PACKET 0x30
|
||||
#define MT_CMD_GET_CMD_STATUS 0xE1
|
||||
#define MT_CMD_GET_INTERFACE_VERSION 0xE2
|
||||
#define MT_CMD_GET_REPORT_INFO 0xE3
|
||||
#define MT_CMD_SHORT_CONTROL_WRITE 0xE4
|
||||
#define MT_CMD_SHORT_CONTROL_READ 0xE6
|
||||
#define MT_CMD_FRAME_READ 0xEA
|
||||
|
||||
// frame types
|
||||
#define MT_FRAME_TYPE_PATH 0x44
|
||||
|
||||
// frame event types
|
||||
#define MT_EVENT_TOUCH_FULL_END 0x0
|
||||
#define MT_EVENT_TOUCH_START 0x3
|
||||
#define MT_EVENT_TOUCH_MOVED 0x4
|
||||
#define MT_EVENT_TOUCH_ENDED 0x7
|
||||
|
||||
typedef struct MTFrameLengthPacket
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t length1;
|
||||
uint8_t length2;
|
||||
uint8_t unused[11];
|
||||
uint8_t checksum1;
|
||||
uint8_t checksum2;
|
||||
} __attribute__((__packed__)) MTFrameLengthPacket;
|
||||
|
||||
typedef struct MTFrameHeader
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t frameNum;
|
||||
uint8_t headerLen;
|
||||
uint8_t unk_3;
|
||||
uint32_t timestamp;
|
||||
uint8_t unk_8;
|
||||
uint8_t unk_9;
|
||||
uint8_t unk_A;
|
||||
uint8_t unk_B;
|
||||
uint16_t unk_C;
|
||||
uint16_t isImage;
|
||||
|
||||
uint8_t numFingers;
|
||||
uint8_t fingerDataLen;
|
||||
uint16_t unk_12;
|
||||
uint16_t unk_14;
|
||||
uint16_t unk_16;
|
||||
} __attribute__((__packed__)) MTFrameHeader;
|
||||
|
||||
typedef struct MTFramePacket
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t unused1;
|
||||
uint8_t length1;
|
||||
uint8_t length2;
|
||||
uint8_t checksum_pad;
|
||||
MTFrameHeader header;
|
||||
} __attribute__((__packed__)) MTFramePacket;
|
||||
|
||||
typedef struct FingerData
|
||||
{
|
||||
uint8_t id;
|
||||
uint8_t event;
|
||||
uint8_t unk_2;
|
||||
uint8_t unk_3;
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t velX;
|
||||
int16_t velY;
|
||||
uint16_t radius2;
|
||||
uint16_t radius3;
|
||||
uint16_t angle;
|
||||
uint16_t radius1;
|
||||
uint16_t contactDensity;
|
||||
uint16_t unk_16;
|
||||
uint16_t unk_18;
|
||||
uint16_t unk_1A;
|
||||
} __attribute__((__packed__)) FingerData;
|
||||
|
||||
typedef struct MTFrame {
|
||||
MTFrameLengthPacket frame_length;
|
||||
MTFramePacket frame_packet;
|
||||
FingerData finger_data; // TODO we assume one finger for now
|
||||
uint8_t checksum1;
|
||||
uint8_t checksum2;
|
||||
} __attribute__((__packed__)) MTFrame;
|
||||
|
||||
typedef struct IPodTouchMultitouchState {
|
||||
SSIPeripheral ssidev;
|
||||
uint8_t cur_cmd;
|
||||
uint8_t *out_buffer;
|
||||
uint8_t *in_buffer;
|
||||
uint32_t buf_size;
|
||||
uint32_t buf_ind;
|
||||
uint32_t in_buffer_ind;
|
||||
uint8_t hbpp_atn_ack_response[2];
|
||||
MTFrame *next_frame;
|
||||
uint32_t frame_counter;
|
||||
bool touch_down;
|
||||
QEMUTimer *touch_timer;
|
||||
QEMUTimer *touch_end_timer;
|
||||
IPodTouchSYSICState *sysic;
|
||||
IPodTouchGPIOState *gpio_state;
|
||||
float touch_x;
|
||||
float touch_y;
|
||||
float prev_touch_x;
|
||||
float prev_touch_y;
|
||||
uint64_t last_frame_timestamp;
|
||||
} IPodTouchMultitouchState;
|
||||
|
||||
void ipod_touch_multitouch_on_touch(IPodTouchMultitouchState *s);
|
||||
void ipod_touch_multitouch_on_release(IPodTouchMultitouchState *s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef HW_ARM_IPOD_TOUCH_SCALER_CSC_H
|
||||
#define HW_ARM_IPOD_TOUCH_SCALER_CSC_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "hw/hw.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "exec/memory.h"
|
||||
|
||||
#define TYPE_IPOD_TOUCH_SCALER_CSC "ipodtouch.scalercsc"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchScalerCSCState, IPOD_TOUCH_SCALER_CSC)
|
||||
|
||||
|
||||
typedef struct IPodTouchScalerCSCState {
|
||||
SysBusDevice busdev;
|
||||
MemoryRegion iomem;
|
||||
} IPodTouchScalerCSCState;
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/arm/ipod_touch_nor_spi.h"
|
||||
#include "hw/arm/ipod_touch_multitouch.h"
|
||||
|
||||
#define TYPE_IPOD_TOUCH_SPI "ipodtouch.spi"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI)
|
||||
@@ -49,7 +50,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI)
|
||||
#define R_WORD_DELAY 0x038
|
||||
#define R_TXCNT 0x04c
|
||||
|
||||
#define R_FIFO_DEPTH 16
|
||||
#define R_FIFO_TX_DEPTH 50000
|
||||
#define R_FIFO_RX_DEPTH 16
|
||||
|
||||
#define REG(_s,_v) ((_s)->regs[(_v)>>2])
|
||||
#define MMIO_SIZE (0x4000)
|
||||
@@ -60,16 +62,17 @@ typedef struct IPodTouchSPIState {
|
||||
|
||||
MemoryRegion iomem;
|
||||
SSIBus *spi;
|
||||
IPodTouchMultitouchState *mt;
|
||||
|
||||
qemu_irq irq;
|
||||
uint32_t last_irq;
|
||||
qemu_irq cs_line;
|
||||
|
||||
Fifo8 rx_fifo;
|
||||
Fifo8 tx_fifo;
|
||||
uint32_t regs[MMIO_SIZE >> 2];
|
||||
uint8_t base;
|
||||
IPodTouchNORSPIState *nor;
|
||||
Fifo8 rx_fifo;
|
||||
Fifo8 tx_fifo;
|
||||
} IPodTouchSPIState;
|
||||
|
||||
void set_spi_base(uint32_t base);
|
||||
|
||||
@@ -49,7 +49,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(PL080State, PL080)
|
||||
struct PL080State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
MemoryRegion iomem1;
|
||||
MemoryRegion iomem2;
|
||||
uint8_t tc_int;
|
||||
uint8_t tc_mask;
|
||||
uint8_t err_int;
|
||||
|
||||
Reference in new issue
Block a user