Compare commits
19
Commits
dfu
..
dfu_s5l8720
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd6f1e0ed9 | ||
|
|
aa88deb054 | ||
|
|
328815631b | ||
|
|
c5998ab084 | ||
|
|
1c586e8a0c | ||
|
|
7022646c4d | ||
|
|
fa0981b602 | ||
|
|
0cb390e281 | ||
|
|
0d8014f8db | ||
|
|
e241f91a5b | ||
|
|
4400b861c8 | ||
|
|
cae1b51a78 | ||
|
|
a99e51abfa | ||
|
|
ce74809f11 | ||
|
|
ceb93afd79 | ||
|
|
bad3d0cc90 | ||
|
|
82b95a84a3 | ||
|
|
28f87fc7d6 | ||
|
|
973b5a90ef |
No files matched your search
+19
@@ -2,6 +2,18 @@
|
||||
|
||||
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
|
||||
|
||||
@@ -14,6 +26,9 @@ 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
|
||||
|
||||
@@ -23,12 +38,16 @@ 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
|
||||
|
||||
|
||||
+20
-17
@@ -96,7 +96,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem,
|
||||
|
||||
// load the bootrom (vrom)
|
||||
uint8_t *file_data = NULL;
|
||||
unsigned long fsize;
|
||||
gsize 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,6 +174,13 @@ 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;
|
||||
@@ -229,6 +236,7 @@ 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]);
|
||||
@@ -396,24 +404,13 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
memory_region_add_subregion(sysmem, UNKNOWN1_MEM_BASE, &unknown1_state->iomem);
|
||||
|
||||
// init 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));
|
||||
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;
|
||||
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);
|
||||
@@ -448,6 +445,9 @@ 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,6 +457,9 @@ 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);
|
||||
@@ -561,4 +564,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)
|
||||
@@ -0,0 +1,54 @@
|
||||
#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)
|
||||
@@ -1,5 +1,7 @@
|
||||
#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) {
|
||||
@@ -24,7 +26,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"; // 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 -v zalloc_debug"; // 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...
|
||||
@@ -45,7 +47,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);
|
||||
}
|
||||
|
||||
@@ -86,7 +88,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%08x\n", __func__, addr);
|
||||
//fprintf(stderr, "%s: read from location 0x%08lx\n", __func__, addr);
|
||||
|
||||
IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque;
|
||||
switch(addr)
|
||||
@@ -101,8 +103,10 @@ 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:
|
||||
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
|
||||
printf("%s: read invalid location 0x%08x.\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@@ -111,7 +115,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%08x to 0x%08x\n", __func__, val, addr);
|
||||
//printf("%s: writing 0x%08lx to 0x%08lx\n", __func__, val, addr);
|
||||
|
||||
switch(addr) {
|
||||
case 0xC00:
|
||||
@@ -146,8 +150,11 @@ 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 not suported yet!\n"); }
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
|
||||
static void s5l8900_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
|
||||
{
|
||||
printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
|
||||
//fprintf(stderr, "%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;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
#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)
|
||||
+25
-11
@@ -3,9 +3,11 @@
|
||||
#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)
|
||||
@@ -26,8 +28,10 @@ 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:
|
||||
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
|
||||
printf("%s: read invalid location 0x%08x.\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@@ -36,15 +40,16 @@ 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->unknown1 = val;
|
||||
s->render = val;
|
||||
qemu_irq_lower(s->irq);
|
||||
// qemu_irq_raise(s->irq);
|
||||
break;
|
||||
case 0x20:
|
||||
s->w1_display_depth_info = val;
|
||||
@@ -61,6 +66,11 @@ 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;
|
||||
@@ -69,6 +79,7 @@ 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 {
|
||||
@@ -77,8 +88,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\n", r, g, b);
|
||||
((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
|
||||
// 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)));
|
||||
s += 4;
|
||||
d += 4;
|
||||
} while (-- width != 0);
|
||||
@@ -86,7 +97,7 @@ static void draw_line32_32(void *opaque, uint8_t *d, const uint8_t *s, int width
|
||||
|
||||
static void lcd_refresh(void *opaque)
|
||||
{
|
||||
//fprintf(stderr, "%s: refreshing LCD screen\n", __func__);
|
||||
// printf("%s: refreshing LCD screen\n", __func__);
|
||||
|
||||
IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(lcd->con);
|
||||
@@ -141,7 +152,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("CLICKY %d %d %d %d\n", x, y, z, buttons_state);
|
||||
// printf("x %d y %d z %d state %d\n", x, y, z, buttons_state);
|
||||
|
||||
// convert x and y to fractional numbers
|
||||
float fx = x / pow(2, 15);
|
||||
@@ -165,9 +176,12 @@ static void refresh_timer_tick(void *opaque)
|
||||
{
|
||||
IPodTouchLCDState *s = (IPodTouchLCDState *)opaque;
|
||||
|
||||
qemu_irq_raise(s->irq);
|
||||
if (s->render == 0x1)
|
||||
qemu_irq_raise(s->irq);
|
||||
else if (s->render == 0xFF)
|
||||
qemu_irq_lower(s->irq);
|
||||
|
||||
timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY);
|
||||
timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 60);//LCD_REFRESH_RATE_FREQUENCY);
|
||||
}
|
||||
|
||||
static void ipod_touch_lcd_realize(DeviceState *dev, Error **errp)
|
||||
@@ -215,4 +229,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)
|
||||
@@ -12,8 +12,21 @@ static uint8_t lis302dl_recv(I2CSlave *i2c)
|
||||
|
||||
switch(s->cmd) {
|
||||
case ACCEL_WHOAMI:
|
||||
return ACCEL_WHOAMI_VALUE; // whoami value
|
||||
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;
|
||||
default:
|
||||
printf("%s Unknown register %d\n", __func__, s->cmd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -52,4 +65,4 @@ static void lis302dl_register_types(void)
|
||||
type_register_static(&lis302dl_info);
|
||||
}
|
||||
|
||||
type_init(lis302dl_register_types)
|
||||
type_init(lis302dl_register_types)
|
||||
+21
-5
@@ -9,7 +9,9 @@ static uint32_t reverse_byte_order(uint32_t value) {
|
||||
|
||||
static uint64_t ipod_touch_mbx1_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
printf("%s: read from location 0x%08x\n", __func__, addr);
|
||||
IPodTouchMBXState *s = (IPodTouchMBXState *)opaque;
|
||||
if (addr != 0x1020)
|
||||
printf("%s: read from location 0x%08x\n", __func__, addr);
|
||||
switch(addr)
|
||||
{
|
||||
case 0x12c:
|
||||
@@ -17,7 +19,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 0x10000;
|
||||
return s->addr != 0x0 ? s->addr : 0x10000;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -28,10 +30,19 @@ 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()
|
||||
static void patch_kernel(bool alreadypatched)
|
||||
{
|
||||
if (alreadypatched) return;
|
||||
alreadypatched = 1;
|
||||
// patch the loading of the AppleBCM4325 driver
|
||||
char *bcm4325_vars = "test";
|
||||
|
||||
@@ -91,11 +102,16 @@ static void patch_kernel()
|
||||
|
||||
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();
|
||||
patch_kernel(s->alreadypatched);
|
||||
break;
|
||||
case 0x4:
|
||||
return 0xFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -149,4 +165,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)
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr);
|
||||
if (addr != 0x00000)
|
||||
fprintf(stderr, "%s: read from location 0x%08lx\n", __func__, addr);
|
||||
|
||||
IPodTouchMIPIDSIState *s = (IPodTouchMIPIDSIState *)opaque;
|
||||
switch(addr)
|
||||
@@ -24,7 +25,7 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz
|
||||
case REG_FIFOCTRL:
|
||||
return rDSIM_FIFOCTRL_EmptyHSfr;
|
||||
default:
|
||||
// hw_error("%s: read invalid location 0x%08x.\n", __func__, addr);
|
||||
printf("%s: read invalid location 0x%08lx.\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@@ -33,13 +34,16 @@ 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%08x to 0x%08x\n", __func__, val, addr);
|
||||
fprintf(stderr, "%s: writing 0x%08lx to 0x%08lx\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;
|
||||
}
|
||||
@@ -89,4 +93,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)
|
||||
@@ -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 {
|
||||
hw_error("Unknown command 0x%02x!", value);
|
||||
printf("%s Unknown command 0x%02x!\n", __func__, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
static void initialize_nor(IPodTouchNORSPIState *s)
|
||||
{
|
||||
unsigned long fsize;
|
||||
gsize 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("Unknown command %d!\n", value);
|
||||
hw_error("Unknown command 0x%02x!", value);
|
||||
printf("%s Unknown command 0x%02x!\n", __func__, value);
|
||||
// hw_error("Unknown command 0x%02x!", value);
|
||||
}
|
||||
|
||||
return 0x0;
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -27,10 +41,10 @@ static uint8_t pcf50633_recv(I2CSlave *i2c)
|
||||
|
||||
switch(s->cmd) {
|
||||
case PMU_MBCS1:
|
||||
res = 0; // battery power source
|
||||
res = 1; // battery power source
|
||||
break;
|
||||
case PMU_ADCC1:
|
||||
res = 0; // battery charge voltage
|
||||
res = 3; // battery charge voltage
|
||||
break;
|
||||
case PMU_RTCSC: // seconds
|
||||
res = int_to_bcd(tm.tm_sec);
|
||||
@@ -70,7 +84,22 @@ static uint8_t pcf50633_recv(I2CSlave *i2c)
|
||||
static int pcf50633_send(I2CSlave *i2c, uint8_t data)
|
||||
{
|
||||
Pcf50633State *s = PCF50633(i2c);
|
||||
s->cmd = data;
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -101,4 +130,4 @@ static void pcf50633_register_types(void)
|
||||
type_register_static(&pcf50633_info);
|
||||
}
|
||||
|
||||
type_init(pcf50633_register_types)
|
||||
type_init(pcf50633_register_types)
|
||||
@@ -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 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);
|
||||
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);
|
||||
|
||||
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 = 14;
|
||||
uint16_t length = s->blklen * s->numblk;
|
||||
frame_header->frame_length = length;
|
||||
frame_header->checksum = length ^ 0xffff;
|
||||
g_queue_push_tail(s->rx_fifo, frame_header);
|
||||
@@ -83,6 +83,9 @@ 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));
|
||||
}
|
||||
@@ -101,7 +104,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;
|
||||
|
||||
@@ -146,7 +149,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;
|
||||
|
||||
@@ -164,11 +167,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;
|
||||
return s->resp1 == 0 ? 0x7465 : s->resp1;
|
||||
case SDIO_RESP2:
|
||||
return s->resp2;
|
||||
return s->resp2 == 0 ? 0x7374 : s->resp2;
|
||||
case SDIO_RESP3:
|
||||
return s->resp3;
|
||||
return s->resp3 == 0 ? 0xFFFF : s->resp3;
|
||||
case SDIO_CSR:
|
||||
return s->csr;
|
||||
case SDIO_IRQ:
|
||||
@@ -249,4 +252,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)
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "hw/arm/ipod_touch_sha1.h"
|
||||
|
||||
static uint64_t swapLong(void *X) {
|
||||
uint64_t x = (uint64_t) X;
|
||||
static uint64_t swapLong(uint64_t x) {
|
||||
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
|
||||
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
||||
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
|
||||
@@ -150,4 +149,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)
|
||||
@@ -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 ~0; // s->irqstat;
|
||||
return s->irqstat; // ~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,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)
|
||||
@@ -0,0 +1,777 @@
|
||||
/*
|
||||
* 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)
|
||||
@@ -19,8 +19,9 @@ 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;
|
||||
//hw_error("%s: read invalid location 0x%08x\n", __func__, addr);
|
||||
//return 0x0;
|
||||
printf("%s: read invalid location 0x%08x\n", __func__, addr);
|
||||
return 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +48,7 @@ static void ipod_touch_usb_phys_write(void *opaque, hwaddr addr, uint64_t val, u
|
||||
return;
|
||||
|
||||
default:
|
||||
//hw_error("%s: write invalid location 0x%08x.\n", __func__, addr);
|
||||
printf("%s: write invalid location 0x%08x.\n", __func__, addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -85,4 +86,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
@@ -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_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'))
|
||||
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'))
|
||||
|
||||
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'))
|
||||
|
||||
@@ -137,8 +137,3 @@ config USB_DWC3
|
||||
config XLNX_USB_SUBSYS
|
||||
bool
|
||||
select USB_DWC3
|
||||
|
||||
config USB_TCP
|
||||
bool
|
||||
default y
|
||||
depends on USB
|
||||
@@ -1368,9 +1368,6 @@ 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)
|
||||
@@ -1390,56 +1387,6 @@ 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,
|
||||
@@ -1501,29 +1448,6 @@ 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);
|
||||
@@ -1538,13 +1462,6 @@ 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,
|
||||
@@ -1556,7 +1473,6 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
|
||||
#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;
|
||||
|
||||
@@ -59,18 +57,12 @@ 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;
|
||||
@@ -149,44 +141,6 @@ 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)];
|
||||
@@ -226,9 +180,6 @@ 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)
|
||||
|
||||
|
||||
@@ -1,457 +0,0 @@
|
||||
#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
@@ -11,7 +11,7 @@ system_ss.add(when: 'CONFIG_USB', if_true: files(
|
||||
'pcap.c',
|
||||
))
|
||||
|
||||
system_ss.add(when: 'CONFIG_USB_TCP', if_true: files('hcd-tcp.c'))
|
||||
system_ss.add(when: 'CONFIG_USB', if_true: files('tcp_usb.c'))
|
||||
|
||||
# usb host adapters
|
||||
system_ss.add(when: 'CONFIG_USB_UHCI', if_true: files('hcd-uhci.c'))
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#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
|
||||
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -9,13 +9,12 @@
|
||||
#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"
|
||||
@@ -155,8 +154,7 @@ typedef struct {
|
||||
IPodTouchChipIDState *chipid_state;
|
||||
IPodTouchGPIOState *gpio_state;
|
||||
IPodTouchSYSICState *sysic;
|
||||
MemoryRegion usb_dma_container_mr;
|
||||
DWC2State *dwc2;
|
||||
synopsys_usb_state *usb_otg;
|
||||
IPodTouchUSBPhysState *usb_phys_state;
|
||||
IPodTouchSHA1State *sha1_state;
|
||||
IPodTouchAESState *aes_state;
|
||||
@@ -178,4 +176,4 @@ typedef struct {
|
||||
IT2G_CPREG_VAR_DEF(REG1);
|
||||
} IPodTouchMachineState;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#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
|
||||
@@ -10,12 +10,11 @@
|
||||
#define TYPE_IPOD_TOUCH_GPIO "ipodtouch.gpio"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchGPIOState, IPOD_TOUCH_GPIO)
|
||||
|
||||
#define GPIO_BUTTON_VOLUP 0x902
|
||||
#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_HOME 0xC01
|
||||
#define GPIO_BUTTON_VOLUP 0x902
|
||||
#define GPIO_BUTTON_VOLDOWN 0xC00
|
||||
#define GPIO_FORCE_DFU 0xB03
|
||||
|
||||
#define GPIO_BUTTON_POWER_IRQ 0x7A
|
||||
#define GPIO_BUTTON_HOME_IRQ 0x79
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#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
|
||||
@@ -22,6 +22,7 @@ typedef struct IPodTouchLCDState
|
||||
QemuConsole *con;
|
||||
IPodTouchMultitouchState *mt;
|
||||
int invalidate;
|
||||
uint8_t brightness;
|
||||
MemoryRegionSection fbsection;
|
||||
qemu_irq irq;
|
||||
uint32_t lcd_con;
|
||||
@@ -31,9 +32,11 @@ typedef struct IPodTouchLCDState
|
||||
uint32_t w1_hspan;
|
||||
uint32_t w1_display_depth_info;
|
||||
|
||||
uint32_t unknown1;
|
||||
uint32_t render;
|
||||
|
||||
QEMUTimer *refresh_timer;
|
||||
} IPodTouchLCDState;
|
||||
|
||||
#endif
|
||||
void lcd_changebrightness(int brightness);
|
||||
|
||||
#endif
|
||||
@@ -12,12 +12,24 @@
|
||||
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
|
||||
@@ -12,6 +12,8 @@ typedef struct IPodTouchMBXState {
|
||||
SysBusDevice busdev;
|
||||
MemoryRegion iomem1;
|
||||
MemoryRegion iomem2;
|
||||
uint64_t addr;
|
||||
bool alreadypatched;
|
||||
} IPodTouchMBXState;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -12,6 +12,7 @@
|
||||
#define TYPE_PCF50633 "pcf50633"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Pcf50633State, PCF50633)
|
||||
|
||||
#define PMU_DSBL1 0x30
|
||||
#define PMU_MBCS1 0x4B
|
||||
#define PMU_ADCC1 0x57
|
||||
|
||||
@@ -27,6 +28,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(Pcf50633State, PCF50633)
|
||||
typedef struct Pcf50633State {
|
||||
I2CSlave i2c;
|
||||
uint32_t cmd;
|
||||
uint32_t ready;
|
||||
uint32_t curreg;
|
||||
} Pcf50633State;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,268 @@
|
||||
#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
|
||||
@@ -1,35 +0,0 @@
|
||||
#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 */
|
||||
@@ -0,0 +1,102 @@
|
||||
#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
|
||||
Reference in new issue
Block a user