Compare commits

..
2 Commits
Author SHA1 Message Date
Martijn de Vos 6d8ef87cc0 Integrated USB/TCP stack from T8030 2024-01-16 21:54:09 +01:00
Martijn de Vos a0698a741e Worked on DFU mode 2024-01-13 19:30:49 +01:00
38 changed files with 771 additions and 2100 deletions

No files matched your search

-19
View File
@@ -2,18 +2,6 @@
This file contains the instructions on how to run the iPod Touch 2G emulator using QEMU.
Note that this is an experimental release and the functionality of the device is still limited.
Linux compatibility is currently unstable. Efforts are underway to improve it.
### Getting the Source Code
Clone the repository using the following commands:
```
git clone https://github.com/devos50/qemu-ios.git
cd qemu-ios
```
Now you can proceed with the rest of the instructions for building and running the emulator.
### Building QEMU
@@ -26,9 +14,6 @@ brew install glib ninja pixman pkg-config sdl2
# On Linux (Ubuntu)
sudo apt install make ninja-build pkg-config libssl-dev libsdl2-dev libpixman-1-dev libpixman-1-0 libglib2.0-dev
# On Linux (Arch)
sudo pacman -S --needed make ninja pkgconf openssl sdl2 pixman glib2
# On Windows (MSYS2/mingw64)
pacman -S base-devel mingw-w64-x86_64-toolchain git python ninja mingw-w64-x86_64-glib2 mingw-w64-x86_64-pixman python-setuptools mingw-w64-x86_64-SDL2
@@ -38,16 +23,12 @@ Compile QEMU by running the following commands from the root directory:
```
mkdir build
cd build
# On Intel Macs
../configure --target-list=arm-softmmu --extra-cflags=-I/usr/local/opt/openssl@3/include --extra-ldflags='-L/usr/local/opt/openssl@3/lib -lcrypto'
# On Apple Silicon Macs
../configure --enable-sdl --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/opt/homebrew/opt/openssl@3/include --extra-ldflags='-L/opt/homebrew/opt/openssl@3/lib -lcrypto'
# On Linux
../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --extra-cflags=-I/usr/include/openssl --extra-ldflags='-lcrypto' --disable-werror --enable-pie
# On Microsoft Windows (with MINGW64)
../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --disable-pie --extra-cflags=-I/mingw64/include/openssl --extra-ldflags='-L/mingw64/lib -lcrypto' --disable-stack-protector --disable-werror
+17 -20
View File
@@ -96,7 +96,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem,
// load the bootrom (vrom)
uint8_t *file_data = NULL;
gsize fsize;
unsigned long fsize;
if (g_file_get_contents(nms->bootrom_path, (char **)&file_data, &fsize, NULL)) {
allocate_ram(sysmem, "vrom", 0x0, 0x20000);
address_space_rw(nsas, VROM_MEM_BASE, MEMTXATTRS_UNSPECIFIED, (uint8_t *)file_data, fsize, 1);
@@ -174,13 +174,6 @@ static inline qemu_irq s5l8900_get_irq(IPodTouchMachineState *s, int n)
return s->irq[n / S5L8720_VIC_SIZE][n % S5L8720_VIC_SIZE];
}
static uint32_t s5l8720_usb_hwcfg[] = {
0,
0x7a8f60d0,
0x082000e8,
0x01f08024
};
static void ipod_touch_key_event(void *opaque, int keycode)
{
bool do_irq = false;
@@ -236,7 +229,6 @@ static void ipod_touch_key_event(void *opaque, int keycode)
gpio_set_off(s->gpio_state->gpio_state, GPIO_BUTTON_VOLUP);
}
}
else return;
s->sysic->gpio_int_status[gpio_group] |= (1 << gpio_selector);
qemu_irq_raise(s->sysic->gpio_irqs[gpio_group]);
@@ -404,13 +396,24 @@ static void ipod_touch_machine_init(MachineState *machine)
memory_region_add_subregion(sysmem, UNKNOWN1_MEM_BASE, &unknown1_state->iomem);
// init USB OTG
dev = ipod_touch_init_usb_otg(s5l8900_get_irq(nms, S5L8720_USB_OTG_IRQ), s5l8720_usb_hwcfg);
synopsys_usb_state *usb_otg = S5L8900USBOTG(dev);
nms->usb_otg = usb_otg;
dev = qdev_new("dwc2-usb");
DWC2State *dwc2 = DWC2_USB(dev);
nms->dwc2 = dwc2;
memory_region_add_subregion(sysmem, USBOTG_MEM_BASE, &dwc2->container);
// TODO add IRQ etc
memory_region_init(&nms->usb_dma_container_mr, OBJECT(dev), "appleusb.dma-container-mr", UINT32_MAX);
object_property_add_const_link(OBJECT(nms->dwc2), "dma-mr", OBJECT(&nms->usb_dma_container_mr));
busdev = SYS_BUS_DEVICE(dev);
memory_region_add_subregion(sysmem, USBOTG_MEM_BASE, &nms->usb_otg->iomem);
sysbus_realize(busdev, &error_fatal);
// create the TCP host and connect the busses
dev = qdev_new(TYPE_USB_TCP_HOST);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize(busdev, &error_fatal);
BusState *bus = QLIST_FIRST(&DEVICE(busdev)->child_bus);
qdev_realize(DEVICE(nms->dwc2->device), bus, &error_fatal);
// init two pl080 DMAC0 devices
dev = qdev_new("pl080");
PL080State *pl080_1 = PL080(dev);
@@ -445,9 +448,6 @@ static void ipod_touch_machine_init(MachineState *machine)
// init the accelerometer
I2CSlave *accelerometer = i2c_slave_create_simple(i2c_state->bus, "lis302dl", 0x1D);
// init the audio codec (disabled because unused)
// I2CSlave *audio_codec = i2c_slave_create_simple(i2c_state->bus, "cs42l58", 0x4A);
// Init I2C1
dev = qdev_new("ipodtouch.i2c");
i2c_state = IPOD_TOUCH_I2C(dev);
@@ -457,9 +457,6 @@ static void ipod_touch_machine_init(MachineState *machine)
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 light sensor
I2CSlave *isl29003dl = i2c_slave_create_simple(i2c_state->bus, "isl29003dl", 0x44);
// init the Mikey
I2CSlave *cd327mikey = i2c_slave_create_simple(i2c_state->bus, "cd3272mikey", 0x39);
@@ -564,4 +561,4 @@ static void ipod_touch_machine_types(void)
type_register_static(&ipod_touch_machine_info);
}
type_init(ipod_touch_machine_types)
type_init(ipod_touch_machine_types)
-54
View File
@@ -1,54 +0,0 @@
#include "hw/arm/ipod_touch_cs42l58.h"
static int cs42l58_event(I2CSlave *i2c, enum i2c_event event)
{
return 0;
}
static uint8_t cs42l58_recv(I2CSlave *i2c)
{
CS42L58State *s = CS42L58(i2c);
printf("Reading stereo codec register %d\n", s->cmd);
switch(s->cmd) {
default:
return 0;
}
}
static int cs42l58_send(I2CSlave *i2c, uint8_t data)
{
CS42L58State *s = CS42L58(i2c);
s->cmd = data;
printf("Writing stereo codec register %d\n", s->cmd);
return 0;
}
static void cs42l58_init(Object *obj)
{
}
static void cs42l58_class_init(ObjectClass *klass, void *data)
{
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
k->event = cs42l58_event;
k->recv = cs42l58_recv;
k->send = cs42l58_send;
}
static const TypeInfo cs42l58_info = {
.name = TYPE_CS42L58,
.parent = TYPE_I2C_SLAVE,
.instance_init = cs42l58_init,
.instance_size = sizeof(CS42L58State),
.class_init = cs42l58_class_init,
};
static void cs42l58_register_types(void)
{
type_register_static(&cs42l58_info);
}
type_init(cs42l58_register_types)
+7 -14
View File
@@ -1,7 +1,5 @@
#include "hw/arm/ipod_touch_fmss.h"
uint64_t temp_storage[512];
static uint8_t find_bit_index(uint8_t num) {
int index = 0;
while (num > 1) {
@@ -26,7 +24,7 @@ static void dump_registers(IPodTouchFMSSState *s) {
static void read_nand_pages(IPodTouchFMSSState *s)
{
// boot args
const char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 pmu-debug=0x1 io=0xffff8fff debug-usb=0xffffffff amfi_allow_any_signature=1 -v zalloc_debug"; // if not const then overwritten
const char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 pmu-debug=0x1 io=0xffff8fff debug-usb=0xffffffff amfi_allow_any_signature=1"; // if not const then overwritten
cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args));
// patch iBoot - we want to inject the bluetooth MAC address which is located as sub-node of uart1 and not uart3 in the device tree...
@@ -47,7 +45,7 @@ static void read_nand_pages(IPodTouchFMSSState *s)
if(cs > 3) {
printf("CS %d invalid! (original CS: %d, reading page %d)\n", cs, og_cs, page_nr);
//dump_registers(s);
dump_registers(s);
hw_error("CS %d invalid!", cs);
}
@@ -88,7 +86,7 @@ static void read_nand_pages(IPodTouchFMSSState *s)
static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size)
{
//fprintf(stderr, "%s: read from location 0x%08lx\n", __func__, addr);
//fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr);
IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque;
switch(addr)
@@ -103,10 +101,8 @@ static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size)
return (0x1 << 30);
case 0xD00:
return 42;
case 0x00000C30:
return 0x1;
default:
printf("%s: read invalid location 0x%08x.\n", __func__, addr);
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
break;
}
return 0;
@@ -115,7 +111,7 @@ static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size)
static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque;
//printf("%s: writing 0x%08lx to 0x%08lx\n", __func__, val, addr);
//printf("%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
switch(addr) {
case 0xC00:
@@ -150,11 +146,8 @@ static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsig
break;
case 0xD38:
if(s->reg_csgenrc == 0xa01) { read_nand_pages(s); }
else { /*printf("NAND write %ld addr %ld\n", val, addr); temp_storage[addr] = val;*//*cpu_physical_memory_write(addr, val, sizeof(val)); */}
break;
default:
//printf("%s unknown write %lx to %lx\n", __func__, val, addr);
break;
else { printf("NAND write not suported yet!\n"); }
}
}
+3 -1
View File
@@ -2,9 +2,11 @@
static void s5l8900_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
IPodTouchGPIOState *s = (struct IPodTouchGPIOState *) opaque;
// TODO this should be implemented at one point
switch(addr) {
default:
break;
-101
View File
@@ -1,101 +0,0 @@
#include "hw/arm/ipod_touch_isl29003dl.h"
static int isl29003dl_event(I2CSlave *i2c, enum i2c_event event)
{
ISL29003DLState *s = ISL29003DL(i2c);
printf("%s Got event %d\n", __func__, event);
if (event == I2C_START_SEND)
s->ready = 1;
return 0;
}
static uint8_t isl29003dl_recv(I2CSlave *i2c)
{
ISL29003DLState *s = ISL29003DL(i2c);
printf("Reading lightsensor register %d\n", s->cmd);
int res = 0;
switch(s->cmd) {
case LIGHTSENSOR_COMMAND:
res = s->command;
break;
case LIGHTSENSOR_CONTROL:
res = s->ctrl;
break;
case LIGHTSENSOR_LSB_SENSOR:
res = s->lsb_sensor;
break;
case LIGHTSENSOR_MSB_SENSOR:
res = s->msb_sensor;
break;
default:
res = 0;
printf("%s unknown register %d\n", __func__, s->cmd);
}
s->cmd += 1;
return res;
}
static int isl29003dl_send(I2CSlave *i2c, uint8_t data)
{
ISL29003DLState *s = ISL29003DL(i2c);
if (s->ready)
{
s->curreg = data;
s->ready = 0;
printf("%s Lightsensor ready\n", __func__);
}
else
{
switch(s->curreg++)
{
case LIGHTSENSOR_COMMAND:
s->command = data;
if ((s->command >> 7) == 1)
{
s->lsb_sensor = 0xE;
s->msb_sensor = 0xE << 4;
s->it_hi = 0xF;
s->it_lo = 0x0;
}
break;
default:
printf("%s unknown register %d\n", __func__, s->curreg-1);
}
}
printf("Writing lightsensor data %d\n", s->cmd);
return 0;
}
static void isl29003dl_init(Object *obj)
{
}
static void isl29003dl_class_init(ObjectClass *klass, void *data)
{
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
k->event = isl29003dl_event;
k->recv = isl29003dl_recv;
k->send = isl29003dl_send;
}
static const TypeInfo isl29003dl_info = {
.name = TYPE_ISL29003DL,
.parent = TYPE_I2C_SLAVE,
.instance_init = isl29003dl_init,
.instance_size = sizeof(ISL29003DLState),
.class_init = isl29003dl_class_init,
};
static void isl29003dl_register_types(void)
{
type_register_static(&isl29003dl_info);
}
type_init(isl29003dl_register_types)
+11 -25
View File
@@ -3,11 +3,9 @@
#include "ui/console.h"
#include "hw/display/framebuffer.h"
int lcd_brightness = 255;
static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size)
{
// printf("%s: read from location 0x%08x\n", __func__, addr);
//printf("%s: read from location 0x%08x\n", __func__, addr);
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
switch(addr)
@@ -28,10 +26,8 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size)
return s->w1_display_resolution_info;
case 0x1b10:
return 2;
case 0x1b14:
return 0x3;
default:
printf("%s: read invalid location 0x%08x.\n", __func__, addr);
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
break;
}
return 0;
@@ -40,16 +36,15 @@ 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;
// printf("%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
//printf("%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
switch(addr) {
case 0x4:
s->lcd_con = val;
break;
case 0xC:
s->render = val;
s->unknown1 = val;
qemu_irq_lower(s->irq);
// qemu_irq_raise(s->irq);
break;
case 0x20:
s->w1_display_depth_info = val;
@@ -66,11 +61,6 @@ static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsign
}
}
void lcd_changebrightness(int brightness)
{
lcd_brightness = brightness & 0xFF;
}
static void lcd_invalidate(void *opaque)
{
IPodTouchLCDState *s = opaque;
@@ -79,7 +69,6 @@ static void lcd_invalidate(void *opaque)
static void draw_line32_32(void *opaque, uint8_t *d, const uint8_t *s, int width, int deststep)
{
// IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque;
uint8_t r, g, b;
do {
@@ -88,8 +77,8 @@ static void draw_line32_32(void *opaque, uint8_t *d, const uint8_t *s, int width
b = s[0];
g = s[1];
r = s[2];
// printf("R: %d, G: %d, B: %d, A: %d\n", r, g, b, lcd_brightness);
((uint32_t *) d)[0] = rgb_to_pixel32(round((float)r * ((float)lcd_brightness / 255.0f)), round((float)g * ((float)lcd_brightness / 255.0f)), round((float)b * ((float)lcd_brightness / 255.0f)));
//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);
@@ -97,7 +86,7 @@ static void draw_line32_32(void *opaque, uint8_t *d, const uint8_t *s, int width
static void lcd_refresh(void *opaque)
{
// printf("%s: refreshing LCD screen\n", __func__);
//fprintf(stderr, "%s: refreshing LCD screen\n", __func__);
IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque;
DisplaySurface *surface = qemu_console_surface(lcd->con);
@@ -152,7 +141,7 @@ static const GraphicHwOps gfx_ops = {
static void ipod_touch_lcd_mouse_event(void *opaque, int x, int y, int z, int buttons_state)
{
// printf("x %d y %d z %d state %d\n", x, y, z, 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);
@@ -176,12 +165,9 @@ static void refresh_timer_tick(void *opaque)
{
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
if (s->render == 0x1)
qemu_irq_raise(s->irq);
else if (s->render == 0xFF)
qemu_irq_lower(s->irq);
qemu_irq_raise(s->irq);
timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 60);//LCD_REFRESH_RATE_FREQUENCY);
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)
@@ -229,4 +215,4 @@ static void ipod_touch_machine_types(void)
type_register_static(&ipod_touch_lcd_info);
}
type_init(ipod_touch_machine_types)
type_init(ipod_touch_machine_types)
+2 -15
View File
@@ -12,21 +12,8 @@ static uint8_t lis302dl_recv(I2CSlave *i2c)
switch(s->cmd) {
case ACCEL_WHOAMI:
return ACCEL_WHOAMI_VALUE;
case ACCEL_OUT_X:
return s->ctrl_reg1 == 1 ? s->out_x : 0;
case ACCEL_OUT_Y:
return s->ctrl_reg1 << 1 == 1 ? s->out_y : 0;
case ACCEL_OUT_Z:
return s->ctrl_reg1 << 2 == 1 ? s->out_z : 0;
case ACCEL_CTRL_REG1:
return s->ctrl_reg1;
case ACCEL_CTRL_REG2:
return s->ctrl_reg2;
case ACCEL_CTRL_REG3:
return s->ctrl_reg3;
return ACCEL_WHOAMI_VALUE; // whoami value
default:
printf("%s Unknown register %d\n", __func__, s->cmd);
return 0;
}
}
@@ -65,4 +52,4 @@ static void lis302dl_register_types(void)
type_register_static(&lis302dl_info);
}
type_init(lis302dl_register_types)
type_init(lis302dl_register_types)
+5 -21
View File
@@ -9,9 +9,7 @@ static uint32_t reverse_byte_order(uint32_t value) {
static uint64_t ipod_touch_mbx1_read(void *opaque, hwaddr addr, unsigned size)
{
IPodTouchMBXState *s = (IPodTouchMBXState *)opaque;
if (addr != 0x1020)
printf("%s: read from location 0x%08x\n", __func__, addr);
printf("%s: read from location 0x%08x\n", __func__, addr);
switch(addr)
{
case 0x12c:
@@ -19,7 +17,7 @@ static uint64_t ipod_touch_mbx1_read(void *opaque, hwaddr addr, unsigned size)
case 0xf00:
return (2 << 0x10) | (1 << 0x18); // seems to be some kind of identifier
case 0x1020:
return s->addr != 0x0 ? s->addr : 0x10000;
return 0x10000;
default:
break;
}
@@ -30,19 +28,10 @@ static void ipod_touch_mbx1_write(void *opaque, hwaddr addr, uint64_t val, unsig
{
IPodTouchMBXState *s = (IPodTouchMBXState *)opaque;
fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
switch(addr)
{
case 0x1020:
s->addr = val;
break;
}
}
static void patch_kernel(bool alreadypatched)
static void patch_kernel()
{
if (alreadypatched) return;
alreadypatched = 1;
// patch the loading of the AppleBCM4325 driver
char *bcm4325_vars = "test";
@@ -102,16 +91,11 @@ static void patch_kernel(bool alreadypatched)
static uint64_t ipod_touch_mbx2_read(void *opaque, hwaddr addr, unsigned size)
{
IPodTouchMBXState *s = (IPodTouchMBXState *)opaque;
printf("%s: read from location 0x%08x\n", __func__, addr);
switch(addr)
{
case 0xC:
patch_kernel(s->alreadypatched);
break;
case 0x4:
return 0xFF;
break;
patch_kernel();
default:
break;
}
@@ -165,4 +149,4 @@ static void ipod_touch_mbx_register_types(void)
type_register_static(&ipod_touch_mbx_type_info);
}
type_init(ipod_touch_mbx_register_types)
type_init(ipod_touch_mbx_register_types)
+4 -8
View File
@@ -2,8 +2,7 @@
static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned size)
{
if (addr != 0x00000)
fprintf(stderr, "%s: read from location 0x%08lx\n", __func__, addr);
fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr);
IPodTouchMIPIDSIState *s = (IPodTouchMIPIDSIState *)opaque;
switch(addr)
@@ -25,7 +24,7 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz
case REG_FIFOCTRL:
return rDSIM_FIFOCTRL_EmptyHSfr;
default:
printf("%s: read invalid location 0x%08lx.\n", __func__, addr);
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
break;
}
return 0;
@@ -34,16 +33,13 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz
static void ipod_touch_mipi_dsi_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
IPodTouchMIPIDSIState *s = (IPodTouchMIPIDSIState *)opaque;
fprintf(stderr, "%s: writing 0x%08lx to 0x%08lx\n", __func__, val, addr);
fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
switch(addr)
{
case REG_PKTHDR:
s->pkthdr_reg = val;
break;
case 0x00000008:
if (val == 0)
printf("turning off screen\n");
default:
break;
}
@@ -93,4 +89,4 @@ static void ipod_touch_machine_types(void)
type_register_static(&ipod_touch_mipi_dsi_info);
}
type_init(ipod_touch_machine_types)
type_init(ipod_touch_machine_types)
+1 -1
View File
@@ -199,7 +199,7 @@ static uint32_t ipod_touch_multitouch_transfer(SSIPeripheral *dev, uint32_t valu
s->out_buffer = (uint8_t *) s->next_frame;
}
else {
printf("%s Unknown command 0x%02x!\n", __func__, value);
hw_error("Unknown command 0x%02x!", value);
}
}
+3 -3
View File
@@ -2,7 +2,7 @@
static void initialize_nor(IPodTouchNORSPIState *s)
{
gsize fsize;
unsigned long fsize;
if (g_file_get_contents(s->nor_path, (char **)&s->nor_data, &fsize, NULL)) {
s->nor_initialized = true;
}
@@ -67,8 +67,8 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value)
s->out_buf[2] = 0x02;
}
else {
printf("%s Unknown command 0x%02x!\n", __func__, value);
// hw_error("Unknown command 0x%02x!", value);
printf("Unknown command %d!\n", value);
hw_error("Unknown command 0x%02x!", value);
}
return 0x0;
+4 -33
View File
@@ -1,21 +1,7 @@
#include "hw/arm/ipod_touch_pcf50633_pmu.h"
#include "hw/arm/ipod_touch_lcd.h"
static int pcf50633_event(I2CSlave *i2c, enum i2c_event event)
{
Pcf50633State *s = PCF50633(i2c);
// printf("%s Event %d\n", __func__, s->cmd);
if (event == I2C_START_SEND)
{
// printf("%s start send %d\n", __func__, s->cmd);
}
else if (event == I2C_FINISH)
{
s->ready = 1;
// printf("%s end send %d\n", __func__, s->cmd);
}
return 0;
}
@@ -41,10 +27,10 @@ static uint8_t pcf50633_recv(I2CSlave *i2c)
switch(s->cmd) {
case PMU_MBCS1:
res = 1; // battery power source
res = 0; // battery power source
break;
case PMU_ADCC1:
res = 3; // battery charge voltage
res = 0; // battery charge voltage
break;
case PMU_RTCSC: // seconds
res = int_to_bcd(tm.tm_sec);
@@ -84,22 +70,7 @@ static uint8_t pcf50633_recv(I2CSlave *i2c)
static int pcf50633_send(I2CSlave *i2c, uint8_t data)
{
Pcf50633State *s = PCF50633(i2c);
if (s->ready)
{
s->curreg = data;
s->ready = 0;
}
else
{
s->cmd = data;
}
printf("Writing PMU register cmd %d reg %d\n", s->cmd, s->curreg);
switch(s->curreg) {
case PMU_DSBL1:
lcd_changebrightness(s->cmd);
break;
}
s->cmd = data;
return 0;
}
@@ -130,4 +101,4 @@ static void pcf50633_register_types(void)
type_register_static(&pcf50633_info);
}
type_init(pcf50633_register_types)
type_init(pcf50633_register_types)
+9 -12
View File
@@ -12,7 +12,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s)
uint32_t cmd_type = s->cmd & 0x3f;
uint32_t addr = (s->arg >> 9) & 0x1ffff;
uint32_t func = (s->arg >> 28) & 0x7;
printf("SDIO CMD: %d, ADDR: %d, FUNC: %d\n", cmd_type, addr, func);
//printf("SDIO CMD: %d, ADDR: %d, FUNC: %d\n", cmd_type, addr, func);
if(cmd_type == 0x3) {
// RCA request - ignore
}
@@ -52,7 +52,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s)
// CMD53 - block transfer
addr = addr & 0x7fff;
bool is_write = (s->arg >> 31) != 0;
printf("SDIO: Executing cmd53 func %x with block size %d and %d blocks (reg address: 0x%08x, destination address: 0x%08x, write? %d)\n", func, s->blklen, s->numblk, addr, s->baddr, is_write);
printf("SDIO: Executing cmd53 with block size %d and %d blocks (reg address: 0x%08x, destination address: 0x%08x, write? %d)\n", s->blklen, s->numblk, addr, s->baddr, is_write);
if(is_write) {
if(func == 0x1) {
@@ -61,7 +61,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s)
else if(func == 0x2) {
// this is a BCM4325 command - add a frame to the queue and schedule the IRQ request to indicate that the command has been completed
BCM4325FrameHeaderPacket *frame_header = calloc(sizeof(BCM4325FrameHeaderPacket), sizeof(uint8_t *));
uint16_t length = s->blklen * s->numblk;
uint16_t length = 14;
frame_header->frame_length = length;
frame_header->checksum = length ^ 0xffff;
g_queue_push_tail(s->rx_fifo, frame_header);
@@ -83,9 +83,6 @@ void sdio_exec_cmd(IPodTouchSDIOState *s)
if(!frame_header) {
// create an empty frame
frame_header = calloc(sizeof(BCM4325FrameHeaderPacket), sizeof(uint8_t *));
frame_header->frame_length = s->blklen * s->numblk;
frame_header->checksum = (s->blklen * s->numblk) ^ 0xffff;
}
cpu_physical_memory_write(s->baddr, frame_header, sizeof(BCM4325FrameHeaderPacket));
}
@@ -104,7 +101,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s)
static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
//printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
IPodTouchSDIOState *s = (struct IPodTouchSDIOState *) opaque;
@@ -149,7 +146,7 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns
static uint64_t ipod_touch_sdio_read(void *opaque, hwaddr addr, unsigned size)
{
printf("%s: offset = 0x%08x\n", __func__, addr);
//printf("%s: offset = 0x%08x\n", __func__, addr);
IPodTouchSDIOState *s = (struct IPodTouchSDIOState *) opaque;
@@ -167,11 +164,11 @@ static uint64_t ipod_touch_sdio_read(void *opaque, hwaddr addr, unsigned size)
case SDIO_RESP0:
return s->resp0;
case SDIO_RESP1:
return s->resp1 == 0 ? 0x7465 : s->resp1;
return s->resp1;
case SDIO_RESP2:
return s->resp2 == 0 ? 0x7374 : s->resp2;
return s->resp2;
case SDIO_RESP3:
return s->resp3 == 0 ? 0xFFFF : s->resp3;
return s->resp3;
case SDIO_CSR:
return s->csr;
case SDIO_IRQ:
@@ -252,4 +249,4 @@ static void ipod_touch_sdio_register_types(void)
type_register_static(&ipod_touch_sdio_type_info);
}
type_init(ipod_touch_sdio_register_types)
type_init(ipod_touch_sdio_register_types)
+3 -2
View File
@@ -1,6 +1,7 @@
#include "hw/arm/ipod_touch_sha1.h"
static uint64_t swapLong(uint64_t x) {
static uint64_t swapLong(void *X) {
uint64_t x = (uint64_t) X;
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
@@ -149,4 +150,4 @@ static void ipod_touch_machine_types(void)
type_register_static(&ipod_touch_sha1_info);
}
type_init(ipod_touch_machine_types)
type_init(ipod_touch_machine_types)
+2 -2
View File
@@ -93,7 +93,7 @@ static uint64_t s5l8900_timer1_read(void *opaque, hwaddr addr, unsigned size)
case TIMER_TICKSLOW:
return s->ticks_low;
case TIMER_IRQSTAT:
return s->irqstat; // ~0; // s->irqstat;
return ~0; // s->irqstat;
case TIMER_IRQLATCH:
return 0xffffffff;
@@ -140,4 +140,4 @@ static void ipod_touch_machine_types(void)
type_register_static(&ipod_touch_timer_info);
}
type_init(ipod_touch_machine_types)
type_init(ipod_touch_machine_types)
+2 -2
View File
@@ -2,7 +2,7 @@
static uint64_t ipod_touch_unknown1_read(void *opaque, hwaddr addr, unsigned size)
{
fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
switch (addr) {
case 0x140:
@@ -53,4 +53,4 @@ static void ipod_touch_unknown1_register_types(void)
type_register_static(&ipod_touch_unknown1_type_info);
}
type_init(ipod_touch_unknown1_register_types)
type_init(ipod_touch_unknown1_register_types)
-777
View File
@@ -1,777 +0,0 @@
/*
* Synopsys DesignWareCore for USB OTG.
*
* Copyright (c) 2011 Richard Ian Taylor.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "hw/platform-bus.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/arm/ipod_touch_usb_otg.h"
static inline size_t synopsys_usb_tx_fifo_start(synopsys_usb_state *_state, uint32_t _fifo)
{
if(_fifo == 0)
return _state->gnptxfsiz >> 16;
else
return _state->dptxfsiz[_fifo-1] >> 16;
}
static inline size_t synopsys_usb_tx_fifo_size(synopsys_usb_state *_state, uint32_t _fifo)
{
if(_fifo == 0)
return _state->gnptxfsiz & 0xFFFF;
else
return _state->dptxfsiz[_fifo-1] & 0xFFFF;
}
static void synopsys_usb_update_irq(synopsys_usb_state *_state)
{
_state->daintsts = 0;
_state->gintsts &=~ (GINTMSK_OEP | GINTMSK_INEP | GINTMSK_OTG);
if(_state->gotgint)
_state->gintsts |= GINTMSK_OTG;
int i;
for(i = 0; i < USB_NUM_ENDPOINTS; i++)
{
if(_state->out_eps[i].interrupt_status & _state->doepmsk)
{
_state->daintsts |= 1 << (i+DAINT_OUT_SHIFT);
if(_state->daintmsk & (1 << (i+DAINT_OUT_SHIFT)))
_state->gintsts |= GINTMSK_OEP;
}
if(_state->in_eps[i].interrupt_status & _state->diepmsk)
{
_state->daintsts |= 1 << (i+DAINT_IN_SHIFT);
if(_state->daintmsk & (1 << (i+DAINT_IN_SHIFT)))
_state->gintsts |= GINTMSK_INEP;
}
}
if((_state->pcgcctl & 3) == 0 && _state->gintmsk & _state->gintsts)
{
//printf("USB: IRQ triggered 0x%08x & 0x%08x.\n", _state->gintsts, _state->gintmsk);
qemu_irq_raise(_state->irq);
}
else
qemu_irq_lower(_state->irq);
}
static void synopsys_usb_update_ep(synopsys_usb_state *_state, synopsys_usb_ep_state *_ep)
{
if(_ep->control & USB_EPCON_SETNAK)
{
_ep->control |= USB_EPCON_NAKSTS;
_ep->interrupt_status |= USB_EPINT_INEPNakEff;
_ep->control &=~ USB_EPCON_SETNAK;
}
if(_ep->control & USB_EPCON_DISABLE)
{
_ep->interrupt_status |= USB_EPINT_EPDisbld;
_ep->control &=~ (USB_EPCON_DISABLE | USB_EPCON_ENABLE);
}
}
static void synopsys_usb_update_in_ep(synopsys_usb_state *_state, uint8_t _ep)
{
synopsys_usb_ep_state *eps = &_state->in_eps[_ep];
synopsys_usb_update_ep(_state, eps);
if(eps->control & USB_EPCON_ENABLE)
;printf("USB: IN transfer queued on %d.\n", _ep);
}
static void synopsys_usb_update_out_ep(synopsys_usb_state *_state, uint8_t _ep)
{
synopsys_usb_ep_state *eps = &_state->out_eps[_ep];
synopsys_usb_update_ep(_state, eps);
if(eps->control & USB_EPCON_ENABLE)
;//printf("USB: OUT transfer queued on %d.\n", _ep);
}
static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_usb_header_t *_hdr, char *_buffer)
{
synopsys_usb_state *state = _arg;
_hdr->addr = (state->dcfg & DCFG_DEVICEADDRMSK) >> DCFG_DEVICEADDR_SHIFT;
if(_hdr->flags & tcp_usb_reset)
{
state->gintsts |= GINTMSK_RESET;
synopsys_usb_update_irq(state);
return 0;
}
if(_hdr->flags & tcp_usb_enumdone)
{
state->gintsts |= GINTMSK_ENUMDONE;
}
int ret;
uint8_t ep = _hdr->ep & 0x7f;
if(_hdr->ep & USB_DIR_IN)
{
synopsys_usb_ep_state *eps = &state->in_eps[ep];
if(eps->control & USB_EPCON_STALL)
{
eps->control &=~ USB_EPCON_STALL; // Should this be EP0 only
//printf("USB: Stall.\n");
ret = USB_RET_STALL;
}
else if(eps->control & USB_EPCON_ENABLE)
{
// Do IN transfer!
eps->control &=~ USB_EPCON_ENABLE;
size_t sz = eps->tx_size & DEPTSIZ_XFERSIZ_MASK;
size_t amtDone = sz;
if(amtDone > _hdr->length)
amtDone = _hdr->length;
if(eps->fifo >= USB_NUM_FIFOS)
hw_error("usb_synopsys: USB transfer on non-existant FIFO %d!\n", eps->fifo);
size_t txfz = synopsys_usb_tx_fifo_size(state, eps->fifo);
if(amtDone > txfz)
amtDone = txfz;
size_t txfs = synopsys_usb_tx_fifo_start(state, eps->fifo);
if(txfs + txfz > sizeof(state->fifos))
hw_error("usb_synopsys: USB transfer would overflow FIFO buffer!\n");
printf("USB: Starting IN transfer on EP %d (%d bytes)...\n", ep, amtDone);
if(amtDone > 0)
{
if(eps->dma_address)
{
cpu_physical_memory_read(eps->dma_address, &state->fifos[txfs], amtDone);
eps->dma_address += amtDone;
}
memcpy(_buffer, (char*)&state->fifos[txfs], amtDone);
}
printf("USB: IN transfer complete!\n");
eps->tx_size = (eps->tx_size &~ DEPTSIZ_XFERSIZ_MASK)
| ((sz-amtDone) & DEPTSIZ_XFERSIZ_MASK);
eps->interrupt_status |= USB_EPINT_XferCompl;
ret = amtDone;
}
else
ret = USB_RET_NAK;
}
else // OUT
{
synopsys_usb_ep_state *eps = &state->out_eps[ep];
printf("EPS control: %d\n", eps->control);
if(eps->control & USB_EPCON_STALL)
{
eps->control &=~ USB_EPCON_STALL; // Should this be EP0 only
//printf("USB: Stall.\n");
ret = USB_RET_STALL;
}
else if(eps->control & USB_EPCON_ENABLE)
{
// Do OUT transfer!
eps->control &=~ USB_EPCON_ENABLE;
size_t sz = eps->tx_size & DEPTSIZ_XFERSIZ_MASK;
size_t amtDone = sz;
if(amtDone > _hdr->length)
amtDone = _hdr->length;
size_t rxfz = state->grxfsiz;
if(amtDone > rxfz)
amtDone = rxfz;
if(rxfz > sizeof(state->fifos))
hw_error("usb_synopsys: USB transfer would overflow FIFO buffer!\n");
printf("USB: Starting OUT transfer on EP %d (%d)...\n", ep, amtDone);
if(amtDone > 0)
{
memcpy((char*)state->fifos, _buffer, amtDone);
if(eps->dma_address)
{
printf("USB: DMA copying to 0x%08x.\n", eps->dma_address);
cpu_physical_memory_write(eps->dma_address, state->fifos, amtDone);
eps->dma_address += amtDone;
}
}
printf("USB: OUT transfer complete!\n");
if(_hdr->flags & tcp_usb_setup)
{
/*
printf("USB: Setup %02x %02x %02x %02x %02x %02x %02x %02x\n",
state->fifos[0],
state->fifos[1],
state->fifos[2],
state->fifos[3],
state->fifos[4],
state->fifos[5],
state->fifos[6],
state->fifos[7]);
*/
eps->interrupt_status |= USB_EPINT_SetUp;
}
else
eps->interrupt_status |= USB_EPINT_XferCompl;
eps->tx_size = (eps->tx_size &~ DEPTSIZ_XFERSIZ_MASK)
| ((sz-amtDone) & DEPTSIZ_XFERSIZ_MASK);
ret = amtDone;
}
else
ret = USB_RET_NAK;
}
synopsys_usb_update_irq(state);
return ret;
}
static uint32_t synopsys_usb_in_ep_read(synopsys_usb_state *_state, uint8_t _ep, hwaddr _addr)
{
if(_ep >= USB_NUM_ENDPOINTS)
{
hw_error("usb_synopsys: Tried to read from disabled EP %d.\n", _ep);
return 0;
}
switch (_addr)
{
case 0x00:
return _state->in_eps[_ep].control;
case 0x08:
return _state->in_eps[_ep].interrupt_status;
case 0x10:
return _state->in_eps[_ep].tx_size;
case 0x14:
return _state->in_eps[_ep].dma_address;
case 0x1C:
return _state->in_eps[_ep].dma_buffer;
default:
hw_error("usb_synopsys: bad ep read offset 0x" HWADDR_FMT_plx "\n", _addr);
break;
}
return 0;
}
static uint32_t synopsys_usb_out_ep_read(synopsys_usb_state *_state, int _ep, hwaddr _addr)
{
if(_ep >= USB_NUM_ENDPOINTS)
{
hw_error("usb_synopsys: Tried to read from disabled EP %d.\n", _ep);
return 0;
}
switch (_addr)
{
case 0x00:
return _state->out_eps[_ep].control;
case 0x08:
return _state->out_eps[_ep].interrupt_status;
case 0x10:
return _state->out_eps[_ep].tx_size;
case 0x14:
return _state->out_eps[_ep].dma_address;
case 0x1C:
return _state->out_eps[_ep].dma_buffer;
default:
hw_error("usb_synopsys: bad ep read offset 0x" HWADDR_FMT_plx "\n", _addr);
break;
}
return 0;
}
static uint64_t synopsys_usb_read(void *opaque, hwaddr _addr, unsigned size)
{
synopsys_usb_state *state = (synopsys_usb_state *)opaque;
//printf("USB: Read 0x%08x.\n", _addr);
switch(_addr)
{
case PCGCCTL:
return state->pcgcctl;
case GOTGCTL:
return state->gotgctl;
case GOTGINT:
return state->gotgint;
case GRSTCTL:
return state->grstctl;
case GHWCFG1:
return state->ghwcfg1;
case GHWCFG2:
return state->ghwcfg2;
case GHWCFG3:
return state->ghwcfg3;
case GHWCFG4:
return state->ghwcfg4;
case GAHBCFG:
return state->gahbcfg;
case GUSBCFG:
return state->gusbcfg;
case GINTMSK:
return state->gintmsk;
case GINTSTS:
return state->gintsts;
case DIEPMSK:
return state->diepmsk;
case DOEPMSK:
return state->doepmsk;
case DAINTMSK:
return state->daintmsk;
case DAINTSTS:
return state->daintsts;
case DCTL:
return state->dctl;
case DCFG:
return state->dcfg;
case DSTS:
return state->dsts;
case GRXSTSR:
case GRXSTSP:
return 0; // TODO: Do something about this?
case GNPTXFSTS:
return 0xFFFFFFFF;
case GRXFSIZ:
return state->grxfsiz;
case GNPTXFSIZ:
return state->gnptxfsiz;
case DIEPTXF(1) ... DIEPTXF(USB_NUM_FIFOS+1):
_addr -= DIEPTXF(1);
_addr >>= 2;
return state->dptxfsiz[_addr];
case USB_INREGS ... (USB_INREGS + USB_EPREGS_SIZE - 4):
_addr -= USB_INREGS;
return synopsys_usb_in_ep_read(state, _addr >> 5, _addr & 0x1f);
case USB_OUTREGS ... (USB_OUTREGS + USB_EPREGS_SIZE - 4):
_addr -= USB_OUTREGS;
return synopsys_usb_out_ep_read(state, _addr >> 5, _addr & 0x1f);
case USB_FIFO_START ... USB_FIFO_END-4:
_addr -= USB_FIFO_START;
return *((uint32_t*)(&state->fifos[_addr]));
default:
hw_error("USB: Unhandled read address 0x%08x!\n", _addr);
}
return 0;
}
static void synopsys_usb_in_ep_write(synopsys_usb_state *_state, int _ep, hwaddr _addr, uint32_t _val)
{
if(_ep >= USB_NUM_ENDPOINTS)
{
hw_error("usb_synopsys: Wrote to disabled EP %d.\n", _ep);
return;
}
if (_addr == 0x10) {
printf("USB: Setting TX size of EP %d to %d.\n", _ep, _val);
}
switch (_addr)
{
case 0x00:
_state->in_eps[_ep].control = _val;
synopsys_usb_update_in_ep(_state, _ep);
return;
case 0x08:
_state->in_eps[_ep].interrupt_status &=~ _val;
synopsys_usb_update_irq(_state);
return;
case 0x10:
_state->in_eps[_ep].tx_size = _val;
return;
case 0x14:
_state->in_eps[_ep].dma_address = _val;
return;
case 0x1C:
_state->in_eps[_ep].dma_buffer = _val;
return;
default:
hw_error("usb_synopsys: bad ep write offset 0x" HWADDR_FMT_plx "\n", _addr);
break;
}
}
static void synopsys_usb_out_ep_write(synopsys_usb_state *_state, int _ep, hwaddr _addr, uint32_t _val)
{
if(_ep >= USB_NUM_ENDPOINTS)
{
hw_error("usb_synopsys: Wrote to disabled EP %d.\n", _ep);
return;
}
switch (_addr)
{
case 0x00:
_state->out_eps[_ep].control = _val;
synopsys_usb_update_out_ep(_state, _ep);
return;
case 0x08:
_state->out_eps[_ep].interrupt_status &=~ _val;
synopsys_usb_update_irq(_state);
return;
case 0x10:
_state->out_eps[_ep].tx_size = _val;
return;
case 0x14:
_state->out_eps[_ep].dma_address = _val;
return;
case 0x1C:
_state->out_eps[_ep].dma_buffer = _val;
return;
default:
hw_error("usb_synopsys: bad ep write offset 0x" HWADDR_FMT_plx "\n", _addr);
break;
}
}
static void synopsys_usb_write(void *opaque, hwaddr _addr, uint64_t _val, unsigned size)
{
synopsys_usb_state *state = (synopsys_usb_state *)opaque;
printf("USB: Write 0x%08x to 0x%08x.\n", _val, _addr);
switch(_addr)
{
case PCGCCTL:
state->pcgcctl = _val;
synopsys_usb_update_irq(state);
return;
case GOTGCTL:
state->gotgctl = _val;
break;
case GOTGINT:
state->gotgint &=~ _val;
synopsys_usb_update_irq(state);
return;
case GRSTCTL:
if(_val & GRSTCTL_CORESOFTRESET)
{
state->grstctl = GRSTCTL_CORESOFTRESET;
// Do reset stuff
if(state->server_host)
{
tcp_usb_cleanup(&state->tcp_state);
tcp_usb_init(&state->tcp_state, synopsys_usb_tcp_callback, NULL, state);
printf("Connecting to USB server at %s:%d...\n",
state->server_host, state->server_port);
int ret = tcp_usb_connect(&state->tcp_state, state->server_host, state->server_port);
if(ret < 0) {
printf("Failed to connect to USB server (%d).\n", ret);
}
else {
printf("Connected to USB server.\n");
}
}
state->grstctl &= ~GRSTCTL_CORESOFTRESET;
state->grstctl |= GRSTCTL_AHBIDLE;
state->gintsts |= GINTMSK_RESET;
synopsys_usb_update_irq(state);
}
else if(_val == 0)
state->grstctl = _val;
return;
case GINTMSK:
state->gintmsk = _val;
synopsys_usb_update_irq(state);
break;
case GINTSTS:
state->gintsts &=~ _val;
synopsys_usb_update_irq(state);
return;
case DOEPMSK:
state->doepmsk = _val;
synopsys_usb_update_irq(state);
return;
case DIEPMSK:
state->diepmsk = _val;
synopsys_usb_update_irq(state);
return;
case DAINTMSK:
state->daintmsk = _val;
synopsys_usb_update_irq(state);
return;
case DAINTSTS:
state->daintsts &=~ _val;
synopsys_usb_update_irq(state);
return;
case GAHBCFG:
state->gahbcfg = _val;
return;
case GUSBCFG:
state->gusbcfg = _val;
return;
case DCTL:
if((_val & DCTL_SGNPINNAK) != (state->dctl & DCTL_SGNPINNAK)
&& (_val & DCTL_SGNPINNAK))
{
state->gintsts |= GINTMSK_GINNAKEFF;
_val &=~ DCTL_SGNPINNAK;
}
if((_val & DCTL_SGOUTNAK) != (state->dctl & DCTL_SGOUTNAK)
&& (_val & DCTL_SGOUTNAK))
{
state->gintsts |= GINTMSK_GOUTNAKEFF;
_val &=~ DCTL_SGOUTNAK;
}
state->dctl = _val;
synopsys_usb_update_irq(state);
return;
case DCFG:
//printf("USB: dcfg = 0x%08x.\n", _val);
state->dcfg = _val;
return;
case GRXFSIZ:
state->grxfsiz = _val;
return;
case GNPTXFSIZ:
state->gnptxfsiz = _val;
return;
case DIEPTXF(1) ... DIEPTXF(USB_NUM_FIFOS+1):
_addr -= DIEPTXF(1);
_addr >>= 2;
state->dptxfsiz[_addr] = _val;
return;
case USB_INREGS ... (USB_INREGS + USB_EPREGS_SIZE - 4):
_addr -= USB_INREGS;
synopsys_usb_in_ep_write(state, _addr >> 5, _addr & 0x1f, _val);
return;
case USB_OUTREGS ... (USB_OUTREGS + USB_EPREGS_SIZE - 4):
_addr -= USB_OUTREGS;
synopsys_usb_out_ep_write(state, _addr >> 5, _addr & 0x1f, _val);
return;
case USB_FIFO_START ... USB_FIFO_END-4:
_addr -= USB_FIFO_START;
*((uint32_t*)(&state->fifos[_addr])) = _val;
return;
default:
hw_error("USB: Unhandled write address 0x%08x!\n", _addr);
}
}
static const MemoryRegionOps usb_otg_ops = {
.read = synopsys_usb_read,
.write = synopsys_usb_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void s5l8900_usb_otg_reset(DeviceState *d)
{
synopsys_usb_state *state = S5L8900USBOTG(d);
printf("USB: cfg = 0x%08x, 0x%08x, 0x%08x, 0x%08x.\n",
state->ghwcfg1,
state->ghwcfg2,
state->ghwcfg3,
state->ghwcfg4);
state->pcgcctl = 3;
state->grstctl = GRSTCTL_AHBIDLE;
state->gahbcfg = 0;
state->gusbcfg = 0;
state->dctl = 0;
state->dcfg = 0;
state->dsts = 0;
state->gotgctl = 0;
state->gotgint = 0;
state->gintmsk = 0;
state->gintsts = 0;
state->daintmsk = 0;
state->daintsts = 0;
state->diepmsk = 0;
state->doepmsk = 0;
state->grxfsiz = 0x100;
state->gnptxfsiz = (0x100 << 16) | 0x100;
state->server_host = "localhost";
state->server_port = 1235;
uint32_t counter = 0x200;
int i;
for(i = 0; i < USB_NUM_FIFOS; i++)
{
state->dptxfsiz[i] = (counter << 16) | 0x100;
counter += 0x100;
}
for(i = 0; i < USB_NUM_ENDPOINTS; i++)
{
synopsys_usb_ep_state *in = &state->in_eps[i];
in->control = 0;
in->dma_address = 0;
in->fifo = 0;
in->tx_size = 0;
synopsys_usb_ep_state *out = &state->out_eps[i];
out->control = 0;
out->dma_address = 0;
out->fifo = 0;
out->tx_size = 0;
}
synopsys_usb_update_irq(state);
}
static void s5l8900_usb_otg_init1(Object *obj)
{
DeviceState *dev = DEVICE(obj);
synopsys_usb_state *s = S5L8900USBOTG(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, OBJECT(s), &usb_otg_ops, s, "usb_otg", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
}
// Helper for adding to a machine
DeviceState *ipod_touch_init_usb_otg(qemu_irq _irq, uint32_t _hwcfg[4])
{
DeviceState *dev = qdev_new(TYPE_S5L8900USBOTG);
synopsys_usb_state *state = S5L8900USBOTG(dev);
state->ghwcfg1 = _hwcfg[0];
state->ghwcfg2 = _hwcfg[1];
state->ghwcfg3 = _hwcfg[2];
state->ghwcfg4 = _hwcfg[3];
SysBusDevice *sdev = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(sdev, 0, _irq);
return dev;
}
static void s5l8900_usb_otg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = s5l8900_usb_otg_reset;
}
static const TypeInfo s5l8900_usb_otg_info = {
.name = TYPE_S5L8900USBOTG,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(synopsys_usb_state),
.instance_init = s5l8900_usb_otg_init1,
.class_init = s5l8900_usb_otg_class_init,
};
static void s5l8900_usb_otg_register_types(void)
{
type_register_static(&s5l8900_usb_otg_info);
}
type_init(s5l8900_usb_otg_register_types)
+4 -5
View File
@@ -19,9 +19,8 @@ static uint64_t ipod_touch_usb_phys_read(void *opaque, hwaddr addr, unsigned siz
case REG_CABLE:
return s->is_cable_connected;
default:
//return 0x0;
printf("%s: read invalid location 0x%08x\n", __func__, addr);
return 0x0;
return 0x0;
//hw_error("%s: read invalid location 0x%08x\n", __func__, addr);
}
}
@@ -48,7 +47,7 @@ static void ipod_touch_usb_phys_write(void *opaque, hwaddr addr, uint64_t val, u
return;
default:
printf("%s: write invalid location 0x%08x.\n", __func__, addr);
//hw_error("%s: write invalid location 0x%08x.\n", __func__, addr);
return;
}
}
@@ -86,4 +85,4 @@ static void ipod_touch_usb_phys_register_types(void)
type_register_static(&ipod_touch_usb_phys_type_info);
}
type_init(ipod_touch_usb_phys_register_types)
type_init(ipod_touch_usb_phys_register_types)
+1 -1
View File
@@ -65,7 +65,7 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('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_XEN', if_true: files('xen_arm.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_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c', 'ipod_touch_isl29003dl.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_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_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c'))
system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
+5
View File
@@ -137,3 +137,8 @@ config USB_DWC3
config XLNX_USB_SUBSYS
bool
select USB_DWC3
config USB_TCP
bool
default y
depends on USB
+84
View File
@@ -1368,6 +1368,9 @@ static void dwc2_realize(DeviceState *dev, Error **errp)
&dev->mem_reentrancy_guard);
sysbus_init_irq(sbd, &s->irq);
s->device = DWC2_USB_DEVICE(qdev_new(TYPE_DWC2_USB_DEVICE));
s->device->dwc2 = s;
}
static void dwc2_init(Object *obj)
@@ -1387,6 +1390,56 @@ static void dwc2_init(Object *obj)
memory_region_add_subregion(&s->container, 0x1000, &s->fifos);
}
static void dwc2_usb_device_realize(USBDevice *dev, Error **errp)
{
dev->speed = USB_SPEED_HIGH;
dev->speedmask = USB_SPEED_MASK_HIGH;
dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
dev->auto_attach = false;
}
static void dwc2_usb_device_handle_attach(USBDevice *dev)
{
DWC2DeviceState *udev = DWC2_USB_DEVICE(dev);
DWC2State *s = udev->dwc2;
/* not in host mode */
assert(!s->uport.dev);
s->gotgctl |= GOTGCTL_BSESVLD | GOTGCTL_CONID_B;
dwc2_lower_global_irq(s, GINTSTS_CURMODE_HOST);
dwc2_raise_global_irq(s, GINTSTS_CONIDSTSCHNG);
}
static void dwc2_usb_device_handle_detach(USBDevice *dev)
{
DWC2DeviceState *udev = DWC2_USB_DEVICE(dev);
DWC2State *s = udev->dwc2;
s->gotgctl &= ~(GOTGCTL_BSESVLD | GOTGCTL_CONID_B);
dwc2_raise_global_irq(s, GINTSTS_CURMODE_HOST | GINTSTS_CONIDSTSCHNG);
}
static void dwc2_usb_device_handle_reset(USBDevice *dev)
{
DWC2DeviceState *udev = DWC2_USB_DEVICE(dev);
DWC2State *s = udev->dwc2;
s->dcfg &= ~DCFG_DEVADDR_MASK;
for (int i = 1; i < DWC2_NB_EP; i++) {
s->diepctl(i) &= ~DXEPCTL_USBACTEP;
s->doepctl(i) &= ~DXEPCTL_USBACTEP;
}
dwc2_raise_global_irq(s, GINTSTS_USBRST);
}
static void dwc2_usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
{
qemu_log_mask(LOG_UNIMP, "%s\n", __func__);
}
static const VMStateDescription vmstate_dwc2_state_packet = {
.name = "dwc2/packet",
.version_id = 1,
@@ -1448,6 +1501,29 @@ static Property dwc2_usb_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
static void dwc2_usb_device_class_initfn_common(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = dwc2_usb_device_realize;
uc->product_desc = "DWC2 USB Device";
uc->unrealize = NULL;
uc->cancel_packet = dwc2_usb_device_cancel_packet;
uc->handle_attach = dwc2_usb_device_handle_attach;
//uc->handle_detach = dwc2_usb_device_handle_detach;
uc->handle_reset = dwc2_usb_device_handle_reset;
uc->handle_data = NULL;
uc->handle_control = NULL;
//uc->handle_packet = dwc2_usb_device_handle_packet;
uc->flush_ep_queue = NULL;
uc->ep_stopped = NULL;
uc->alloc_streams = NULL;
uc->free_streams = NULL;
uc->usb_desc = NULL;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
static void dwc2_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1462,6 +1538,13 @@ static void dwc2_class_init(ObjectClass *klass, void *data)
dwc2_reset_exit, &c->parent_phases);
}
static const TypeInfo dwc2_usb_device_type_info = {
.name = TYPE_DWC2_USB_DEVICE,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(DWC2DeviceState),
.class_init = dwc2_usb_device_class_initfn_common,
};
static const TypeInfo dwc2_usb_type_info = {
.name = TYPE_DWC2_USB,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -1473,6 +1556,7 @@ static const TypeInfo dwc2_usb_type_info = {
static void dwc2_usb_register_types(void)
{
type_register_static(&dwc2_usb_device_type_info);
type_register_static(&dwc2_usb_type_info);
}
+49
View File
@@ -30,8 +30,10 @@
#define DWC2_NB_CHAN 8 /* Number of host channels */
#define DWC2_MAX_XFER_SIZE 65536 /* Max transfer size expected in HCTSIZ */
#define DWC2_NB_EP 16 /* Number of device endpoints */
typedef struct DWC2Packet DWC2Packet;
typedef struct DWC2DeviceState DWC2DeviceState;
typedef struct DWC2State DWC2State;
typedef struct DWC2Class DWC2Class;
@@ -57,12 +59,18 @@ struct DWC2Packet {
bool needs_service;
};
struct DWC2DeviceState {
USBDevice parent_obj;
DWC2State *dwc2;
};
struct DWC2State {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
USBBus bus;
DWC2DeviceState *device;
qemu_irq irq;
MemoryRegion *dma_mr;
AddressSpace dma_as;
@@ -141,6 +149,44 @@ struct DWC2State {
#define hcdma(_ch) hreg1[((_ch) << 3) + 5] /* 514, 534, ... */
#define hcdmab(_ch) hreg1[((_ch) << 3) + 7] /* 51c, 53c, ... */
union {
#define DWC2_DREG_SIZE 0x38
uint32_t dreg[DWC2_DREG_SIZE / sizeof(uint32_t)];
struct {
uint32_t dcfg; /* 800 */
uint32_t dctl; /* 804 */
uint32_t dsts; /* 808 */
uint32_t rsvd2; /* 80c */
uint32_t diepmsk; /* 810 */
uint32_t doepmsk; /* 814 */
uint32_t daint; /* 818 */
uint32_t daintmsk; /* 81c */
uint32_t dtknqr1; /* 820 */
uint32_t dtknqr2; /* 824 */
uint32_t dvbusdis; /* 828 */
uint32_t dvbuspulse; /* 82c */
uint32_t dtknqr3; /* 830 */
uint32_t dtknqr4; /* 834 */
};
};
#define DWC2_DIEPREG_SIZE (0x20 * DWC2_NB_EP)
uint32_t diepreg[DWC2_DIEPREG_SIZE / sizeof(uint32_t)];
#define diepctl(_ch) diepreg[((_ch) << 3) + 0] /* 900, 920, ... */
#define diepint(_ch) diepreg[((_ch) << 3) + 2] /* 908, 928, ... */
#define dieptsiz(_ch) diepreg[((_ch) << 3) + 4] /* 910, 930, ... */
#define diepdma(_ch) diepreg[((_ch) << 3) + 5] /* 914, 934, ... */
#define dtxfsts(_ch) diepreg[((_ch) << 3) + 6] /* 918, 938, ... */
#define DWC2_DOEPREG_SIZE (0x20 * DWC2_NB_EP)
uint32_t doepreg[DWC2_DIEPREG_SIZE / sizeof(uint32_t)];
#define doepctl(_ch) doepreg[((_ch) << 3) + 0] /* b00, b20, ... */
#define doepint(_ch) doepreg[((_ch) << 3) + 2] /* b08, b28, ... */
#define doeptsiz(_ch) doepreg[((_ch) << 3) + 4] /* b10, b30, ... */
#define doepdma(_ch) doepreg[((_ch) << 3) + 5] /* b14, b34, ... */
union {
#define DWC2_PCGREG_SIZE 0x08
uint32_t pcgreg[DWC2_PCGREG_SIZE / sizeof(uint32_t)];
@@ -180,6 +226,9 @@ struct DWC2Class {
/*< public >*/
};
#define TYPE_DWC2_USB_DEVICE "dwc2-usb-device"
OBJECT_DECLARE_TYPE(DWC2DeviceState, USBDeviceClass, DWC2_USB_DEVICE)
#define TYPE_DWC2_USB "dwc2-usb"
OBJECT_DECLARE_TYPE(DWC2State, DWC2Class, DWC2_USB)
+457
View File
@@ -0,0 +1,457 @@
#include "qemu/osdep.h"
#include "qom/object.h"
#include "qemu/lockable.h"
#include "hw/usb.h"
#include "tcp-usb.h"
#include "hw/usb/hcd-tcp.h"
#include "qemu/cutils.h"
#include "hw/qdev-properties.h"
#include "qemu/main-loop.h"
#include "qemu/coroutine.h"
#include "io/channel.h"
#include "io/channel-util.h"
#include "qapi/error.h"
#include "sysemu/iothread.h"
#include "qemu/error-report.h"
#include "migration/blocker.h"
//#define DEBUG_HCD_TCP
#ifdef DEBUG_HCD_TCP
#define DPRINTF(fmt, ...) \
do { fprintf(stderr, "hcd-tcp: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF(fmt, ...) do {} while(0)
#endif
static void usb_tcp_host_closed(USBTCPHostState *s)
{
DPRINTF("%s\n", __func__);
if (s->ioc) {
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
qio_channel_close(s->ioc, NULL);
object_unref(OBJECT(s->ioc));
s->ioc = NULL;
}
s->closed = true;
migrate_del_blocker(s->migration_blocker);
}
static ssize_t tcp_usb_read(QIOChannel *ioc, void *buf, size_t len)
{
struct iovec iov = { .iov_base = buf, .iov_len = len };
bool iolock = qemu_mutex_iothread_locked();
bool iothread = qemu_in_iothread();
ssize_t ret = -1;
Error *err = NULL;
/*
* Dont use in IOThread out of co-routine context as
* it will block IOThread.
*/
assert(qemu_in_coroutine() || !iothread);
if (iolock && !iothread && !qemu_in_coroutine()) {
qemu_mutex_unlock_iothread();
}
ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, NULL, 0, &err);
if (iolock && !iothread && !qemu_in_coroutine()) {
qemu_mutex_lock_iothread();
}
if (err) {
error_report_err(err);
}
return (ret <= 0) ? ret : iov.iov_len;
}
static bool tcp_usb_write(QIOChannel *ioc, void *buf, ssize_t len)
{
struct iovec iov = { .iov_base = buf, .iov_len = len };
bool iolock = qemu_mutex_iothread_locked();
bool iothread = qemu_in_iothread();
bool ret = false;
Error *err = NULL;
/*
* Dont use in IOThread out of co-routine context as
* it will block IOThread.
*/
assert(qemu_in_coroutine() || !iothread);
if (iolock && !iothread && !qemu_in_coroutine()) {
qemu_mutex_unlock_iothread();
}
if (!qio_channel_writev_full_all(ioc, &iov, 1, NULL, 0, 0, &err)) {
ret = true;
}
if (iolock && !iothread && !qemu_in_coroutine()) {
qemu_mutex_lock_iothread();
}
if (err) {
error_report_err(err);
}
return ret;
}
static USBPort *usb_tcp_host_find_active_port(USBTCPHostState *s)
{
for (int i = 0; i < G_N_ELEMENTS(s->uports) - 1; i++) {
if (s->uports[i].dev->attached) {
return &s->uports[i];
}
}
return &s->uports[0];
}
static void coroutine_fn usb_tcp_host_respond_packet_co(void *opaque)
{
USBTCPPacket *pkt = (USBTCPPacket *)opaque;
USBTCPHostState *s = USB_TCP_HOST(pkt->s);
USBPacket *p = &pkt->p;
tcp_usb_header_t hdr = { 0 };
tcp_usb_response_header resp = { 0 };
g_autofree void *buffer = NULL;
USBPort *uport = usb_tcp_host_find_active_port(s);
WITH_QEMU_LOCK_GUARD(&s->write_mutex) {
if (!s->closed) {
hdr.type = TCP_USB_RESPONSE;
resp.addr = uport->dev->addr;
resp.pid = p->pid;
resp.ep = p->ep->nr;
resp.id = p->id;
resp.status = p->status;
resp.length = p->iov.size;
if (resp.length > p->actual_length) {
resp.length = p->actual_length;
}
if (p->pid == USB_TOKEN_IN && p->status != USB_RET_ASYNC) {
buffer = g_malloc(resp.length);
iov_to_buf(p->iov.iov, p->iov.niov, 0, buffer, resp.length);
}
if (!tcp_usb_write(s->ioc, &hdr, sizeof(hdr))) {
usb_tcp_host_closed(s);
return;
}
if (!tcp_usb_write(s->ioc, &resp, sizeof(resp))) {
usb_tcp_host_closed(s);
return;
}
if (buffer) {
if (!tcp_usb_write(s->ioc, buffer, resp.length)) {
usb_tcp_host_closed(s);
return;
}
}
}
}
if (!usb_packet_is_inflight(p)) {
if (pkt->buffer) {
g_free(pkt->buffer);
}
usb_packet_cleanup(p);
g_free(pkt);
}
}
static void usb_tcp_host_respond_packet(USBTCPHostState *s, USBTCPPacket *pkt)
{
Coroutine *co = NULL;
co = qemu_coroutine_create(usb_tcp_host_respond_packet_co, pkt);
qemu_coroutine_enter(co);
}
static void coroutine_fn usb_tcp_host_msg_loop_co(void *opaque)
{
USBTCPHostState *s = USB_TCP_HOST(opaque);
USBPort *uport = usb_tcp_host_find_active_port(s);
QIOChannel *ioc = s->ioc;
for(;;) {
tcp_usb_header_t hdr = { 0 };
if (unlikely((tcp_usb_read(ioc, &hdr, sizeof(hdr)) != sizeof(hdr)))) {
usb_tcp_host_closed(s);
return;
}
switch (hdr.type) {
case TCP_USB_REQUEST: {
/* fprintf(stderr, "%s: TCP_USB_REQUEST\n", __func__); */
tcp_usb_request_header pkt_hdr = {0};
g_autofree void *buffer = NULL;
g_autofree USBTCPPacket *pkt = (USBTCPPacket *) g_malloc0(sizeof(USBTCPPacket));
USBEndpoint *ep = NULL;
if (unlikely(tcp_usb_read(ioc, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr))) {
usb_tcp_host_closed(s);
return;
}
#if 0
DPRINTF("%s: TCP_USB_REQUEST pid: 0x%x ep: %d id: 0x%lx\n", __func__, pkt_hdr.pid, pkt_hdr.ep, pkt_hdr.id);
#endif
ep = usb_ep_get(uport->dev, pkt_hdr.pid, pkt_hdr.ep);
if (ep == NULL) {
DPRINTF("%s: TCP_USB_REQUEST unknown EP\n", __func__);
usb_tcp_host_closed(s);
return;
}
usb_packet_init(&pkt->p);
usb_packet_setup(&pkt->p, pkt_hdr.pid, ep, pkt_hdr.stream, pkt_hdr.id, pkt_hdr.short_not_ok, pkt_hdr.int_req);
if (pkt_hdr.length > 0) {
buffer = g_malloc0(pkt_hdr.length);
if (pkt_hdr.pid != USB_TOKEN_IN) {
if (unlikely(tcp_usb_read(s->ioc, buffer, pkt_hdr.length) != pkt_hdr.length)) {
usb_tcp_host_closed(s);
usb_packet_cleanup(&pkt->p);
return;
}
/* qemu_hexdump(stderr, __func__, buffer, pkt_hdr.length); */
}
usb_packet_addbuf(&pkt->p, buffer, pkt_hdr.length);
pkt->buffer = buffer;
g_steal_pointer(&buffer);
}
if (pkt_hdr.addr != uport->dev->addr) {
/*
* fprintf(stderr,
* "%s: USB_RET_NODEV: pkt_hdr.addr != uport->dev->addr: %d != %d\n",
* __func__, pkt_hdr.addr, uport->dev->addr);
*/
/* Can't enforce this check because dwc2 address transition time is slow */
}
pkt->dev = ep->dev;
pkt->s = s;
pkt->addr = pkt_hdr.addr;
assert(qemu_mutex_iothread_locked());
usb_handle_packet(pkt->dev, &pkt->p);
usb_tcp_host_respond_packet(s, pkt);
g_steal_pointer(&pkt);
break;
}
case TCP_USB_RESPONSE:
fprintf(stderr, "%s: unexpected TCP_USB_RESPONSE\n", __func__);
usb_tcp_host_closed(s);
return;
case TCP_USB_CANCEL: {
/* DPRINTF("%s: TCP_USB_CANCEL\n", __func__); */
tcp_usb_cancel_header pkt_hdr = {0};
USBTCPPacket *pkt = NULL;
USBPacket *p = NULL;
if (unlikely(tcp_usb_read(ioc, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr))) {
usb_tcp_host_closed(s);
return;
}
#if 1
DPRINTF("%s: TCP_USB_CANCEL pid: 0x%x ep: %d\n", __func__, pkt_hdr.pid, pkt_hdr.ep);
#endif
if (pkt_hdr.addr != uport->dev->addr) {
/*
* fprintf(stderr,
* "%s: USB_RET_NODEV: pkt_hdr.addr != uport->dev->addr: %d != %d\n",
* __func__, pkt_hdr.addr, uport->dev->addr);
*/
/* Can't enforce this check because dwc2 address transition time is slow */
}
assert(qemu_mutex_iothread_locked());
p = usb_ep_find_packet_by_id(uport->dev, pkt_hdr.pid,
pkt_hdr.ep, pkt_hdr.id);
if (p) {
pkt = container_of(p, USBTCPPacket, p);
usb_cancel_packet(&pkt->p);
DPRINTF("%s: TCP_USB_CANCEL: packet"
" pid: 0x%x ep: %d id: 0x%lx len: 0x%x\n",
__func__, pkt_hdr.pid, pkt_hdr.ep, pkt_hdr.id, p->actual_length);
usb_tcp_host_respond_packet(s, pkt);
} else {
warn_report("%s: TCP_USB_CANCEL: packet"
" pid: 0x%x ep: %d id: 0x%lx not found",
__func__, pkt_hdr.pid, pkt_hdr.ep, pkt_hdr.id);
}
break;
}
case TCP_USB_RESET:
/* fprintf(stderr, "%s: TCP_USB_RESET\n", __func__); */
DPRINTF("%s: TCP_USB_RESET\n", __func__);
assert(qemu_mutex_iothread_locked());
usb_device_reset(uport->dev);
break;;
default:
g_assert_not_reached();
break;
}
}
return;
}
static void usb_tcp_host_attach(USBPort *uport)
{
struct sockaddr_un server_addr;
USBTCPHostState *s = USB_TCP_HOST(uport->opaque);
int sock = -1;
Coroutine *co = NULL;
QIOChannel *ioc = NULL;
int ret;
Error *err = NULL;
if (uport->index >= G_N_ELEMENTS(s->uports) - 1) {
error_report("%s: attached to unused port\n", __func__);
return;
}
if (usb_tcp_host_find_active_port(s) != uport) {
error_report("%s: Attaching to 2 proxy ports at the same time. "
"This port might not be able to receive packets.\n",
__func__);
return;
}
if (!uport->dev || !uport->dev->attached) {
return;
}
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket < 0) {
error_report("%s: cannot open socket", __func__);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, socket_path, sizeof(server_addr.sun_path));
server_addr.sun_path[sizeof(server_addr.sun_path) - 1] = '\0';
ret = connect(sock, (const struct sockaddr *) &server_addr, sizeof(server_addr));
if (ret < 0) {
error_report("%s: failed to connect to server: %d\n", __func__, ret);
close(sock);
return;
}
ioc = qio_channel_new_fd(sock, &err);
if (!ioc) {
error_report_err(err);
close(sock);
return;
}
qio_channel_set_blocking(ioc, false, NULL);
s->closed = 0;
s->ioc = ioc;
migrate_add_blocker(s->migration_blocker, NULL);
co = qemu_coroutine_create(usb_tcp_host_msg_loop_co, s);
qemu_coroutine_enter(co);
}
static void usb_tcp_host_detach(USBPort *uport)
{
USBTCPHostState *s = USB_TCP_HOST(uport->opaque);
usb_tcp_host_closed(s);
}
static void usb_tcp_host_async_packet_complete(USBPort *port, USBPacket *p)
{
USBTCPHostState *s = USB_TCP_HOST(port->opaque);
usb_tcp_host_respond_packet(s, container_of(p, USBTCPPacket, p));
}
static USBBusOps usb_tcp_bus_ops = { };
static USBPortOps usb_tcp_host_port_ops = {
.attach = usb_tcp_host_attach,
.detach = usb_tcp_host_detach,
.child_detach = NULL,
.wakeup = NULL,
.complete = usb_tcp_host_async_packet_complete,
};
static void usb_tcp_host_realize(DeviceState *dev, Error **errp)
{
USBTCPHostState *s = USB_TCP_HOST(dev);
usb_bus_new(&s->bus, sizeof(s->bus), &usb_tcp_bus_ops, dev);
for (int i = 0; i < G_N_ELEMENTS(s->uports); i++) {
usb_register_port(&s->bus, &s->uports[i], s, i, &usb_tcp_host_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
USB_SPEED_MASK_HIGH);
}
s->closed = 1;
qemu_co_mutex_init(&s->write_mutex);
}
static void usb_tcp_host_unrealize(DeviceState *dev)
{
USBTCPHostState *s = USB_TCP_HOST(dev);
if (s->ioc) {
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
qio_channel_close(s->ioc, NULL);
s->ioc = NULL;
}
s->closed = 1;
s->stopped = 1;
}
static void usb_tcp_host_init(Object *obj)
{
USBTCPHostState *s = USB_TCP_HOST(obj);
s->closed = 1;
error_setg(&s->migration_blocker, "%s does not support migration "
"while connected", TYPE_USB_TCP_HOST);
}
static Property usb_tcp_host_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
static void usb_tcp_host_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = usb_tcp_host_realize;
dc->unrealize = usb_tcp_host_unrealize;
dc->desc = "QEMU USB Passthrough Host Controller";
device_class_set_props(dc, usb_tcp_host_properties);
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
static const TypeInfo usb_tcp_host_type_info = {
.name = TYPE_USB_TCP_HOST,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(USBTCPHostState),
.class_init = usb_tcp_host_class_init,
.instance_init = usb_tcp_host_init,
};
static void usb_tcp_host_register_types(void)
{
type_register_static(&usb_tcp_host_type_info);
}
type_init(usb_tcp_host_register_types)
+1 -1
View File
@@ -11,7 +11,7 @@ system_ss.add(when: 'CONFIG_USB', if_true: files(
'pcap.c',
))
system_ss.add(when: 'CONFIG_USB', if_true: files('tcp_usb.c'))
system_ss.add(when: 'CONFIG_USB_TCP', if_true: files('hcd-tcp.c'))
# usb host adapters
system_ss.add(when: 'CONFIG_USB_UHCI', if_true: files('hcd-uhci.c'))
+48
View File
@@ -0,0 +1,48 @@
#ifndef HW_USB_TCP_USB_H
#define HW_USB_TCP_USB_H
#include "qemu/osdep.h"
#include "hw/usb.h"
static const char *socket_path = "/tmp/usbqemu";
enum {
TCP_USB_REQUEST = (1 << 0),
TCP_USB_RESPONSE = (1 << 1),
TCP_USB_RESET = (1 << 2),
TCP_USB_CANCEL = (1 << 3)
};
typedef struct QEMU_PACKED tcp_usb_header {
uint8_t type;
} tcp_usb_header_t;
typedef struct QEMU_PACKED tcp_usb_request_header {
uint8_t addr;
int pid;
uint8_t ep;
unsigned int stream;
uint64_t id;
uint8_t short_not_ok;
uint8_t int_req;
uint16_t length;
} tcp_usb_request_header;
typedef struct QEMU_PACKED tcp_usb_response_header {
uint8_t addr;
int pid;
uint8_t ep;
uint64_t id;
uint32_t status;
uint16_t length;
} tcp_usb_response_header;
typedef struct QEMU_PACKED tcp_usb_cancel_header {
uint8_t addr;
int pid;
uint8_t ep;
uint64_t id;
} tcp_usb_cancel_header;
#endif //HW_USB_TCP_USB_H
-524
View File
@@ -1,524 +0,0 @@
/*
* USB over TCP driver.
*
* Copyright (c) 2011 Richard Ian Taylor.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/usb/tcp_usb.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define DEBUG_TCP_USB
void tcp_usb_init(tcp_usb_state_t *_state, tcp_usb_callback_t _cb, tcp_usb_closed_t _closed, void *_arg)
{
_state->data_callback = _cb;
_state->closed_callback = _closed;
_state->callback_arg = _arg;
_state->socket = -1;
_state->closed = 1;
_state->state = tcp_usb_idle;
_state->amount_done = 0;
}
void tcp_usb_cleanup(tcp_usb_state_t *_state)
{
if(_state->socket >= 0)
{
close(_state->socket);
qemu_set_fd_handler(_state->socket, NULL, NULL, NULL);
_state->socket = -1;
}
}
int tcp_usb_closed(tcp_usb_state_t *_state)
{
return _state->closed != 0;
}
static void tcp_usb_do_closed(tcp_usb_state_t *_state)
{
if(_state->closed)
return;
_state->closed = 1;
qemu_set_fd_handler(_state->socket, NULL, NULL, NULL);
if(_state->closed_callback)
_state->closed_callback(_state, _state->callback_arg);
}
#ifdef DEBUG_TCP_USB
static void hexdump(const void *_data, size_t _amt)
{
char *ptr = (char*)_data;
int i;
for(i = 0; i < _amt; i++)
{
if((i%8) == 0)
fprintf(stderr, "\t");
fprintf(stderr, "%02x ", (ptr[i] & 0xFF));
if((i%8) == 7)
fprintf(stderr, "\n");
}
if((i%8) != 0)
fprintf(stderr, "\n");
}
# define debug_hexdump(title, data, amt); fprintf(stderr, title); hexdump((data), (amt));
# define debug_printf(args...) printf(args);
#else
# define debug_hexdump(a, b, c)
# define debug_printf(a...)
#endif // DEBUG_TCP_USB
static void tcp_usb_callback(tcp_usb_state_t *state, int _can_read, int _can_write)
{
if(state->closed)
return;
int ret;
switch(state->state)
{
case tcp_usb_idle:
if(!_can_read)
return;
debug_printf("%s: tcp_usb_idle.\n", __func__);
// Receiving new request
state->header = malloc(sizeof(*state->header));
state->amount_done = 0;
state->state = tcp_usb_read_request;
// Fall through
case tcp_usb_read_request:
debug_printf("%s: tcp_usb_read_request\n", __func__);
if(state->amount_done < sizeof(*state->header))
{
ret = read(state->socket,
((char*)state->header) + state->amount_done,
sizeof(*state->header) - state->amount_done);
if(ret == 0 && _can_read)
{
free(state->header);
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d reading request header!\n", ret);
return;
}
_can_read = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header))
return;
debug_hexdump("tcp_usb: Got Header: ", state->header, sizeof(*state->header));
debug_printf("Length: %d\n", state->header->length);
if(state->header->length > 0)
state->buffer = malloc(state->header->length);
else
state->buffer = NULL;
}
if((state->header->ep & USB_DIR_IN) == 0 && state->header->length > 0) // OUT
{
ret = read(state->socket,
((char*)state->buffer) + (state->amount_done - sizeof(*state->header)),
state->header->length - (state->amount_done - sizeof(*state->header)));
printf("RET: %d\n", ret);
if(ret == 0 && _can_read)
{
free(state->header);
if(state->buffer)
free(state->buffer);
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
printf("tcp_usb: Error %d reading request data!\n", ret);
return;
}
_can_read = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header) + state->header->length)
return;
debug_hexdump("tcp_usb: Read: ", state->buffer, state->header->length);
}
// Transfer complete! Call callback!
if(state->data_callback)
{
state->state = tcp_usb_write_response;
state->amount_done = 0;
debug_printf("tcp_usb: Calling callback.\n");
ret = state->data_callback(state, state->callback_arg, state->header, state->buffer);
state->header->length = ret;
}
else
{
fprintf(stderr, "tcp_usb: Packet received but no callback!\n");
state->state = tcp_usb_idle;
return;
}
// Fall through
case tcp_usb_write_response:
debug_printf("%s: tcp_usb_write_response\n", __func__);
if(state->amount_done < sizeof(*state->header))
{
ret = write(state->socket,
((char*)state->header) + state->amount_done,
sizeof(*state->header) - state->amount_done);
if(ret == 0 && _can_write)
{
free(state->header);
if(state->buffer)
free(state->buffer);
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d writing response header.\n", ret);
return;
}
_can_write = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header))
return;
debug_hexdump("tcp_usb: Sent Header (write response): ", state->header, sizeof(*state->header));
}
if((state->header->ep & USB_DIR_IN) != 0 && state->header->length > 0) // IN
{
ret = write(state->socket,
((char*)state->buffer) + (state->amount_done - sizeof(*state->header)),
state->header->length - (state->amount_done - sizeof(*state->header)));
if(ret == 0 && _can_write)
{
free(state->header);
if(state->buffer)
free(state->buffer);
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d writing response data.\n", ret);
return;
}
_can_write = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header) + state->header->length)
return;
debug_hexdump("tcp_usb: Wrote: ", state->buffer, state->header->length);
}
free(state->header);
if(state->buffer)
free(state->buffer);
state->state = tcp_usb_idle;
break;
case tcp_usb_write_request:
debug_printf("%s: tcp_usb_write_request\n", __func__);
if(state->amount_done < sizeof(*state->header))
{
ret = write(state->socket,
((char*)state->header) + state->amount_done,
sizeof(*state->header) - state->amount_done);
if(ret == 0 && _can_write)
{
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d writing request header!\n", ret);
return;
}
_can_write = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header))
return;
debug_hexdump("tcp_usb: Sent Header (write request): ", state->header, sizeof(*state->header));
}
if((state->header->ep & USB_DIR_IN) == 0 && state->header->length > 0) // OUT
{
ret = write(state->socket,
((char*)state->buffer) + (state->amount_done - sizeof(*state->header)),
state->header->length - (state->amount_done - sizeof(*state->header)));
if(ret == 0 && _can_write)
{
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d writing request data!\n", ret);
return;
}
_can_write = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header) + state->header->length)
return;
debug_hexdump("tcp_usb: Wrote: ", state->buffer, state->header->length);
}
state->state = tcp_usb_read_response;
state->amount_done = 0;
// Fall through
case tcp_usb_read_response:
debug_printf("%s: tcp_usb_read_response\n", __func__);
if(state->amount_done < sizeof(*state->header))
{
ret = read(state->socket,
((char*)state->header) + state->amount_done,
sizeof(*state->header) - state->amount_done);
if(ret == 0 && _can_read)
{
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d reading response header.\n", ret);
return;
}
_can_read = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header))
return;
debug_hexdump("tcp_usb: Got Header: ", state->header, sizeof(*state->header));
}
if((state->header->ep & USB_DIR_IN) != 0 && state->header->length > 0) // IN
{
ret = read(state->socket,
((char*)state->buffer) + (state->amount_done - sizeof(*state->header)),
state->header->length - (state->amount_done - sizeof(*state->header)));
if(ret == 0 && _can_read)
{
tcp_usb_do_closed(state);
return;
}
else if(ret == EWOULDBLOCK || ret == 0 || ret == -1)
return;
else if(ret < 0)
{
fprintf(stderr, "tcp_usb: Error %d reading response data.\n", ret);
return;
}
_can_read = 0;
state->amount_done += ret;
if(state->amount_done < sizeof(*state->header) + state->header->length)
return;
debug_hexdump("tcp_usb: Read: ", state->buffer, state->header->length);
}
state->state = tcp_usb_idle;
// Transfer complete! Call callback!
if(state->data_callback)
{
debug_printf("tcp_usb: calling callback!\n");
state->data_callback(state, state->callback_arg, state->header, state->buffer);
return;
}
else
{
fprintf(stderr, "tcp_usb: Request sent but no callback!\n");
state->state = tcp_usb_idle;
return;
}
break;
}
}
static void tcp_usb_read_callback(void *_arg)
{
tcp_usb_state_t *state = _arg;
tcp_usb_callback(state, 1, 0);
}
static void tcp_usb_write_callback(void *_arg)
{
tcp_usb_state_t *state = _arg;
tcp_usb_callback(state, 0, 1);
}
int tcp_usb_connect(tcp_usb_state_t *_state, char *_host, uint32_t _port)
{
_state->socket = socket(AF_INET, SOCK_STREAM, 0);
struct hostent *hostname = gethostbyname(_host);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(_port);
memcpy(&server_addr.sin_addr.s_addr,
hostname->h_addr, hostname->h_length);
int ret = connect(_state->socket, &server_addr, sizeof(server_addr));
if(ret < 0)
return -EIO;
_state->closed = 0;
int flags = fcntl(_state->socket, F_GETFL, 0);
fcntl(_state->socket, F_SETFL, flags | O_NONBLOCK);
qemu_set_fd_handler(_state->socket, tcp_usb_read_callback, tcp_usb_write_callback, _state);
return 0;
}
int tcp_usb_request(tcp_usb_state_t *_state, tcp_usb_header_t *_header, const char *_data)
{
debug_printf("%s.\n", __func__);
if(_state->state != tcp_usb_idle)
return -EBUSY;
debug_printf("%s starting request.\n", __func__);
_state->state = tcp_usb_write_request;
_state->amount_done = 0;
_state->buffer = (char*)_data;
_state->header = _header;
tcp_usb_callback(_state, 0, 1);
return 0;
}
void tcp_usb_host_init(tcp_usb_host_state_t *_state)
{
_state->socket = -1;
}
void tcp_usb_host_cleanup(tcp_usb_host_state_t *_state)
{
if(_state->socket >= 0)
{
close(_state->socket);
_state->socket = -1;
}
}
int tcp_usb_host_okay(tcp_usb_host_state_t *_state)
{
return 0;
}
int tcp_usb_host(tcp_usb_host_state_t *_state, uint32_t _port)
{
_state->socket = socket(AF_INET, SOCK_STREAM, 0);
if(_state->socket < 0)
return -EIO;
struct linger linger;
linger.l_onoff = 0;
linger.l_linger = 0;
setsockopt(_state->socket, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger));
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(_port);
server_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(_state->socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
return -EIO;
listen(_state->socket, 5);
return 0;
}
int tcp_usb_accept(tcp_usb_host_state_t *_host, tcp_usb_state_t *_client)
{
struct sockaddr_in addr;
size_t addr_sz = sizeof(addr);
debug_printf("%s: waiting on accept...\n", __func__);
_client->socket = accept(_host->socket, &addr, &addr_sz);
if(_client->socket < 0)
{
fprintf(stderr, "%s: accept error %d.\n", __func__, errno);
return -EIO;
}
_client->closed = 0;
int flags = fcntl(_client->socket, F_GETFL, 0);
fcntl(_client->socket, F_SETFL, flags | O_NONBLOCK);
qemu_set_fd_handler(_client->socket, tcp_usb_read_callback, tcp_usb_write_callback, _client);
debug_printf("%s: USB device accepted!\n", __func__);
return 0;
}
+5 -3
View File
@@ -9,12 +9,13 @@
#include "cpu.h"
#include "hw/dma/pl080.h"
#include "hw/i2c/ipod_touch_i2c.h"
#include "hw/usb/hcd-dwc2.h"
#include "hw/usb/hcd-tcp.h"
#include "hw/arm/ipod_touch_timer.h"
#include "hw/arm/ipod_touch_clock.h"
#include "hw/arm/ipod_touch_chipid.h"
#include "hw/arm/ipod_touch_gpio.h"
#include "hw/arm/ipod_touch_sysic.h"
#include "hw/arm/ipod_touch_usb_otg.h"
#include "hw/arm/ipod_touch_usb_phys.h"
#include "hw/arm/ipod_touch_spi.h"
#include "hw/arm/ipod_touch_sha1.h"
@@ -154,7 +155,8 @@ typedef struct {
IPodTouchChipIDState *chipid_state;
IPodTouchGPIOState *gpio_state;
IPodTouchSYSICState *sysic;
synopsys_usb_state *usb_otg;
MemoryRegion usb_dma_container_mr;
DWC2State *dwc2;
IPodTouchUSBPhysState *usb_phys_state;
IPodTouchSHA1State *sha1_state;
IPodTouchAESState *aes_state;
@@ -176,4 +178,4 @@ typedef struct {
IT2G_CPREG_VAR_DEF(REG1);
} IPodTouchMachineState;
#endif
#endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef HW_CS42L58_H
#define HW_CS42L58_H
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "hw/sysbus.h"
#include "hw/i2c/i2c.h"
#include "hw/irq.h"
#define TYPE_CS42L58 "cs42l58"
OBJECT_DECLARE_SIMPLE_TYPE(CS42L58State, CS42L58)
typedef struct CS42L58State {
I2CSlave i2c;
uint32_t cmd;
} CS42L58State;
#endif
+4 -3
View File
@@ -10,11 +10,12 @@
#define TYPE_IPOD_TOUCH_GPIO "ipodtouch.gpio"
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchGPIOState, IPOD_TOUCH_GPIO)
#define GPIO_BUTTON_POWER 0xC02
#define GPIO_BUTTON_HOME 0xC01
#define GPIO_BUTTON_VOLUP 0x902
#define GPIO_BUTTON_VOLDOWN 0xC00
#define GPIO_FORCE_DFU 0xB03
#define GPIO_BUTTON_VOLDOWN 0xC00
#define GPIO_BUTTON_HOME 0xC01
#define GPIO_BUTTON_POWER 0xC02
#define GPIO_DFU_STATUS 0xC03
#define GPIO_BUTTON_POWER_IRQ 0x7A
#define GPIO_BUTTON_HOME_IRQ 0x79
-39
View File
@@ -1,39 +0,0 @@
#ifndef HW_ISL29003DL_H
#define HW_ISL29003DL_H
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "hw/sysbus.h"
#include "hw/i2c/i2c.h"
#include "hw/irq.h"
#include "time.h"
#define TYPE_ISL29003DL "isl29003dl"
OBJECT_DECLARE_SIMPLE_TYPE(ISL29003DLState, ISL29003DL)
#define LIGHTSENSOR_COMMAND 0x00
#define LIGHTSENSOR_CONTROL 0x01
#define LIGHTSENSOR_IT_HI 0x02
#define LIGHTSENSOR_IT_LO 0x03
#define LIGHTSENSOR_LSB_SENSOR 0x04
#define LIGHTSENSOR_MSB_SENSOR 0x05
#define LIGHTSENSOR_LSB_TIMER 0x06
#define LIGHTSENSOR_MSB_TIMER 0x07
typedef struct ISL29003DLState {
I2CSlave i2c;
uint32_t cmd;
uint32_t command;
uint32_t ctrl;
uint32_t curreg;
uint32_t ready;
uint32_t it_hi;
uint32_t it_lo;
uint32_t lsb_sensor;
uint32_t msb_sensor;
uint32_t lsb_timer;
uint32_t msb_timer;
} ISL29003DLState;
#endif
+2 -5
View File
@@ -22,7 +22,6 @@ typedef struct IPodTouchLCDState
QemuConsole *con;
IPodTouchMultitouchState *mt;
int invalidate;
uint8_t brightness;
MemoryRegionSection fbsection;
qemu_irq irq;
uint32_t lcd_con;
@@ -32,11 +31,9 @@ typedef struct IPodTouchLCDState
uint32_t w1_hspan;
uint32_t w1_display_depth_info;
uint32_t render;
uint32_t unknown1;
QEMUTimer *refresh_timer;
} IPodTouchLCDState;
void lcd_changebrightness(int brightness);
#endif
#endif
+1 -13
View File
@@ -12,24 +12,12 @@
OBJECT_DECLARE_SIMPLE_TYPE(LIS302DLState, LIS302DL)
#define ACCEL_WHOAMI 0x0F
#define ACCEL_OUT_X 0x29
#define ACCEL_OUT_Y 0x2B
#define ACCEL_OUT_Z 0x2D
#define ACCEL_CTRL_REG1 0x20
#define ACCEL_CTRL_REG2 0x21
#define ACCEL_CTRL_REG3 0x22
#define ACCEL_WHOAMI_VALUE 0x3B
typedef struct LIS302DLState {
I2CSlave i2c;
uint32_t cmd;
uint32_t out_x;
uint32_t out_y;
uint32_t out_z;
uint16_t ctrl_reg1;
uint16_t ctrl_reg2;
uint16_t ctrl_reg3;
} LIS302DLState;
#endif
#endif
+1 -3
View File
@@ -12,8 +12,6 @@ typedef struct IPodTouchMBXState {
SysBusDevice busdev;
MemoryRegion iomem1;
MemoryRegion iomem2;
uint64_t addr;
bool alreadypatched;
} IPodTouchMBXState;
#endif
#endif
+1 -4
View File
@@ -12,7 +12,6 @@
#define TYPE_PCF50633 "pcf50633"
OBJECT_DECLARE_SIMPLE_TYPE(Pcf50633State, PCF50633)
#define PMU_DSBL1 0x30
#define PMU_MBCS1 0x4B
#define PMU_ADCC1 0x57
@@ -28,8 +27,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(Pcf50633State, PCF50633)
typedef struct Pcf50633State {
I2CSlave i2c;
uint32_t cmd;
uint32_t ready;
uint32_t curreg;
} Pcf50633State;
#endif
#endif
-268
View File
@@ -1,268 +0,0 @@
#ifndef HW_ARM_IPOD_TOUCH_USB_OTG_H
#define HW_ARM_IPOD_TOUCH_USB_OTG_H
#include "hw/irq.h"
#include "hw/usb.h"
#include "hw/usb/tcp_usb.h"
#define DEVICE_NAME "usb_synopsys"
#define TYPE_S5L8900USBOTG "s5l8900usbotg"
OBJECT_DECLARE_SIMPLE_TYPE(synopsys_usb_state, S5L8900USBOTG)
// Maximums supported by OIB
#define USB_NUM_ENDPOINTS 8
#define USB_NUM_FIFOS 16
#define RX_FIFO_DEPTH 0x1C0
#define TX_FIFO_DEPTH 0x1C0
#define TX_FIFO_STARTADDR 0x200
#define PERIODIC_TX_FIFO_STARTADDR 0x21B
#define PERIODIC_TX_FIFO_DEPTH 0x100
// Registers
#define GOTGCTL 0x0
#define GOTGINT 0x4
#define GAHBCFG 0x8
#define GUSBCFG 0xC
#define GRSTCTL 0x10
#define GINTSTS 0x14
#define GINTMSK 0x18
#define GRXSTSR 0x1C
#define GRXSTSP 0x20
#define GRXFSIZ 0x24
#define GNPTXFSIZ 0x28
#define GNPTXFSTS 0x2C
#define GHWCFG1 0x44
#define GHWCFG2 0x48
#define GHWCFG3 0x4C
#define GHWCFG4 0x50
#define DIEPTXF(x) (0x100 + (4*(x)))
#define DCFG 0x800
#define DCTL 0x804
#define DSTS 0x808
#define DIEPMSK 0x810
#define DOEPMSK 0x814
#define DAINTSTS 0x818
#define DAINTMSK 0x81C
#define DTKNQR1 0x820
#define DTKNQR2 0x824
#define DTKNQR3 0x830
#define DTKNQR4 0x834
#define USB_INREGS 0x900
#define USB_OUTREGS 0xB00
#define USB_EPREGS_SIZE 0x200
#define USB_FIFO_START 0x1000
#define USB_FIFO_SIZE (0x100*(USB_NUM_FIFOS+1))
#define USB_FIFO_END (USB_FIFO_START+USB_FIFO_SIZE)
#define PCGCCTL 0xE00
#define PCGCCTL_ONOFF_MASK 3 // bits 0, 1
#define PCGCCTL_ON 0
#define PCGCCTL_OFF 1
#define GOTGCTL_BSESSIONVALID (1 << 19)
#define GOTGCTL_SESSIONREQUEST (1 << 1)
#define GAHBCFG_DMAEN (1 << 5)
#define GAHBCFG_BSTLEN_SINGLE (0 << 1)
#define GAHBCFG_BSTLEN_INCR (1 << 1)
#define GAHBCFG_BSTLEN_INCR4 (3 << 1)
#define GAHBCFG_BSTLEN_INCR8 (5 << 1)
#define GAHBCFG_BSTLEN_INCR16 (7 << 1)
#define GAHBCFG_MASKINT 0x1
#define GUSBCFG_TURNAROUND_MASK 0xF
#define GUSBCFG_TURNAROUND_SHIFT 10
#define GUSBCFG_HNPENABLE (1 << 9)
#define GUSBCFG_SRPENABLE (1 << 8)
#define GUSBCFG_PHYIF16BIT (1 << 3)
#define USB_UNKNOWNREG1_START 0x1708
#define GHWCFG2_TKNDEPTH_SHIFT 26
#define GHWCFG2_TKNDEPTH_MASK 0xF
#define GHWCFG2_NUM_ENDPOINTS_SHIFT 10
#define GHWCFG2_NUM_ENDPOINTS_MASK 0xf
#define GHWCFG4_DED_FIFO_EN (1 << 25)
#define GRSTCTL_AHBIDLE (1 << 31)
#define GRSTCTL_TXFFLUSH (1 << 5)
#define GRSTCTL_TXFFNUM_SHIFT 6
#define GRSTCTL_TXFFNUM_MASK 0x1f
#define GRSTCTL_CORESOFTRESET 0x1
#define GRSTCTL_TKNFLUSH 3
#define GINTMSK_NONE 0x0
#define GINTMSK_OTG (1 << 2)
#define GINTMSK_SOF (1 << 3)
#define GINTMSK_GINNAKEFF (1 << 6)
#define GINTMSK_GOUTNAKEFF (1 << 7)
#define GINTMSK_SUSPEND (1 << 11)
#define GINTMSK_RESET (1 << 12)
#define GINTMSK_ENUMDONE (1 << 13)
#define GINTMSK_EPMIS (1 << 17)
#define GINTMSK_INEP (1 << 18)
#define GINTMSK_OEP (1 << 19)
#define GINTMSK_DISCONNECT (1 << 29)
#define GINTMSK_RESUME (1 << 31)
#define GOTGINT_SESENDDET (1 << 2)
#define FIFO_DEPTH_SHIFT 16
#define GNPTXFSTS_GET_TXQSPCAVAIL(x) GET_BITS(x, 16, 8)
#define GHWCFG4_DED_FIFO_EN (1 << 25)
#define DAINT_ALL 0xFFFFFFFF
#define DAINT_NONE 0
#define DAINT_OUT_SHIFT 16
#define DAINT_IN_SHIFT 0
#define DCTL_SFTDISCONNECT 0x2
#define DCTL_PROGRAMDONE (1 << 11)
#define DCTL_CGOUTNAK (1 << 10)
#define DCTL_SGOUTNAK (1 << 9)
#define DCTL_CGNPINNAK (1 << 8)
#define DCTL_SGNPINNAK (1 << 7)
#define DSTS_GET_SPEED(x) GET_BITS(x, 1, 2)
#define DCFG_NZSTSOUTHSHK (1 << 2)
#define DCFG_EPMSCNT (1 << 18)
#define DCFG_HISPEED 0x0
#define DCFG_FULLSPEED 0x1
#define DCFG_DEVICEADDR_UNSHIFTED_MASK 0x7F
#define DCFG_DEVICEADDR_SHIFT 4
#define DCFG_DEVICEADDRMSK (DCFG_DEVICEADDR_UNSHIFTED_MASK << DCFG_DEVICEADDR_SHIFT)
#define DCFG_ACTIVE_EP_COUNT_MASK 0x1f
#define DCFG_ACTIVE_EP_COUNT_SHIFT 18
#define DOEPTSIZ0_SUPCNT_MASK 0x3
#define DOEPTSIZ0_SUPCNT_SHIFT 29
#define DOEPTSIZ0_PKTCNT_MASK 0x1
#define DEPTSIZ0_XFERSIZ_MASK 0x7F
#define DIEPTSIZ_MC_MASK 0x3
#define DIEPTSIZ_MC_SHIFT 29
#define DEPTSIZ_PKTCNT_MASK 0x3FF
#define DEPTSIZ_PKTCNT_SHIFT 19
#define DEPTSIZ_XFERSIZ_MASK 0x1FFFF
// ENDPOINT_DIRECTIONS register has two bits per endpoint. 0, 1 for endpoint 0. 1, 2 for end point 1, etc.
#define USB_EP_DIRECTION(ep) (USBDirection)(2-((GET_REG(USB + GHWCFG1) >> ((ep) * 2)) & 0x3))
#define USB_ENDPOINT_DIRECTIONS_BIDIR 0
#define USB_ENDPOINT_DIRECTIONS_IN 1
#define USB_ENDPOINT_DIRECTIONS_OUT 2
#define USB_START_DELAYUS 10000
#define USB_SFTDISCONNECT_DELAYUS 4000
#define USB_ONOFFSTART_DELAYUS 100
#define USB_RESETWAITFINISH_DELAYUS 1000
#define USB_SFTCONNECT_DELAYUS 250
#define USB_PROGRAMDONE_DELAYUS 10
#define USB_EPCON_ENABLE (1 << 31)
#define USB_EPCON_DISABLE (1 << 30)
#define USB_EPCON_SETD0PID (1 << 28)
#define USB_EPCON_SETNAK (1 << 27)
#define USB_EPCON_CLEARNAK (1 << 26)
#define USB_EPCON_TXFNUM_MASK 0xf
#define USB_EPCON_TXFNUM_SHIFT 22
#define USB_EPCON_STALL (1 << 21)
#define USB_EPCON_TYPE_MASK 0x3
#define USB_EPCON_TYPE_SHIFT 18
#define USB_EPCON_NAKSTS (1 << 17)
#define USB_EPCON_ACTIVE (1 << 15)
#define USB_EPCON_NEXTEP_MASK 0xF
#define USB_EPCON_NEXTEP_SHIFT 11
#define USB_EPCON_MPS_MASK 0x7FF
#define USB_EPINT_INEPNakEff 0x40
#define USB_EPINT_INTknEPMis 0x20
#define USB_EPINT_INTknTXFEmp 0x10
#define USB_EPINT_TimeOUT 0x8
#define USB_EPINT_AHBErr 0x4
#define USB_EPINT_EPDisbld 0x2
#define USB_EPINT_XferCompl 0x1
#define USB_EPINT_Back2BackSetup (1 << 6)
#define USB_EPINT_OUTTknEPDis 0x10
#define USB_EPINT_SetUp 0x8
#define USB_EPINT_EpDisbld 0x1
#define USB_EPINT_NONE 0
#define USB_EPINT_ALL 0xFFFFFFFF
#define USB_2_0 0x0200
#define USB_HIGHSPEED 0
#define USB_FULLSPEED 1
#define USB_LOWSPEED 2
#define USB_FULLSPEED_48_MHZ 3
#define USB_CONTROLEP 0
typedef struct _synopsys_usb_ep_state
{
uint32_t control;
uint32_t tx_size;
uint32_t fifo;
uint32_t interrupt_status;
hwaddr dma_address;
hwaddr dma_buffer;
} synopsys_usb_ep_state;
typedef struct synopsys_usb_state
{
SysBusDevice busdev;
MemoryRegion iomem;
qemu_irq irq;
char *server_host;
uint32_t server_port;
tcp_usb_state_t tcp_state;
uint32_t pcgcctl;
uint32_t ghwcfg1;
uint32_t ghwcfg2;
uint32_t ghwcfg3;
uint32_t ghwcfg4;
uint32_t gahbcfg;
uint32_t gusbcfg;
uint32_t grxfsiz;
uint32_t gnptxfsiz;
uint32_t gotgctl;
uint32_t gotgint;
uint32_t grstctl;
uint32_t gintmsk;
uint32_t gintsts;
uint32_t dptxfsiz[USB_NUM_FIFOS];
uint32_t dctl;
uint32_t dcfg;
uint32_t dsts;
uint32_t daintmsk;
uint32_t daintsts;
uint32_t diepmsk;
uint32_t doepmsk;
synopsys_usb_ep_state in_eps[USB_NUM_ENDPOINTS];
synopsys_usb_ep_state out_eps[USB_NUM_ENDPOINTS];
uint8_t fifos[0x100 * (USB_NUM_FIFOS+1)];
} synopsys_usb_state;
DeviceState *ipod_touch_init_usb_otg(qemu_irq _irq, uint32_t _hwcfg[4]);
#endif
+35
View File
@@ -0,0 +1,35 @@
#ifndef HW_USB_HCD_TCP_H
#define HW_USB_HCD_TCP_H
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "qom/object.h"
#include "hw/usb.h"
#include "io/channel.h"
#include "qemu/coroutine.h"
#include "qapi/error.h"
#define TYPE_USB_TCP_HOST "usb-tcp-host"
OBJECT_DECLARE_SIMPLE_TYPE(USBTCPHostState, USB_TCP_HOST)
typedef struct USBTCPPacket {
USBPacket p;
void *buffer;
USBDevice *dev;
USBTCPHostState *s;
uint8_t addr;
} USBTCPPacket;
struct USBTCPHostState {
SysBusDevice parent_obj;
USBBus bus;
USBPort uports[3];
QIOChannel *ioc;
CoMutex write_mutex;
Error *migration_blocker;
bool closed;
bool stopped;
};
#endif /* HW_USB_HCD_TCP_H */
-102
View File
@@ -1,102 +0,0 @@
#ifndef HW_TCP_USB
#define HW_TCP_USB
/*
* USB over TCP driver.
*
* Copyright (c) 2011 Richard Ian Taylor.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qemu/main-loop.h"
#include "hw/usb.h"
#include "hw/sysbus.h"
enum
{
tcp_usb_setup = 1 << 0,
tcp_usb_reset = 1 << 1,
tcp_usb_enumdone = 1 << 2,
};
typedef enum _tcp_usb_state_enum
{
tcp_usb_idle,
// Client
tcp_usb_read_request,
tcp_usb_write_response,
// Host
tcp_usb_write_request,
tcp_usb_read_response,
} tcp_usb_state_enum_t;
typedef struct _tcp_usb_header
{
uint8_t addr;
uint8_t ep;
uint8_t flags;
int16_t length;
} __attribute__((packed)) tcp_usb_header_t;
struct _tcp_usb_state;
typedef int (*tcp_usb_callback_t)(struct _tcp_usb_state *_status, void *_arg, tcp_usb_header_t *_hdr, char *_buffer);
typedef void (*tcp_usb_closed_t)(struct _tcp_usb_state *_state, void *_arg);
typedef struct _tcp_usb_state
{
int socket;
int closed;
tcp_usb_state_enum_t state;
tcp_usb_header_t *header;
char *buffer;
size_t amount_done;
tcp_usb_closed_t closed_callback;
tcp_usb_callback_t data_callback;
void *callback_arg;
} tcp_usb_state_t;
void tcp_usb_init(tcp_usb_state_t *_state, tcp_usb_callback_t _cb, tcp_usb_closed_t _closed, void *_arg);
void tcp_usb_cleanup(tcp_usb_state_t *_state);
int tcp_usb_closed(tcp_usb_state_t *_state);
int tcp_usb_connect(tcp_usb_state_t *_state, char *_host, uint32_t _port);
int tcp_usb_request(tcp_usb_state_t *_state, tcp_usb_header_t *_header, const char *_data);
typedef struct _tcp_usb_host_state
{
int socket;
} tcp_usb_host_state_t;
void tcp_usb_host_init(tcp_usb_host_state_t *_state);
void tcp_usb_host_cleanup(tcp_usb_host_state_t *_state);
int tcp_usb_host_okay(tcp_usb_host_state_t *_state);
int tcp_usb_host(tcp_usb_host_state_t *_state, uint32_t _port);
int tcp_usb_accept(tcp_usb_host_state_t *_host, tcp_usb_state_t *_client);
#endif //HW_TCP_USB