Started rewrite of USB packet handling required for full async packet support.
Step #1: Allocate buffer for data transfers dynamicly with the required size (done in UHCI, OHCI and EHCI).
This commit is contained in:
parent
de6ee1d7eb
commit
0192554c25
@ -65,22 +65,16 @@ bx_uhci_core_c::bx_uhci_core_c()
|
||||
{
|
||||
put("uhci_core", "UHCIC");
|
||||
memset((void*)&hub, 0, sizeof(bx_uhci_core_t));
|
||||
device_buffer = NULL;
|
||||
hub.timer_index = BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
|
||||
bx_uhci_core_c::~bx_uhci_core_c()
|
||||
{
|
||||
if (device_buffer != NULL)
|
||||
delete [] device_buffer;
|
||||
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
void bx_uhci_core_c::init_uhci(Bit8u devfunc, Bit16u devid, Bit8u headt, Bit8u intp)
|
||||
{
|
||||
device_buffer = new Bit8u[65536];
|
||||
|
||||
// Call our timer routine every 1mS (1,000uS)
|
||||
// Continuous and active
|
||||
hub.timer_index =
|
||||
@ -801,18 +795,17 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
BX_ERROR(("too many pending packets"));
|
||||
return 0;
|
||||
}
|
||||
usb_packet_init(&usb_packet, maxlen);
|
||||
usb_packet.pid = pid;
|
||||
usb_packet.devaddr = addr;
|
||||
usb_packet.devep = endpt;
|
||||
usb_packet.data = device_buffer;
|
||||
usb_packet.len = maxlen;
|
||||
usb_packet.complete_cb = uhci_async_complete_packet;
|
||||
usb_packet.complete_dev = this;
|
||||
switch (pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
case USB_TOKEN_SETUP:
|
||||
if (maxlen > 0) {
|
||||
DEV_MEM_READ_PHYSICAL_DMA(td->dword3, maxlen, device_buffer);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(td->dword3, maxlen, usb_packet.data);
|
||||
}
|
||||
ret = broadcast_packet(&usb_packet);
|
||||
len = maxlen;
|
||||
@ -839,7 +832,7 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
ret = USB_RET_BABBLE;
|
||||
}
|
||||
if (len > 0) {
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(td->dword3, len, device_buffer);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(td->dword3, len, usb_packet.data);
|
||||
}
|
||||
} else {
|
||||
len = 0;
|
||||
@ -850,6 +843,7 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
} else {
|
||||
set_status(td, 1, 0, 0, 0, 0, 0, 0x007); // stalled
|
||||
}
|
||||
usb_packet_cleanup(&usb_packet);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,6 @@ protected:
|
||||
bx_uhci_core_t hub;
|
||||
Bit8u global_reset;
|
||||
bx_bool busy;
|
||||
Bit8u *device_buffer;
|
||||
|
||||
USBPacket usb_packet;
|
||||
|
||||
|
@ -214,6 +214,26 @@ protected:
|
||||
int set_usb_string(Bit8u *buf, const char *str);
|
||||
};
|
||||
|
||||
static BX_CPP_INLINE void usb_packet_init(USBPacket *p, int size)
|
||||
{
|
||||
memset(p, 0, sizeof(USBPacket));
|
||||
if (size > 0) {
|
||||
p->data = new Bit8u[size];
|
||||
if (!p->data) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
p->len = size;
|
||||
}
|
||||
|
||||
static BX_CPP_INLINE void usb_packet_cleanup(USBPacket *p)
|
||||
{
|
||||
if (p->data) {
|
||||
delete [] p->data;
|
||||
p->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BX_CPP_INLINE void usb_defer_packet(USBPacket *p, usb_device_c *dev)
|
||||
{
|
||||
p->dev = dev;
|
||||
|
@ -184,7 +184,6 @@ bx_usb_ehci_c::bx_usb_ehci_c()
|
||||
{
|
||||
put("usb_ehci", "EHCI");
|
||||
memset((void*)&hub, 0, sizeof(bx_usb_ehci_t));
|
||||
device_buffer = NULL;
|
||||
rt_conf_id = -1;
|
||||
hub.frame_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
}
|
||||
@ -195,8 +194,6 @@ bx_usb_ehci_c::~bx_usb_ehci_c()
|
||||
int i;
|
||||
|
||||
SIM->unregister_runtime_config_handler(rt_conf_id);
|
||||
if (BX_EHCI_THIS device_buffer != NULL)
|
||||
delete [] BX_EHCI_THIS device_buffer;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (BX_EHCI_THIS uhci[i] != NULL)
|
||||
@ -233,8 +230,6 @@ void bx_usb_ehci_c::init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
BX_EHCI_THIS device_buffer = new Bit8u[BUFF_SIZE];
|
||||
|
||||
// Call our frame timer routine every 1mS (1,024uS)
|
||||
// Continuous and active
|
||||
BX_EHCI_THIS hub.frame_timer_index = bx_pc_system.register_timer(this, ehci_frame_handler,
|
||||
@ -1207,7 +1202,7 @@ int bx_usb_ehci_c::qh_do_overlay(EHCIQueue *q)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bx_usb_ehci_c::init_transfer(EHCIPacket *p)
|
||||
int bx_usb_ehci_c::transfer(EHCIPacket *p)
|
||||
{
|
||||
Bit32u cpage, offset, bytes, plen, blen = 0;
|
||||
Bit64u page;
|
||||
@ -1233,9 +1228,9 @@ int bx_usb_ehci_c::init_transfer(EHCIPacket *p)
|
||||
|
||||
// Bochs specific code (no async and scatter/gather support yet)
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(page, plen, device_buffer+blen);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(page, plen, p->packet.data+blen);
|
||||
} else {
|
||||
DEV_MEM_READ_PHYSICAL_DMA(page, plen, device_buffer+blen);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(page, plen, p->packet.data+blen);
|
||||
}
|
||||
blen += plen;
|
||||
bytes -= plen;
|
||||
@ -1273,7 +1268,7 @@ void bx_usb_ehci_c::async_complete_packet(USBPacket *packet)
|
||||
BX_INFO(("Experimental async packet completion"));
|
||||
p = container_of_usb_packet(packet);
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
BX_EHCI_THIS init_transfer(p);
|
||||
BX_EHCI_THIS transfer(p);
|
||||
}
|
||||
BX_ASSERT(p->async == EHCI_ASYNC_INFLIGHT);
|
||||
p->async = EHCI_ASYNC_FINISHED;
|
||||
@ -1379,18 +1374,17 @@ int bx_usb_ehci_c::execute(EHCIPacket *p)
|
||||
|
||||
// FIXME: This check makes transfer fail with current Bochs code
|
||||
// if (p->async == EHCI_ASYNC_NONE) {
|
||||
usb_packet_init(&p->packet, p->tbytes);
|
||||
if (p->pid != USB_TOKEN_IN) {
|
||||
if (BX_EHCI_THIS init_transfer(p) != 0) {
|
||||
if (BX_EHCI_THIS transfer(p) != 0) {
|
||||
return USB_RET_PROCERR;
|
||||
}
|
||||
}
|
||||
|
||||
// Packet setup (could be moved separate function)
|
||||
// Packet setup
|
||||
p->packet.pid = p->pid;
|
||||
p->packet.devaddr = p->queue->dev->get_address();
|
||||
p->packet.devep = endp;
|
||||
p->packet.data = BX_EHCI_THIS device_buffer;
|
||||
p->packet.len = p->tbytes;
|
||||
p->packet.complete_cb = ehci_async_complete_packet;
|
||||
p->packet.complete_dev = BX_EHCI_THIS_PTR;
|
||||
|
||||
@ -1413,11 +1407,12 @@ int bx_usb_ehci_c::execute(EHCIPacket *p)
|
||||
// it received, not the amount it anticipates on receiving/sending in the next packet.
|
||||
ret = 8;
|
||||
} else if (p->pid == USB_TOKEN_IN) {
|
||||
if (BX_EHCI_THIS init_transfer(p) != 0) {
|
||||
if (BX_EHCI_THIS transfer(p) != 0) {
|
||||
return USB_RET_PROCERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
usb_packet_cleanup(&p->packet);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
//
|
||||
// Experimental USB EHCI adapter (partly ported from Qemu)
|
||||
//
|
||||
// Copyright (C) 2015 The Bochs Project
|
||||
// Copyright (C) 2015-2016 The Bochs Project
|
||||
//
|
||||
// Copyright(c) 2008 Emutex Ltd. (address@hidden)
|
||||
// Copyright(c) 2011-2012 Red Hat, Inc.
|
||||
@ -344,7 +344,6 @@ private:
|
||||
Bit8u devfunc;
|
||||
Bit8u device_change;
|
||||
int rt_conf_id;
|
||||
Bit8u *device_buffer;
|
||||
Bit32u maxframes;
|
||||
|
||||
void reset_hc(void);
|
||||
@ -383,7 +382,7 @@ private:
|
||||
int put_dwords(Bit32u addr, Bit32u *buf, int num);
|
||||
void flush_qh(EHCIQueue *q);
|
||||
int qh_do_overlay(EHCIQueue *q);
|
||||
int init_transfer(EHCIPacket *p);
|
||||
int transfer(EHCIPacket *p);
|
||||
void finish_transfer(EHCIQueue *q, int status);
|
||||
void execute_complete(EHCIQueue *q);
|
||||
int execute(EHCIPacket *p);
|
||||
|
@ -132,7 +132,6 @@ bx_usb_ohci_c::bx_usb_ohci_c()
|
||||
{
|
||||
put("usb_ohci", "OHCI");
|
||||
memset((void*)&hub, 0, sizeof(bx_usb_ohci_t));
|
||||
device_buffer = NULL;
|
||||
hub.frame_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
hub.rt_conf_id = -1;
|
||||
}
|
||||
@ -142,8 +141,6 @@ bx_usb_ohci_c::~bx_usb_ohci_c()
|
||||
char pname[16];
|
||||
|
||||
SIM->unregister_runtime_config_handler(hub.rt_conf_id);
|
||||
if (BX_OHCI_THIS device_buffer != NULL)
|
||||
delete [] BX_OHCI_THIS device_buffer;
|
||||
|
||||
for (int i=0; i<USB_OHCI_PORTS; i++) {
|
||||
sprintf(pname, "port%d.device", i+1);
|
||||
@ -174,8 +171,6 @@ void bx_usb_ohci_c::init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
BX_OHCI_THIS device_buffer = new Bit8u[8192];
|
||||
|
||||
// Call our frame timer routine every 1mS (1,000uS)
|
||||
// Continuous and active
|
||||
BX_OHCI_THIS hub.frame_timer_index =
|
||||
@ -1213,6 +1208,7 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
unsigned pid = 0, len = 0, len1, len2;
|
||||
int ilen, ret = 0;
|
||||
Bit32u addr;
|
||||
Bit16u maxlen = 0;
|
||||
bx_bool completion;
|
||||
|
||||
addr = ED_GET_HEADP(ed);
|
||||
@ -1263,21 +1259,21 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
BX_ERROR(("too many pending packets"));
|
||||
return 0;
|
||||
}
|
||||
BX_OHCI_THIS usb_packet.pid = pid;
|
||||
BX_OHCI_THIS usb_packet.devaddr = ED_GET_FA(ed);
|
||||
BX_OHCI_THIS usb_packet.devep = ED_GET_EN(ed);
|
||||
BX_OHCI_THIS usb_packet.data = BX_OHCI_THIS device_buffer;
|
||||
BX_OHCI_THIS usb_packet.complete_cb = ohci_async_complete_packet;
|
||||
BX_OHCI_THIS usb_packet.complete_dev = this;
|
||||
switch (pid) {
|
||||
case USB_TOKEN_SETUP:
|
||||
case USB_TOKEN_OUT:
|
||||
BX_OHCI_THIS usb_packet.len = (len <= ED_GET_MPS(ed)) ? len : ED_GET_MPS(ed);
|
||||
maxlen = (len <= ED_GET_MPS(ed)) ? len : ED_GET_MPS(ed);
|
||||
break;
|
||||
case USB_TOKEN_IN:
|
||||
BX_OHCI_THIS usb_packet.len = len;
|
||||
maxlen = len;
|
||||
break;
|
||||
}
|
||||
usb_packet_init(&BX_OHCI_THIS usb_packet, maxlen);
|
||||
BX_OHCI_THIS usb_packet.pid = pid;
|
||||
BX_OHCI_THIS usb_packet.devaddr = ED_GET_FA(ed);
|
||||
BX_OHCI_THIS usb_packet.devep = ED_GET_EN(ed);
|
||||
BX_OHCI_THIS usb_packet.complete_cb = ohci_async_complete_packet;
|
||||
BX_OHCI_THIS usb_packet.complete_dev = this;
|
||||
|
||||
BX_DEBUG((" pid = %s addr = %i endpnt = %i len = %i mps = %i (td->cbp = 0x%08X, td->be = 0x%08X)",
|
||||
(pid == USB_TOKEN_IN)? "IN" : (pid == USB_TOKEN_OUT) ? "OUT" : (pid == USB_TOKEN_SETUP) ? "SETUP" : "UNKNOWN",
|
||||
@ -1287,7 +1283,7 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
switch (pid) {
|
||||
case USB_TOKEN_SETUP:
|
||||
if (len > 0)
|
||||
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, device_buffer);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, BX_OHCI_THIS usb_packet.data);
|
||||
// TODO: This is a hack. dev->handle_packet() should return the amount of bytes
|
||||
// it received, not the amount it anticipates on receiving/sending in the next packet.
|
||||
if ((ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet)) >= 0)
|
||||
@ -1295,7 +1291,7 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
break;
|
||||
case USB_TOKEN_OUT:
|
||||
if (len > 0)
|
||||
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, device_buffer);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), maxlen, BX_OHCI_THIS usb_packet.data);
|
||||
ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
|
||||
break;
|
||||
case USB_TOKEN_IN:
|
||||
@ -1317,10 +1313,10 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
if (((TD_GET_CBP(td) & 0xfff) + ret) > 0x1000) {
|
||||
len1 = 0x1000 - (TD_GET_CBP(td) & 0xfff);
|
||||
len2 = ret - len1;
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), len1, device_buffer);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA((TD_GET_BE(td) & ~0xfff), len2, device_buffer+len1);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), len1, BX_OHCI_THIS usb_packet.data);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA((TD_GET_BE(td) & ~0xfff), len2, BX_OHCI_THIS usb_packet.data+len1);
|
||||
} else {
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), ret, device_buffer);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), ret, BX_OHCI_THIS usb_packet.data);
|
||||
}
|
||||
}
|
||||
if ((ret == (int)len) || ((pid == USB_TOKEN_IN) && (ret >= 0) &&
|
||||
@ -1373,6 +1369,7 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
|
||||
BX_DEBUG((" td->cbp = 0x%08X ret = %i len = %i td->cc = %i td->ec = %i ed->h = %i", TD_GET_CBP(td), ret, len, TD_GET_CC(td), TD_GET_EC(td), ED_GET_H(ed)));
|
||||
BX_DEBUG((" td->t = %i ed->c = %i", TD_GET_T(td), ED_GET_C(ed)));
|
||||
usb_packet_cleanup(&BX_OHCI_THIS usb_packet);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -263,7 +263,6 @@ public:
|
||||
private:
|
||||
|
||||
bx_usb_ohci_t hub;
|
||||
Bit8u *device_buffer;
|
||||
|
||||
USBPacket usb_packet;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user