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:
Volker Ruppert 2016-11-18 21:27:43 +00:00
parent de6ee1d7eb
commit 0192554c25
7 changed files with 50 additions and 47 deletions

View File

@ -65,22 +65,16 @@ bx_uhci_core_c::bx_uhci_core_c()
{ {
put("uhci_core", "UHCIC"); put("uhci_core", "UHCIC");
memset((void*)&hub, 0, sizeof(bx_uhci_core_t)); memset((void*)&hub, 0, sizeof(bx_uhci_core_t));
device_buffer = NULL;
hub.timer_index = BX_NULL_TIMER_HANDLE; hub.timer_index = BX_NULL_TIMER_HANDLE;
} }
bx_uhci_core_c::~bx_uhci_core_c() bx_uhci_core_c::~bx_uhci_core_c()
{ {
if (device_buffer != NULL)
delete [] device_buffer;
BX_DEBUG(("Exit")); BX_DEBUG(("Exit"));
} }
void bx_uhci_core_c::init_uhci(Bit8u devfunc, Bit16u devid, Bit8u headt, Bit8u intp) 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) // Call our timer routine every 1mS (1,000uS)
// Continuous and active // Continuous and active
hub.timer_index = 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")); BX_ERROR(("too many pending packets"));
return 0; return 0;
} }
usb_packet_init(&usb_packet, maxlen);
usb_packet.pid = pid; usb_packet.pid = pid;
usb_packet.devaddr = addr; usb_packet.devaddr = addr;
usb_packet.devep = endpt; usb_packet.devep = endpt;
usb_packet.data = device_buffer;
usb_packet.len = maxlen;
usb_packet.complete_cb = uhci_async_complete_packet; usb_packet.complete_cb = uhci_async_complete_packet;
usb_packet.complete_dev = this; usb_packet.complete_dev = this;
switch (pid) { switch (pid) {
case USB_TOKEN_OUT: case USB_TOKEN_OUT:
case USB_TOKEN_SETUP: case USB_TOKEN_SETUP:
if (maxlen > 0) { 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); ret = broadcast_packet(&usb_packet);
len = maxlen; len = maxlen;
@ -839,7 +832,7 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
ret = USB_RET_BABBLE; ret = USB_RET_BABBLE;
} }
if (len > 0) { 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 { } else {
len = 0; len = 0;
@ -850,6 +843,7 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
} else { } else {
set_status(td, 1, 0, 0, 0, 0, 0, 0x007); // stalled set_status(td, 1, 0, 0, 0, 0, 0, 0x007); // stalled
} }
usb_packet_cleanup(&usb_packet);
return 1; return 1;
} }

View File

@ -190,7 +190,6 @@ protected:
bx_uhci_core_t hub; bx_uhci_core_t hub;
Bit8u global_reset; Bit8u global_reset;
bx_bool busy; bx_bool busy;
Bit8u *device_buffer;
USBPacket usb_packet; USBPacket usb_packet;

View File

@ -214,6 +214,26 @@ protected:
int set_usb_string(Bit8u *buf, const char *str); 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) static BX_CPP_INLINE void usb_defer_packet(USBPacket *p, usb_device_c *dev)
{ {
p->dev = dev; p->dev = dev;

View File

@ -184,7 +184,6 @@ bx_usb_ehci_c::bx_usb_ehci_c()
{ {
put("usb_ehci", "EHCI"); put("usb_ehci", "EHCI");
memset((void*)&hub, 0, sizeof(bx_usb_ehci_t)); memset((void*)&hub, 0, sizeof(bx_usb_ehci_t));
device_buffer = NULL;
rt_conf_id = -1; rt_conf_id = -1;
hub.frame_timer_index = BX_NULL_TIMER_HANDLE; hub.frame_timer_index = BX_NULL_TIMER_HANDLE;
} }
@ -195,8 +194,6 @@ bx_usb_ehci_c::~bx_usb_ehci_c()
int i; int i;
SIM->unregister_runtime_config_handler(rt_conf_id); 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++) { for (i = 0; i < 3; i++) {
if (BX_EHCI_THIS uhci[i] != NULL) if (BX_EHCI_THIS uhci[i] != NULL)
@ -233,8 +230,6 @@ void bx_usb_ehci_c::init(void)
return; return;
} }
BX_EHCI_THIS device_buffer = new Bit8u[BUFF_SIZE];
// Call our frame timer routine every 1mS (1,024uS) // Call our frame timer routine every 1mS (1,024uS)
// Continuous and active // Continuous and active
BX_EHCI_THIS hub.frame_timer_index = bx_pc_system.register_timer(this, ehci_frame_handler, 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; 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; Bit32u cpage, offset, bytes, plen, blen = 0;
Bit64u page; 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) // Bochs specific code (no async and scatter/gather support yet)
if (p->pid == USB_TOKEN_IN) { 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 { } else {
DEV_MEM_READ_PHYSICAL_DMA(page, plen, device_buffer+blen); DEV_MEM_READ_PHYSICAL_DMA(page, plen, p->packet.data+blen);
} }
blen += plen; blen += plen;
bytes -= plen; bytes -= plen;
@ -1273,7 +1268,7 @@ void bx_usb_ehci_c::async_complete_packet(USBPacket *packet)
BX_INFO(("Experimental async packet completion")); BX_INFO(("Experimental async packet completion"));
p = container_of_usb_packet(packet); p = container_of_usb_packet(packet);
if (p->pid == USB_TOKEN_IN) { if (p->pid == USB_TOKEN_IN) {
BX_EHCI_THIS init_transfer(p); BX_EHCI_THIS transfer(p);
} }
BX_ASSERT(p->async == EHCI_ASYNC_INFLIGHT); BX_ASSERT(p->async == EHCI_ASYNC_INFLIGHT);
p->async = EHCI_ASYNC_FINISHED; 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 // FIXME: This check makes transfer fail with current Bochs code
// if (p->async == EHCI_ASYNC_NONE) { // if (p->async == EHCI_ASYNC_NONE) {
usb_packet_init(&p->packet, p->tbytes);
if (p->pid != USB_TOKEN_IN) { 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; return USB_RET_PROCERR;
} }
} }
// Packet setup (could be moved separate function) // Packet setup
p->packet.pid = p->pid; p->packet.pid = p->pid;
p->packet.devaddr = p->queue->dev->get_address(); p->packet.devaddr = p->queue->dev->get_address();
p->packet.devep = endp; 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_cb = ehci_async_complete_packet;
p->packet.complete_dev = BX_EHCI_THIS_PTR; 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. // it received, not the amount it anticipates on receiving/sending in the next packet.
ret = 8; ret = 8;
} else if (p->pid == USB_TOKEN_IN) { } 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; return USB_RET_PROCERR;
} }
} }
} }
usb_packet_cleanup(&p->packet);
return ret; return ret;
} }

