Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d8ef87cc0 | ||
|
|
a0698a741e |
No files matched your search
+21
-11
@@ -174,13 +174,6 @@ static inline qemu_irq s5l8900_get_irq(IPodTouchMachineState *s, int n)
|
||||
return s->irq[n / S5L8720_VIC_SIZE][n % S5L8720_VIC_SIZE];
|
||||
}
|
||||
|
||||
static uint32_t s5l8720_usb_hwcfg[] = {
|
||||
0,
|
||||
0x7a8f60d0,
|
||||
0x082000e8,
|
||||
0x01f08024
|
||||
};
|
||||
|
||||
static void ipod_touch_key_event(void *opaque, int keycode)
|
||||
{
|
||||
bool do_irq = false;
|
||||
@@ -403,10 +396,23 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
memory_region_add_subregion(sysmem, UNKNOWN1_MEM_BASE, &unknown1_state->iomem);
|
||||
|
||||
// init USB OTG
|
||||
dev = ipod_touch_init_usb_otg(s5l8900_get_irq(nms, S5L8720_USB_OTG_IRQ), s5l8720_usb_hwcfg);
|
||||
synopsys_usb_state *usb_otg = S5L8900USBOTG(dev);
|
||||
nms->usb_otg = usb_otg;
|
||||
memory_region_add_subregion(sysmem, USBOTG_MEM_BASE, &nms->usb_otg->iomem);
|
||||
dev = qdev_new("dwc2-usb");
|
||||
DWC2State *dwc2 = DWC2_USB(dev);
|
||||
nms->dwc2 = dwc2;
|
||||
memory_region_add_subregion(sysmem, USBOTG_MEM_BASE, &dwc2->container);
|
||||
// TODO add IRQ etc
|
||||
memory_region_init(&nms->usb_dma_container_mr, OBJECT(dev), "appleusb.dma-container-mr", UINT32_MAX);
|
||||
object_property_add_const_link(OBJECT(nms->dwc2), "dma-mr", OBJECT(&nms->usb_dma_container_mr));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
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");
|
||||
@@ -526,6 +532,10 @@ static void ipod_touch_machine_init(MachineState *machine)
|
||||
qemu_register_reset(ipod_touch_cpu_reset, nms);
|
||||
|
||||
qemu_add_kbd_event_handler(ipod_touch_key_event, spi4_state->mt);
|
||||
|
||||
// toggle DFU
|
||||
gpio_set_on(nms->gpio_state->gpio_state, GPIO_FORCE_DFU);
|
||||
nms->usb_phys_state->is_cable_connected = true;
|
||||
}
|
||||
|
||||
static void ipod_touch_machine_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
static void s5l8900_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
|
||||
{
|
||||
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
|
||||
printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
|
||||
IPodTouchGPIOState *s = (struct IPodTouchGPIOState *) opaque;
|
||||
|
||||
// TODO this should be implemented at one point
|
||||
|
||||
switch(addr) {
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1,616 +0,0 @@
|
||||
/*
|
||||
* Synopsys DesignWareCore for USB OTG.
|
||||
*
|
||||
* Copyright (c) 2011 Richard Ian Taylor.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/ipod_touch_usb_otg.h"
|
||||
|
||||
static inline size_t synopsys_usb_tx_fifo_start(synopsys_usb_state *_state, uint32_t _fifo)
|
||||
{
|
||||
if(_fifo == 0)
|
||||
return _state->gnptxfsiz >> 16;
|
||||
else
|
||||
return _state->dptxfsiz[_fifo-1] >> 16;
|
||||
}
|
||||
|
||||
static inline size_t synopsys_usb_tx_fifo_size(synopsys_usb_state *_state, uint32_t _fifo)
|
||||
{
|
||||
if(_fifo == 0)
|
||||
return _state->gnptxfsiz & 0xFFFF;
|
||||
else
|
||||
return _state->dptxfsiz[_fifo-1] & 0xFFFF;
|
||||
}
|
||||
|
||||
static void synopsys_usb_update_irq(synopsys_usb_state *_state)
|
||||
{
|
||||
_state->daintsts = 0;
|
||||
_state->gintsts &=~ (GINTMSK_OEP | GINTMSK_INEP | GINTMSK_OTG);
|
||||
|
||||
if(_state->gotgint)
|
||||
_state->gintsts |= GINTMSK_OTG;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < USB_NUM_ENDPOINTS; i++)
|
||||
{
|
||||
if(_state->out_eps[i].interrupt_status & _state->doepmsk)
|
||||
{
|
||||
_state->daintsts |= 1 << (i+DAINT_OUT_SHIFT);
|
||||
if(_state->daintmsk & (1 << (i+DAINT_OUT_SHIFT)))
|
||||
_state->gintsts |= GINTMSK_OEP;
|
||||
}
|
||||
|
||||
if(_state->in_eps[i].interrupt_status & _state->diepmsk)
|
||||
{
|
||||
_state->daintsts |= 1 << (i+DAINT_IN_SHIFT);
|
||||
if(_state->daintmsk & (1 << (i+DAINT_IN_SHIFT)))
|
||||
_state->gintsts |= GINTMSK_INEP;
|
||||
}
|
||||
}
|
||||
|
||||
if((_state->pcgcctl & 3) == 0 && _state->gintmsk & _state->gintsts)
|
||||
{
|
||||
//printf("USB: IRQ triggered 0x%08x & 0x%08x.\n", _state->gintsts, _state->gintmsk);
|
||||
qemu_irq_raise(_state->irq);
|
||||
}
|
||||
else
|
||||
qemu_irq_lower(_state->irq);
|
||||
}
|
||||
|
||||
static void synopsys_usb_update_ep(synopsys_usb_state *_state, synopsys_usb_ep_state *_ep)
|
||||
{
|
||||
if(_ep->control & USB_EPCON_SETNAK)
|
||||
{
|
||||
_ep->control |= USB_EPCON_NAKSTS;
|
||||
_ep->interrupt_status |= USB_EPINT_INEPNakEff;
|
||||
_ep->control &=~ USB_EPCON_SETNAK;
|
||||
}
|
||||
|
||||
if(_ep->control & USB_EPCON_DISABLE)
|
||||
{
|
||||
_ep->interrupt_status |= USB_EPINT_EPDisbld;
|
||||
_ep->control &=~ (USB_EPCON_DISABLE | USB_EPCON_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void synopsys_usb_update_in_ep(synopsys_usb_state *_state, uint8_t _ep)
|
||||
{
|
||||
synopsys_usb_ep_state *eps = &_state->in_eps[_ep];
|
||||
synopsys_usb_update_ep(_state, eps);
|
||||
|
||||
if(eps->control & USB_EPCON_ENABLE)
|
||||
;//printf("USB: IN transfer queued on %d.\n", _ep);
|
||||
}
|
||||
|
||||
static void synopsys_usb_update_out_ep(synopsys_usb_state *_state, uint8_t _ep)
|
||||
{
|
||||
synopsys_usb_ep_state *eps = &_state->out_eps[_ep];
|
||||
synopsys_usb_update_ep(_state, eps);
|
||||
|
||||
if(eps->control & USB_EPCON_ENABLE)
|
||||
;//printf("USB: OUT transfer queued on %d.\n", _ep);
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
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)
|
||||
// hw_error("Failed to connect to USB server (%d).\n", ret);
|
||||
|
||||
// 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->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;
|
||||
|
||||
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)
|
||||
@@ -16,6 +16,8 @@ static uint64_t ipod_touch_usb_phys_read(void *opaque, hwaddr addr, unsigned siz
|
||||
return s->usb_unknown1;
|
||||
case REG_OPHYTUNE:
|
||||
return s->usb_ophytune;
|
||||
case REG_CABLE:
|
||||
return s->is_cable_connected;
|
||||
default:
|
||||
return 0x0;
|
||||
//hw_error("%s: read invalid location 0x%08x\n", __func__, addr);
|
||||
|
||||
+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_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'))
|
||||
arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
|
||||
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
|
||||
|
||||
@@ -137,3 +137,8 @@ config USB_DWC3
|
||||
config XLNX_USB_SUBSYS
|
||||
bool
|
||||
select USB_DWC3
|
||||
|
||||
config USB_TCP
|
||||
bool
|
||||
default y
|
||||
depends on USB
|
||||
@@ -1368,6 +1368,9 @@ static void dwc2_realize(DeviceState *dev, Error **errp)
|
||||
&dev->mem_reentrancy_guard);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
s->device = DWC2_USB_DEVICE(qdev_new(TYPE_DWC2_USB_DEVICE));
|
||||
s->device->dwc2 = s;
|
||||
}
|
||||
|
||||
static void dwc2_init(Object *obj)
|
||||
@@ -1387,6 +1390,56 @@ static void dwc2_init(Object *obj)
|
||||
memory_region_add_subregion(&s->container, 0x1000, &s->fifos);
|
||||
}
|
||||
|
||||
static void dwc2_usb_device_realize(USBDevice *dev, Error **errp)
|
||||
{
|
||||
dev->speed = USB_SPEED_HIGH;
|
||||
dev->speedmask = USB_SPEED_MASK_HIGH;
|
||||
dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
|
||||
dev->auto_attach = false;
|
||||
}
|
||||
|
||||
static void dwc2_usb_device_handle_attach(USBDevice *dev)
|
||||
{
|
||||
DWC2DeviceState *udev = DWC2_USB_DEVICE(dev);
|
||||
DWC2State *s = udev->dwc2;
|
||||
|
||||
/* not in host mode */
|
||||
assert(!s->uport.dev);
|
||||
|
||||
s->gotgctl |= GOTGCTL_BSESVLD | GOTGCTL_CONID_B;
|
||||
dwc2_lower_global_irq(s, GINTSTS_CURMODE_HOST);
|
||||
dwc2_raise_global_irq(s, GINTSTS_CONIDSTSCHNG);
|
||||
}
|
||||
|
||||
static void dwc2_usb_device_handle_detach(USBDevice *dev)
|
||||
{
|
||||
DWC2DeviceState *udev = DWC2_USB_DEVICE(dev);
|
||||
DWC2State *s = udev->dwc2;
|
||||
|
||||
s->gotgctl &= ~(GOTGCTL_BSESVLD | GOTGCTL_CONID_B);
|
||||
dwc2_raise_global_irq(s, GINTSTS_CURMODE_HOST | GINTSTS_CONIDSTSCHNG);
|
||||
}
|
||||
|
||||
static void dwc2_usb_device_handle_reset(USBDevice *dev)
|
||||
{
|
||||
DWC2DeviceState *udev = DWC2_USB_DEVICE(dev);
|
||||
DWC2State *s = udev->dwc2;
|
||||
|
||||
s->dcfg &= ~DCFG_DEVADDR_MASK;
|
||||
|
||||
for (int i = 1; i < DWC2_NB_EP; i++) {
|
||||
s->diepctl(i) &= ~DXEPCTL_USBACTEP;
|
||||
s->doepctl(i) &= ~DXEPCTL_USBACTEP;
|
||||
}
|
||||
|
||||
dwc2_raise_global_irq(s, GINTSTS_USBRST);
|
||||
}
|
||||
|
||||
static void dwc2_usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_dwc2_state_packet = {
|
||||
.name = "dwc2/packet",
|
||||
.version_id = 1,
|
||||
@@ -1448,6 +1501,29 @@ static Property dwc2_usb_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void dwc2_usb_device_class_initfn_common(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
||||
|
||||
uc->realize = dwc2_usb_device_realize;
|
||||
uc->product_desc = "DWC2 USB Device";
|
||||
uc->unrealize = NULL;
|
||||
uc->cancel_packet = dwc2_usb_device_cancel_packet;
|
||||
uc->handle_attach = dwc2_usb_device_handle_attach;
|
||||
//uc->handle_detach = dwc2_usb_device_handle_detach;
|
||||
uc->handle_reset = dwc2_usb_device_handle_reset;
|
||||
uc->handle_data = NULL;
|
||||
uc->handle_control = NULL;
|
||||
//uc->handle_packet = dwc2_usb_device_handle_packet;
|
||||
uc->flush_ep_queue = NULL;
|
||||
uc->ep_stopped = NULL;
|
||||
uc->alloc_streams = NULL;
|
||||
uc->free_streams = NULL;
|
||||
uc->usb_desc = NULL;
|
||||
set_bit(DEVICE_CATEGORY_USB, dc->categories);
|
||||
}
|
||||
|
||||
static void dwc2_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@@ -1462,6 +1538,13 @@ static void dwc2_class_init(ObjectClass *klass, void *data)
|
||||
dwc2_reset_exit, &c->parent_phases);
|
||||
}
|
||||
|
||||
static const TypeInfo dwc2_usb_device_type_info = {
|
||||
.name = TYPE_DWC2_USB_DEVICE,
|
||||
.parent = TYPE_USB_DEVICE,
|
||||
.instance_size = sizeof(DWC2DeviceState),
|
||||
.class_init = dwc2_usb_device_class_initfn_common,
|
||||
};
|
||||
|
||||
static const TypeInfo dwc2_usb_type_info = {
|
||||
.name = TYPE_DWC2_USB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
@@ -1473,6 +1556,7 @@ static const TypeInfo dwc2_usb_type_info = {
|
||||
|
||||
static void dwc2_usb_register_types(void)
|
||||
{
|
||||
type_register_static(&dwc2_usb_device_type_info);
|
||||
type_register_static(&dwc2_usb_type_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
|
||||
#define DWC2_NB_CHAN 8 /* Number of host channels */
|
||||
#define DWC2_MAX_XFER_SIZE 65536 /* Max transfer size expected in HCTSIZ */
|
||||
#define DWC2_NB_EP 16 /* Number of device endpoints */
|
||||
|
||||
typedef struct DWC2Packet DWC2Packet;
|
||||
typedef struct DWC2DeviceState DWC2DeviceState;
|
||||
typedef struct DWC2State DWC2State;
|
||||
typedef struct DWC2Class DWC2Class;
|
||||
|
||||
@@ -57,12 +59,18 @@ struct DWC2Packet {
|
||||
bool needs_service;
|
||||
};
|
||||
|
||||
struct DWC2DeviceState {
|
||||
USBDevice parent_obj;
|
||||
DWC2State *dwc2;
|
||||
};
|
||||
|
||||
struct DWC2State {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
USBBus bus;
|
||||
DWC2DeviceState *device;
|
||||
qemu_irq irq;
|
||||
MemoryRegion *dma_mr;
|
||||
AddressSpace dma_as;
|
||||
@@ -141,6 +149,44 @@ struct DWC2State {
|
||||
#define hcdma(_ch) hreg1[((_ch) << 3) + 5] /* 514, 534, ... */
|
||||
#define hcdmab(_ch) hreg1[((_ch) << 3) + 7] /* 51c, 53c, ... */
|
||||
|
||||
union {
|
||||
#define DWC2_DREG_SIZE 0x38
|
||||
uint32_t dreg[DWC2_DREG_SIZE / sizeof(uint32_t)];
|
||||
struct {
|
||||
uint32_t dcfg; /* 800 */
|
||||
uint32_t dctl; /* 804 */
|
||||
uint32_t dsts; /* 808 */
|
||||
uint32_t rsvd2; /* 80c */
|
||||
uint32_t diepmsk; /* 810 */
|
||||
uint32_t doepmsk; /* 814 */
|
||||
uint32_t daint; /* 818 */
|
||||
uint32_t daintmsk; /* 81c */
|
||||
uint32_t dtknqr1; /* 820 */
|
||||
uint32_t dtknqr2; /* 824 */
|
||||
uint32_t dvbusdis; /* 828 */
|
||||
uint32_t dvbuspulse; /* 82c */
|
||||
uint32_t dtknqr3; /* 830 */
|
||||
uint32_t dtknqr4; /* 834 */
|
||||
};
|
||||
};
|
||||
|
||||
#define DWC2_DIEPREG_SIZE (0x20 * DWC2_NB_EP)
|
||||
uint32_t diepreg[DWC2_DIEPREG_SIZE / sizeof(uint32_t)];
|
||||
|
||||
#define diepctl(_ch) diepreg[((_ch) << 3) + 0] /* 900, 920, ... */
|
||||
#define diepint(_ch) diepreg[((_ch) << 3) + 2] /* 908, 928, ... */
|
||||
#define dieptsiz(_ch) diepreg[((_ch) << 3) + 4] /* 910, 930, ... */
|
||||
#define diepdma(_ch) diepreg[((_ch) << 3) + 5] /* 914, 934, ... */
|
||||
#define dtxfsts(_ch) diepreg[((_ch) << 3) + 6] /* 918, 938, ... */
|
||||
|
||||
#define DWC2_DOEPREG_SIZE (0x20 * DWC2_NB_EP)
|
||||
uint32_t doepreg[DWC2_DIEPREG_SIZE / sizeof(uint32_t)];
|
||||
|
||||
#define doepctl(_ch) doepreg[((_ch) << 3) + 0] /* b00, b20, ... */
|
||||
#define doepint(_ch) doepreg[((_ch) << 3) + 2] /* b08, b28, ... */
|
||||
#define doeptsiz(_ch) doepreg[((_ch) << 3) + 4] /* b10, b30, ... */
|
||||
#define doepdma(_ch) doepreg[((_ch) << 3) + 5] /* b14, b34, ... */
|
||||
|
||||
union {
|
||||
#define DWC2_PCGREG_SIZE 0x08
|
||||
uint32_t pcgreg[DWC2_PCGREG_SIZE / sizeof(uint32_t)];
|
||||
@@ -180,6 +226,9 @@ struct DWC2Class {
|
||||
/*< public >*/
|
||||
};
|
||||
|
||||
#define TYPE_DWC2_USB_DEVICE "dwc2-usb-device"
|
||||
OBJECT_DECLARE_TYPE(DWC2DeviceState, USBDeviceClass, DWC2_USB_DEVICE)
|
||||
|
||||
#define TYPE_DWC2_USB "dwc2-usb"
|
||||
OBJECT_DECLARE_TYPE(DWC2State, DWC2Class, DWC2_USB)
|
||||
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/lockable.h"
|
||||
#include "hw/usb.h"
|
||||
#include "tcp-usb.h"
|
||||
#include "hw/usb/hcd-tcp.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "io/channel.h"
|
||||
#include "io/channel-util.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/iothread.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "migration/blocker.h"
|
||||
|
||||
//#define DEBUG_HCD_TCP
|
||||
|
||||
#ifdef DEBUG_HCD_TCP
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { fprintf(stderr, "hcd-tcp: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do {} while(0)
|
||||
#endif
|
||||
|
||||
static void usb_tcp_host_closed(USBTCPHostState *s)
|
||||
{
|
||||
DPRINTF("%s\n", __func__);
|
||||
if (s->ioc) {
|
||||
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
||||
qio_channel_close(s->ioc, NULL);
|
||||
object_unref(OBJECT(s->ioc));
|
||||
s->ioc = NULL;
|
||||
}
|
||||
s->closed = true;
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
static ssize_t tcp_usb_read(QIOChannel *ioc, void *buf, size_t len)
|
||||
{
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = len };
|
||||
bool iolock = qemu_mutex_iothread_locked();
|
||||
bool iothread = qemu_in_iothread();
|
||||
ssize_t ret = -1;
|
||||
Error *err = NULL;
|
||||
|
||||
/*
|
||||
* Dont use in IOThread out of co-routine context as
|
||||
* it will block IOThread.
|
||||
*/
|
||||
assert(qemu_in_coroutine() || !iothread);
|
||||
|
||||
if (iolock && !iothread && !qemu_in_coroutine()) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, NULL, 0, &err);
|
||||
|
||||
if (iolock && !iothread && !qemu_in_coroutine()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
return (ret <= 0) ? ret : iov.iov_len;
|
||||
}
|
||||
|
||||
static bool tcp_usb_write(QIOChannel *ioc, void *buf, ssize_t len)
|
||||
{
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = len };
|
||||
bool iolock = qemu_mutex_iothread_locked();
|
||||
bool iothread = qemu_in_iothread();
|
||||
bool ret = false;
|
||||
Error *err = NULL;
|
||||
|
||||
/*
|
||||
* Dont use in IOThread out of co-routine context as
|
||||
* it will block IOThread.
|
||||
*/
|
||||
assert(qemu_in_coroutine() || !iothread);
|
||||
|
||||
if (iolock && !iothread && !qemu_in_coroutine()) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
if (!qio_channel_writev_full_all(ioc, &iov, 1, NULL, 0, 0, &err)) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (iolock && !iothread && !qemu_in_coroutine()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static USBPort *usb_tcp_host_find_active_port(USBTCPHostState *s)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS(s->uports) - 1; i++) {
|
||||
if (s->uports[i].dev->attached) {
|
||||
return &s->uports[i];
|
||||
}
|
||||
}
|
||||
return &s->uports[0];
|
||||
}
|
||||
|
||||
static void coroutine_fn usb_tcp_host_respond_packet_co(void *opaque)
|
||||
{
|
||||
USBTCPPacket *pkt = (USBTCPPacket *)opaque;
|
||||
USBTCPHostState *s = USB_TCP_HOST(pkt->s);
|
||||
USBPacket *p = &pkt->p;
|
||||
tcp_usb_header_t hdr = { 0 };
|
||||
tcp_usb_response_header resp = { 0 };
|
||||
g_autofree void *buffer = NULL;
|
||||
USBPort *uport = usb_tcp_host_find_active_port(s);
|
||||
|
||||
WITH_QEMU_LOCK_GUARD(&s->write_mutex) {
|
||||
if (!s->closed) {
|
||||
hdr.type = TCP_USB_RESPONSE;
|
||||
resp.addr = uport->dev->addr;
|
||||
resp.pid = p->pid;
|
||||
resp.ep = p->ep->nr;
|
||||
resp.id = p->id;
|
||||
resp.status = p->status;
|
||||
resp.length = p->iov.size;
|
||||
|
||||
if (resp.length > p->actual_length) {
|
||||
resp.length = p->actual_length;
|
||||
}
|
||||
|
||||
if (p->pid == USB_TOKEN_IN && p->status != USB_RET_ASYNC) {
|
||||
buffer = g_malloc(resp.length);
|
||||
iov_to_buf(p->iov.iov, p->iov.niov, 0, buffer, resp.length);
|
||||
}
|
||||
|
||||
if (!tcp_usb_write(s->ioc, &hdr, sizeof(hdr))) {
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tcp_usb_write(s->ioc, &resp, sizeof(resp))) {
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
if (!tcp_usb_write(s->ioc, buffer, resp.length)) {
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!usb_packet_is_inflight(p)) {
|
||||
if (pkt->buffer) {
|
||||
g_free(pkt->buffer);
|
||||
}
|
||||
usb_packet_cleanup(p);
|
||||
g_free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_tcp_host_respond_packet(USBTCPHostState *s, USBTCPPacket *pkt)
|
||||
{
|
||||
Coroutine *co = NULL;
|
||||
co = qemu_coroutine_create(usb_tcp_host_respond_packet_co, pkt);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
static void coroutine_fn usb_tcp_host_msg_loop_co(void *opaque)
|
||||
{
|
||||
USBTCPHostState *s = USB_TCP_HOST(opaque);
|
||||
USBPort *uport = usb_tcp_host_find_active_port(s);
|
||||
QIOChannel *ioc = s->ioc;
|
||||
|
||||
for(;;) {
|
||||
tcp_usb_header_t hdr = { 0 };
|
||||
|
||||
if (unlikely((tcp_usb_read(ioc, &hdr, sizeof(hdr)) != sizeof(hdr)))) {
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (hdr.type) {
|
||||
case TCP_USB_REQUEST: {
|
||||
/* fprintf(stderr, "%s: TCP_USB_REQUEST\n", __func__); */
|
||||
tcp_usb_request_header pkt_hdr = {0};
|
||||
g_autofree void *buffer = NULL;
|
||||
g_autofree USBTCPPacket *pkt = (USBTCPPacket *) g_malloc0(sizeof(USBTCPPacket));
|
||||
USBEndpoint *ep = NULL;
|
||||
|
||||
if (unlikely(tcp_usb_read(ioc, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr))) {
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
DPRINTF("%s: TCP_USB_REQUEST pid: 0x%x ep: %d id: 0x%lx\n", __func__, pkt_hdr.pid, pkt_hdr.ep, pkt_hdr.id);
|
||||
#endif
|
||||
ep = usb_ep_get(uport->dev, pkt_hdr.pid, pkt_hdr.ep);
|
||||
if (ep == NULL) {
|
||||
DPRINTF("%s: TCP_USB_REQUEST unknown EP\n", __func__);
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
|
||||
usb_packet_init(&pkt->p);
|
||||
usb_packet_setup(&pkt->p, pkt_hdr.pid, ep, pkt_hdr.stream, pkt_hdr.id, pkt_hdr.short_not_ok, pkt_hdr.int_req);
|
||||
|
||||
if (pkt_hdr.length > 0) {
|
||||
buffer = g_malloc0(pkt_hdr.length);
|
||||
|
||||
if (pkt_hdr.pid != USB_TOKEN_IN) {
|
||||
if (unlikely(tcp_usb_read(s->ioc, buffer, pkt_hdr.length) != pkt_hdr.length)) {
|
||||
usb_tcp_host_closed(s);
|
||||
usb_packet_cleanup(&pkt->p);
|
||||
return;
|
||||
}
|
||||
/* qemu_hexdump(stderr, __func__, buffer, pkt_hdr.length); */
|
||||
}
|
||||
|
||||
usb_packet_addbuf(&pkt->p, buffer, pkt_hdr.length);
|
||||
pkt->buffer = buffer;
|
||||
g_steal_pointer(&buffer);
|
||||
}
|
||||
|
||||
if (pkt_hdr.addr != uport->dev->addr) {
|
||||
/*
|
||||
* fprintf(stderr,
|
||||
* "%s: USB_RET_NODEV: pkt_hdr.addr != uport->dev->addr: %d != %d\n",
|
||||
* __func__, pkt_hdr.addr, uport->dev->addr);
|
||||
*/
|
||||
/* Can't enforce this check because dwc2 address transition time is slow */
|
||||
}
|
||||
pkt->dev = ep->dev;
|
||||
pkt->s = s;
|
||||
pkt->addr = pkt_hdr.addr;
|
||||
assert(qemu_mutex_iothread_locked());
|
||||
|
||||
usb_handle_packet(pkt->dev, &pkt->p);
|
||||
usb_tcp_host_respond_packet(s, pkt);
|
||||
g_steal_pointer(&pkt);
|
||||
break;
|
||||
}
|
||||
case TCP_USB_RESPONSE:
|
||||
fprintf(stderr, "%s: unexpected TCP_USB_RESPONSE\n", __func__);
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
case TCP_USB_CANCEL: {
|
||||
/* DPRINTF("%s: TCP_USB_CANCEL\n", __func__); */
|
||||
tcp_usb_cancel_header pkt_hdr = {0};
|
||||
USBTCPPacket *pkt = NULL;
|
||||
USBPacket *p = NULL;
|
||||
|
||||
if (unlikely(tcp_usb_read(ioc, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr))) {
|
||||
usb_tcp_host_closed(s);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 1
|
||||
DPRINTF("%s: TCP_USB_CANCEL pid: 0x%x ep: %d\n", __func__, pkt_hdr.pid, pkt_hdr.ep);
|
||||
#endif
|
||||
|
||||
if (pkt_hdr.addr != uport->dev->addr) {
|
||||
/*
|
||||
* fprintf(stderr,
|
||||
* "%s: USB_RET_NODEV: pkt_hdr.addr != uport->dev->addr: %d != %d\n",
|
||||
* __func__, pkt_hdr.addr, uport->dev->addr);
|
||||
*/
|
||||
/* Can't enforce this check because dwc2 address transition time is slow */
|
||||
}
|
||||
assert(qemu_mutex_iothread_locked());
|
||||
p = usb_ep_find_packet_by_id(uport->dev, pkt_hdr.pid,
|
||||
pkt_hdr.ep, pkt_hdr.id);
|
||||
if (p) {
|
||||
pkt = container_of(p, USBTCPPacket, p);
|
||||
usb_cancel_packet(&pkt->p);
|
||||
DPRINTF("%s: TCP_USB_CANCEL: packet"
|
||||
" pid: 0x%x ep: %d id: 0x%lx len: 0x%x\n",
|
||||
__func__, pkt_hdr.pid, pkt_hdr.ep, pkt_hdr.id, p->actual_length);
|
||||
usb_tcp_host_respond_packet(s, pkt);
|
||||
} else {
|
||||
warn_report("%s: TCP_USB_CANCEL: packet"
|
||||
" pid: 0x%x ep: %d id: 0x%lx not found",
|
||||
__func__, pkt_hdr.pid, pkt_hdr.ep, pkt_hdr.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TCP_USB_RESET:
|
||||
/* fprintf(stderr, "%s: TCP_USB_RESET\n", __func__); */
|
||||
DPRINTF("%s: TCP_USB_RESET\n", __func__);
|
||||
assert(qemu_mutex_iothread_locked());
|
||||
usb_device_reset(uport->dev);
|
||||
break;;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void usb_tcp_host_attach(USBPort *uport)
|
||||
{
|
||||
struct sockaddr_un server_addr;
|
||||
USBTCPHostState *s = USB_TCP_HOST(uport->opaque);
|
||||
int sock = -1;
|
||||
Coroutine *co = NULL;
|
||||
QIOChannel *ioc = NULL;
|
||||
int ret;
|
||||
Error *err = NULL;
|
||||
|
||||
if (uport->index >= G_N_ELEMENTS(s->uports) - 1) {
|
||||
error_report("%s: attached to unused port\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_tcp_host_find_active_port(s) != uport) {
|
||||
error_report("%s: Attaching to 2 proxy ports at the same time. "
|
||||
"This port might not be able to receive packets.\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uport->dev || !uport->dev->attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (socket < 0) {
|
||||
error_report("%s: cannot open socket", __func__);
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sun_family = AF_UNIX;
|
||||
strncpy(server_addr.sun_path, socket_path, sizeof(server_addr.sun_path));
|
||||
server_addr.sun_path[sizeof(server_addr.sun_path) - 1] = '\0';
|
||||
|
||||
ret = connect(sock, (const struct sockaddr *) &server_addr, sizeof(server_addr));
|
||||
if (ret < 0) {
|
||||
error_report("%s: failed to connect to server: %d\n", __func__, ret);
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
ioc = qio_channel_new_fd(sock, &err);
|
||||
if (!ioc) {
|
||||
error_report_err(err);
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
qio_channel_set_blocking(ioc, false, NULL);
|
||||
s->closed = 0;
|
||||
s->ioc = ioc;
|
||||
|
||||
migrate_add_blocker(s->migration_blocker, NULL);
|
||||
co = qemu_coroutine_create(usb_tcp_host_msg_loop_co, s);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
static void usb_tcp_host_detach(USBPort *uport)
|
||||
{
|
||||
USBTCPHostState *s = USB_TCP_HOST(uport->opaque);
|
||||
|
||||
usb_tcp_host_closed(s);
|
||||
}
|
||||
|
||||
static void usb_tcp_host_async_packet_complete(USBPort *port, USBPacket *p)
|
||||
{
|
||||
USBTCPHostState *s = USB_TCP_HOST(port->opaque);
|
||||
usb_tcp_host_respond_packet(s, container_of(p, USBTCPPacket, p));
|
||||
}
|
||||
|
||||
static USBBusOps usb_tcp_bus_ops = { };
|
||||
|
||||
static USBPortOps usb_tcp_host_port_ops = {
|
||||
.attach = usb_tcp_host_attach,
|
||||
.detach = usb_tcp_host_detach,
|
||||
.child_detach = NULL,
|
||||
.wakeup = NULL,
|
||||
.complete = usb_tcp_host_async_packet_complete,
|
||||
};
|
||||
|
||||
static void usb_tcp_host_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
USBTCPHostState *s = USB_TCP_HOST(dev);
|
||||
|
||||
usb_bus_new(&s->bus, sizeof(s->bus), &usb_tcp_bus_ops, dev);
|
||||
for (int i = 0; i < G_N_ELEMENTS(s->uports); i++) {
|
||||
usb_register_port(&s->bus, &s->uports[i], s, i, &usb_tcp_host_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
|
||||
USB_SPEED_MASK_HIGH);
|
||||
}
|
||||
|
||||
s->closed = 1;
|
||||
qemu_co_mutex_init(&s->write_mutex);
|
||||
}
|
||||
|
||||
static void usb_tcp_host_unrealize(DeviceState *dev)
|
||||
{
|
||||
USBTCPHostState *s = USB_TCP_HOST(dev);
|
||||
|
||||
if (s->ioc) {
|
||||
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
||||
qio_channel_close(s->ioc, NULL);
|
||||
s->ioc = NULL;
|
||||
}
|
||||
|
||||
s->closed = 1;
|
||||
s->stopped = 1;
|
||||
}
|
||||
|
||||
static void usb_tcp_host_init(Object *obj)
|
||||
{
|
||||
USBTCPHostState *s = USB_TCP_HOST(obj);
|
||||
s->closed = 1;
|
||||
error_setg(&s->migration_blocker, "%s does not support migration "
|
||||
"while connected", TYPE_USB_TCP_HOST);
|
||||
}
|
||||
|
||||
static Property usb_tcp_host_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void usb_tcp_host_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = usb_tcp_host_realize;
|
||||
dc->unrealize = usb_tcp_host_unrealize;
|
||||
dc->desc = "QEMU USB Passthrough Host Controller";
|
||||
device_class_set_props(dc, usb_tcp_host_properties);
|
||||
set_bit(DEVICE_CATEGORY_USB, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo usb_tcp_host_type_info = {
|
||||
.name = TYPE_USB_TCP_HOST,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(USBTCPHostState),
|
||||
.class_init = usb_tcp_host_class_init,
|
||||
.instance_init = usb_tcp_host_init,
|
||||
};
|
||||
|
||||
static void usb_tcp_host_register_types(void)
|
||||
{
|
||||
type_register_static(&usb_tcp_host_type_info);
|
||||
}
|
||||
|
||||
type_init(usb_tcp_host_register_types)
|
||||
@@ -11,6 +11,8 @@ system_ss.add(when: 'CONFIG_USB', if_true: files(
|
||||
'pcap.c',
|
||||
))
|
||||
|
||||
system_ss.add(when: 'CONFIG_USB_TCP', if_true: files('hcd-tcp.c'))
|
||||
|
||||
# usb host adapters
|
||||
system_ss.add(when: 'CONFIG_USB_UHCI', if_true: files('hcd-uhci.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_OHCI', if_true: files('hcd-ohci.c'))
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef HW_USB_TCP_USB_H
|
||||
#define HW_USB_TCP_USB_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/usb.h"
|
||||
|
||||
static const char *socket_path = "/tmp/usbqemu";
|
||||
|
||||
enum {
|
||||
TCP_USB_REQUEST = (1 << 0),
|
||||
TCP_USB_RESPONSE = (1 << 1),
|
||||
TCP_USB_RESET = (1 << 2),
|
||||
TCP_USB_CANCEL = (1 << 3)
|
||||
};
|
||||
|
||||
typedef struct QEMU_PACKED tcp_usb_header {
|
||||
uint8_t type;
|
||||
} tcp_usb_header_t;
|
||||
|
||||
typedef struct QEMU_PACKED tcp_usb_request_header {
|
||||
uint8_t addr;
|
||||
int pid;
|
||||
uint8_t ep;
|
||||
unsigned int stream;
|
||||
uint64_t id;
|
||||
uint8_t short_not_ok;
|
||||
uint8_t int_req;
|
||||
uint16_t length;
|
||||
} tcp_usb_request_header;
|
||||
|
||||
typedef struct QEMU_PACKED tcp_usb_response_header {
|
||||
uint8_t addr;
|
||||
int pid;
|
||||
uint8_t ep;
|
||||
uint64_t id;
|
||||
uint32_t status;
|
||||
uint16_t length;
|
||||
} tcp_usb_response_header;
|
||||
|
||||
typedef struct QEMU_PACKED tcp_usb_cancel_header {
|
||||
uint8_t addr;
|
||||
int pid;
|
||||
uint8_t ep;
|
||||
uint64_t id;
|
||||
|
||||
} tcp_usb_cancel_header;
|
||||
|
||||
#endif //HW_USB_TCP_USB_H
|
||||
@@ -9,12 +9,13 @@
|
||||
#include "cpu.h"
|
||||
#include "hw/dma/pl080.h"
|
||||
#include "hw/i2c/ipod_touch_i2c.h"
|
||||
#include "hw/usb/hcd-dwc2.h"
|
||||
#include "hw/usb/hcd-tcp.h"
|
||||
#include "hw/arm/ipod_touch_timer.h"
|
||||
#include "hw/arm/ipod_touch_clock.h"
|
||||
#include "hw/arm/ipod_touch_chipid.h"
|
||||
#include "hw/arm/ipod_touch_gpio.h"
|
||||
#include "hw/arm/ipod_touch_sysic.h"
|
||||
#include "hw/arm/ipod_touch_usb_otg.h"
|
||||
#include "hw/arm/ipod_touch_usb_phys.h"
|
||||
#include "hw/arm/ipod_touch_spi.h"
|
||||
#include "hw/arm/ipod_touch_sha1.h"
|
||||
@@ -154,7 +155,8 @@ typedef struct {
|
||||
IPodTouchChipIDState *chipid_state;
|
||||
IPodTouchGPIOState *gpio_state;
|
||||
IPodTouchSYSICState *sysic;
|
||||
synopsys_usb_state *usb_otg;
|
||||
MemoryRegion usb_dma_container_mr;
|
||||
DWC2State *dwc2;
|
||||
IPodTouchUSBPhysState *usb_phys_state;
|
||||
IPodTouchSHA1State *sha1_state;
|
||||
IPodTouchAESState *aes_state;
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
#define TYPE_IPOD_TOUCH_GPIO "ipodtouch.gpio"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchGPIOState, IPOD_TOUCH_GPIO)
|
||||
|
||||
#define GPIO_BUTTON_POWER 0xC02
|
||||
#define GPIO_BUTTON_HOME 0xC01
|
||||
#define GPIO_BUTTON_VOLUP 0x902
|
||||
#define GPIO_BUTTON_VOLDOWN 0xC00
|
||||
#define GPIO_FORCE_DFU 0xB03
|
||||
#define GPIO_BUTTON_VOLDOWN 0xC00
|
||||
#define GPIO_BUTTON_HOME 0xC01
|
||||
#define GPIO_BUTTON_POWER 0xC02
|
||||
#define GPIO_DFU_STATUS 0xC03
|
||||
|
||||
#define GPIO_BUTTON_POWER_IRQ 0x7A
|
||||
#define GPIO_BUTTON_HOME_IRQ 0x79
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
#ifndef HW_ARM_IPOD_TOUCH_USB_OTG_H
|
||||
#define HW_ARM_IPOD_TOUCH_USB_OTG_H
|
||||
|
||||
#include "hw/irq.h"
|
||||
#include "hw/usb.h"
|
||||
|
||||
#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
|
||||
@@ -8,11 +8,12 @@
|
||||
#define TYPE_IPOD_TOUCH_USB_PHYS "ipodtouch.usbphys"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchUSBPhysState, IPOD_TOUCH_USB_PHYS)
|
||||
|
||||
#define REG_OPHYPWR 0x0
|
||||
#define REG_OPHYCLK 0x4
|
||||
#define REG_ORSTCON 0x8
|
||||
#define REG_OPHYPWR 0x0
|
||||
#define REG_OPHYCLK 0x4
|
||||
#define REG_ORSTCON 0x8
|
||||
#define REG_UNKNOWN1 0x1C
|
||||
#define REG_OPHYTUNE 0x20
|
||||
#define REG_CABLE 0x28
|
||||
|
||||
typedef struct IPodTouchUSBPhysState {
|
||||
SysBusDevice busdev;
|
||||
@@ -23,6 +24,7 @@ typedef struct IPodTouchUSBPhysState {
|
||||
uint32_t usb_orstcon;
|
||||
uint32_t usb_unknown1;
|
||||
uint32_t usb_ophytune;
|
||||
bool is_cable_connected;
|
||||
} IPodTouchUSBPhysState;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef HW_USB_HCD_TCP_H
|
||||
#define HW_USB_HCD_TCP_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/usb.h"
|
||||
#include "io/channel.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define TYPE_USB_TCP_HOST "usb-tcp-host"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(USBTCPHostState, USB_TCP_HOST)
|
||||
|
||||
typedef struct USBTCPPacket {
|
||||
USBPacket p;
|
||||
void *buffer;
|
||||
USBDevice *dev;
|
||||
USBTCPHostState *s;
|
||||
uint8_t addr;
|
||||
} USBTCPPacket;
|
||||
|
||||
struct USBTCPHostState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
USBBus bus;
|
||||
USBPort uports[3];
|
||||
QIOChannel *ioc;
|
||||
CoMutex write_mutex;
|
||||
Error *migration_blocker;
|
||||
bool closed;
|
||||
bool stopped;
|
||||
};
|
||||
|
||||
#endif /* HW_USB_HCD_TCP_H */
|
||||
Reference in new issue
Block a user