Implemented S8000 USB stack

This commit is contained in:
Martijn de Vos committed 2024-01-20 19:24:37 +01:00
1 parent a0698a741e
commit 410b1ae746
11 files changed
+1699 -52

No files matched your search

+10 -9
View File
@@ -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;
@@ -405,14 +398,22 @@ static void ipod_touch_machine_init(MachineState *machine)
// init USB OTG
dev = qdev_new("dwc2-usb");
DWC2State *dwc2 = DWC2_USB(dev);
nms->usb_otg = dwc2;
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->usb_otg), "dma-mr", OBJECT(&nms->usb_dma_container_mr));
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");
PL080State *pl080_1 = PL080(dev);
+5
View File
@@ -137,3 +137,8 @@ config USB_DWC3
config XLNX_USB_SUBSYS
bool
select USB_DWC3
config USB_TCP
bool
default y
depends on USB
+1053 -36
View File
File diff suppressed because it is too large. Load diff
+65 -5
View File
@@ -28,10 +28,12 @@
#define DWC2_MMIO_SIZE 0x11000
#define DWC2_NB_CHAN 8 /* Number of host channels */
#define DWC2_MAX_XFER_SIZE 65536 /* Max transfer size expected in HCTSIZ */
#define DWC2_NB_CHAN 16 /* Number of host channels */
#define DWC2_MAX_XFER_SIZE 0x1000 /* 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,19 @@ struct DWC2Packet {
bool needs_service;
};
struct DWC2DeviceState {
USBDevice parent_obj;
DWC2State *dwc2;
};
struct DWC2State {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
USBBus bus;
/* This device in device mode */
DWC2DeviceState *device;
qemu_irq irq;
MemoryRegion *dma_mr;
AddressSpace dma_as;
@@ -112,6 +121,13 @@ struct DWC2State {
uint32_t hptxfsiz; /* 100 */
};
};
union {
#define DWC2_DFSZREG_SIZE 0x3c
uint32_t dfszreg[DWC2_DFSZREG_SIZE / sizeof(uint32_t)];
struct {
uint32_t dptxfsiz[DWC2_NB_EP]; /* 104 */
};
};
union {
#define DWC2_HREG0_SIZE 0x44
@@ -141,6 +157,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)];
@@ -152,13 +206,13 @@ struct DWC2State {
/* TODO - implement FIFO registers for slave mode */
#define DWC2_HFIFO_SIZE (0x1000 * DWC2_NB_CHAN)
/*
* Internal state
*/
QEMUTimer *eof_timer;
QEMUTimer *frame_timer;
QEMUBH *async_bh;
QEMUBH *device_async_bh;
int64_t sof_time;
int64_t usb_frame_time;
int64_t usb_bit_time;
@@ -169,7 +223,10 @@ struct DWC2State {
bool working;
USBPort uport;
DWC2Packet packet[DWC2_NB_CHAN]; /* one packet per chan */
uint8_t usb_buf[DWC2_NB_CHAN][DWC2_MAX_XFER_SIZE]; /* one buffer per chan */
union {
uint8_t usb_buf[DWC2_NB_CHAN][DWC2_MAX_XFER_SIZE]; /* one buffer per chan */
uint8_t fifos_buf[DWC2_HFIFO_SIZE];
};
};
struct DWC2Class {
@@ -180,7 +237,10 @@ 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)
#endif
#endif
+458
View File
@@ -0,0 +1,458 @@
#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;
printf("??000\n");
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)
+2
View File
@@ -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'))
+48
View File
@@ -0,0 +1,48 @@
#ifndef HW_USB_TCP_USB_H
#define HW_USB_TCP_USB_H
#include "qemu/osdep.h"
#include "hw/usb.h"
static const char *socket_path = "/tmp/usbqemu";
enum {
TCP_USB_REQUEST = (1 << 0),
TCP_USB_RESPONSE = (1 << 1),
TCP_USB_RESET = (1 << 2),
TCP_USB_CANCEL = (1 << 3)
};
typedef struct QEMU_PACKED tcp_usb_header {
uint8_t type;
} tcp_usb_header_t;
typedef struct QEMU_PACKED tcp_usb_request_header {
uint8_t addr;
int pid;
uint8_t ep;
unsigned int stream;
uint64_t id;
uint8_t short_not_ok;
uint8_t int_req;
uint16_t length;
} tcp_usb_request_header;
typedef struct QEMU_PACKED tcp_usb_response_header {
uint8_t addr;
int pid;
uint8_t ep;
uint64_t id;
uint32_t status;
uint16_t length;
} tcp_usb_response_header;
typedef struct QEMU_PACKED tcp_usb_cancel_header {
uint8_t addr;
int pid;
uint8_t ep;
uint64_t id;
} tcp_usb_cancel_header;
#endif //HW_USB_TCP_USB_H
+2 -1
View File
@@ -10,6 +10,7 @@
#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"
@@ -155,7 +156,7 @@ typedef struct {
IPodTouchGPIOState *gpio_state;
IPodTouchSYSICState *sysic;
MemoryRegion usb_dma_container_mr;
DWC2State *usb_otg;
DWC2State *dwc2;
IPodTouchUSBPhysState *usb_phys_state;
IPodTouchSHA1State *sha1_state;
IPodTouchAESState *aes_state;
+9
View File
@@ -175,6 +175,15 @@
#define USB_INTERFACE_INVALID 255
/* binary representation */
struct usb_control_packet {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} QEMU_PACKED;
typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
+12 -1
View File
@@ -558,9 +558,11 @@
#define DXEPCTL_TXFNUM_SHIFT 22
#define DXEPCTL_TXFNUM_LIMIT 0xf
#define DXEPCTL_TXFNUM(_x) ((_x) << 22)
#define DXEPCTL_TXFNUM_GET(_x) (((_x) >> 22) & 0xf)
#define DXEPCTL_STALL BIT(21)
#define DXEPCTL_SNP BIT(20)
#define DXEPCTL_EPTYPE_MASK (0x3 << 18)
#define DXEPCTL_EPTYPE_SHIFT (18)
#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18)
#define DXEPCTL_EPTYPE_ISO (0x1 << 18)
#define DXEPCTL_EPTYPE_BULK (0x2 << 18)
@@ -578,6 +580,7 @@
#define DXEPCTL_MPS_SHIFT 0
#define DXEPCTL_MPS_LIMIT 0x7ff
#define DXEPCTL_MPS(_x) ((_x) << 0)
#define DXEPCTL_MPS_GET(_x) (((_x) >> 0) & 0x7ff)
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
@@ -607,19 +610,26 @@
#define DIEPTSIZ0_PKTCNT_SHIFT 19
#define DIEPTSIZ0_PKTCNT_LIMIT 0x3
#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19)
#define DIEPTSIZ0_PKTCNT_GET(_v) (((_v) >> 19) & 0x3)
#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
#define DIEPTSIZ0_XFERSIZE_SHIFT 0
#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f
#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0)
#define DIEPTSIZ0_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7f)
#define DOEPTSIZ0 HSOTG_REG(0xB10)
#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29)
#define DOEPTSIZ0_SUPCNT_SHIFT 29
#define DOEPTSIZ0_SUPCNT_LIMIT 0x3
#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29)
#define DOEPTSIZ0_PKTCNT BIT(19)
#define DOEPTSIZ0_PKTCNT(_x) (((_x) & 0x1) << 19)
#define DOEPTSIZ0_PKTCNT_MASK (0x1 << 19)
#define DOEPTSIZ0_PKTCNT_SHIFT 19
#define DOEPTSIZ0_PKTCNT_GET(_v) (((_v) >> 19) & 0x1)
#define DOEPTSIZ0_XFERSIZE(_v) (((_v) & 0x7f) << 0)
#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
#define DOEPTSIZ0_XFERSIZE_SHIFT 0
#define DOEPTSIZ0_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7f)
#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20))
#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20))
@@ -866,6 +876,7 @@ struct dwc2_dma_desc {
#define DEV_DMA_BUFF_STS_DMABUSY 1
#define DEV_DMA_BUFF_STS_DMADONE 2
#define DEV_DMA_BUFF_STS_HBUSY 3
#define DEV_DMA_BUFF_STS_GET(_x) (((_x) >> 30) & 0x3)
#define DEV_DMA_STS_MASK (0x3 << 28)
#define DEV_DMA_STS_SHIFT 28
#define DEV_DMA_STS_SUCC 0
+35
View File
@@ -0,0 +1,35 @@
#ifndef HW_USB_HCD_TCP_H
#define HW_USB_HCD_TCP_H
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "qom/object.h"
#include "hw/usb.h"
#include "io/channel.h"
#include "qemu/coroutine.h"
#include "qapi/error.h"
#define TYPE_USB_TCP_HOST "usb-tcp-host"
OBJECT_DECLARE_SIMPLE_TYPE(USBTCPHostState, USB_TCP_HOST)
typedef struct USBTCPPacket {
USBPacket p;
void *buffer;
USBDevice *dev;
USBTCPHostState *s;
uint8_t addr;
} USBTCPPacket;
struct USBTCPHostState {
SysBusDevice parent_obj;
USBBus bus;
USBPort uports[3];
QIOChannel *ioc;
CoMutex write_mutex;
Error *migration_blocker;
bool closed;
bool stopped;
};
#endif /* HW_USB_HCD_TCP_H */