View File

@ -4,7 +4,7 @@
// //
// Experimental USB EHCI adapter (partly ported from Qemu) // 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) 2008 Emutex Ltd. (address@hidden)
// Copyright(c) 2011-2012 Red Hat, Inc. // Copyright(c) 2011-2012 Red Hat, Inc.
@ -344,7 +344,6 @@ private:
Bit8u devfunc; Bit8u devfunc;
Bit8u device_change; Bit8u device_change;
int rt_conf_id; int rt_conf_id;
Bit8u *device_buffer;
Bit32u maxframes; Bit32u maxframes;
void reset_hc(void); void reset_hc(void);
@ -383,7 +382,7 @@ private:
int put_dwords(Bit32u addr, Bit32u *buf, int num); int put_dwords(Bit32u addr, Bit32u *buf, int num);
void flush_qh(EHCIQueue *q); void flush_qh(EHCIQueue *q);
int qh_do_overlay(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 finish_transfer(EHCIQueue *q, int status);
void execute_complete(EHCIQueue *q); void execute_complete(EHCIQueue *q);
int execute(EHCIPacket *p); int execute(EHCIPacket *p);

View File

@ -132,7 +132,6 @@ bx_usb_ohci_c::bx_usb_ohci_c()
{ {
put("usb_ohci", "OHCI"); put("usb_ohci", "OHCI");
memset((void*)&hub, 0, sizeof(bx_usb_ohci_t)); memset((void*)&hub, 0, sizeof(bx_usb_ohci_t));
device_buffer = NULL;
hub.frame_timer_index = BX_NULL_TIMER_HANDLE; hub.frame_timer_index = BX_NULL_TIMER_HANDLE;
hub.rt_conf_id = -1; hub.rt_conf_id = -1;
} }
@ -142,8 +141,6 @@ bx_usb_ohci_c::~bx_usb_ohci_c()
char pname[16]; char pname[16];
SIM->unregister_runtime_config_handler(hub.rt_conf_id); 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++) { for (int i=0; i<USB_OHCI_PORTS; i++) {
sprintf(pname, "port%d.device", i+1); sprintf(pname, "port%d.device", i+1);
@ -174,8 +171,6 @@ void bx_usb_ohci_c::init(void)
return; return;
} }
BX_OHCI_THIS device_buffer = new Bit8u[8192];
// Call our frame timer routine every 1mS (1,000uS) // Call our frame timer routine every 1mS (1,000uS)
// Continuous and active // Continuous and active
BX_OHCI_THIS hub.frame_timer_index = 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; unsigned pid = 0, len = 0, len1, len2;
int ilen, ret = 0; int ilen, ret = 0;
Bit32u addr; Bit32u addr;
Bit16u maxlen = 0;
bx_bool completion; bx_bool completion;
addr = ED_GET_HEADP(ed); 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")); BX_ERROR(("too many pending packets"));
return 0; 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) { switch (pid) {
case USB_TOKEN_SETUP: case USB_TOKEN_SETUP:
case USB_TOKEN_OUT: 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; break;
case USB_TOKEN_IN: case USB_TOKEN_IN:
BX_OHCI_THIS usb_packet.len = len; maxlen = len;
break; 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)", 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", (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) { switch (pid) {
case USB_TOKEN_SETUP: case USB_TOKEN_SETUP:
if (len > 0) 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 // 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. // 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) 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; break;
case USB_TOKEN_OUT: case USB_TOKEN_OUT:
if (len > 0) 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); ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
break; break;
case USB_TOKEN_IN: 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) { if (((TD_GET_CBP(td) & 0xfff) + ret) > 0x1000) {
len1 = 0x1000 - (TD_GET_CBP(td) & 0xfff); len1 = 0x1000 - (TD_GET_CBP(td) & 0xfff);
len2 = ret - len1; len2 = ret - len1;
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), len1, device_buffer); 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, device_buffer+len1); DEV_MEM_WRITE_PHYSICAL_DMA((TD_GET_BE(td) & ~0xfff), len2, BX_OHCI_THIS usb_packet.data+len1);
} else { } 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) && 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->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))); 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; return 1;
} }

View File

@ -263,7 +263,6 @@ public:
private: private:
bx_usb_ohci_t hub; bx_usb_ohci_t hub;
Bit8u *device_buffer;
USBPacket usb_packet; USBPacket usb_packet;