Added support for multiple async packets on UHCI (TODO: other HCs).
This commit is contained in:
parent
666780dab5
commit
f82bb13f88
@ -59,6 +59,12 @@
|
||||
const Bit8u uhci_iomask[32] = {2, 1, 2, 1, 2, 1, 2, 0, 4, 0, 0, 0, 1, 0, 0, 0,
|
||||
3, 1, 3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static inline struct UHCIAsync *container_of_usb_packet(void *ptr)
|
||||
{
|
||||
return reinterpret_cast<struct UHCIAsync*>(static_cast<char*>(ptr) -
|
||||
reinterpret_cast<size_t>(&(static_cast<struct UHCIAsync*>(0)->packet)));
|
||||
}
|
||||
|
||||
// the device object
|
||||
|
||||
bx_uhci_core_c::bx_uhci_core_c()
|
||||
@ -162,9 +168,9 @@ void bx_uhci_core_c::reset_uhci(unsigned type)
|
||||
set_connect_status(j, hub.usb_port[j].device->get_type(), 1);
|
||||
}
|
||||
}
|
||||
if (hub.async_td) {
|
||||
usb_cancel_packet(&usb_packet);
|
||||
hub.async_td = 0;
|
||||
while (packets != NULL) {
|
||||
usb_cancel_packet(&packets->packet);
|
||||
remove_async_packet(packets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,8 +223,7 @@ void bx_uhci_core_c::register_state(bx_list_c *parent)
|
||||
// empty list for USB device state
|
||||
new bx_list_c(port, "device");
|
||||
}
|
||||
BXRS_DEC_PARAM_FIELD(hub1, async_td, hub.async_td);
|
||||
BXRS_PARAM_BOOL(hub1, async_complete, hub.async_complete);
|
||||
// TODO: handle async packets
|
||||
register_pci_state(hub1);
|
||||
|
||||
BXRS_PARAM_BOOL(list, busy, busy);
|
||||
@ -747,12 +752,14 @@ void uhci_async_complete_packet(USBPacket *packet, void *dev)
|
||||
void bx_uhci_core_c::async_complete_packet(USBPacket *packet)
|
||||
{
|
||||
BX_DEBUG(("Experimental async packet completion"));
|
||||
hub.async_complete = 1;
|
||||
UHCIAsync *p = container_of_usb_packet(packet);
|
||||
p->done = 1;
|
||||
}
|
||||
|
||||
bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td) {
|
||||
|
||||
int len = 0, ret = 0;
|
||||
UHCIAsync *p;
|
||||
bx_bool completion;
|
||||
|
||||
Bit16u maxlen = (td->dword2 >> 21);
|
||||
@ -763,8 +770,9 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
BX_DEBUG(("QH%03i:TD found at address: 0x%08X", queue_num, address));
|
||||
BX_DEBUG((" %08X %08X %08X %08X", td->dword0, td->dword1, td->dword2, td->dword3));
|
||||
|
||||
completion = (address == hub.async_td);
|
||||
if (completion && !hub.async_complete) {
|
||||
p = find_async_packet(address);
|
||||
completion = (p != NULL);
|
||||
if (completion && !p->done) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -787,31 +795,25 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
maxlen &= 0x7FF;
|
||||
|
||||
if (completion) {
|
||||
ret = usb_packet.len;
|
||||
hub.async_td = 0;
|
||||
hub.async_complete = 0;
|
||||
ret = p->packet.len;
|
||||
} else {
|
||||
if (hub.async_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.complete_cb = uhci_async_complete_packet;
|
||||
usb_packet.complete_dev = this;
|
||||
p = create_async_packet(address, maxlen);
|
||||
p->packet.pid = pid;
|
||||
p->packet.devaddr = addr;
|
||||
p->packet.devep = endpt;
|
||||
p->packet.complete_cb = uhci_async_complete_packet;
|
||||
p->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, usb_packet.data);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(td->dword3, maxlen, p->packet.data);
|
||||
}
|
||||
ret = broadcast_packet(&usb_packet);
|
||||
ret = broadcast_packet(&p->packet);
|
||||
len = maxlen;
|
||||
break;
|
||||
case USB_TOKEN_IN:
|
||||
ret = broadcast_packet(&usb_packet);
|
||||
ret = broadcast_packet(&p->packet);
|
||||
break;
|
||||
default:
|
||||
hub.usb_status.host_error = 1;
|
||||
@ -819,7 +821,6 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
return 0;
|
||||
}
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
hub.async_td = address;
|
||||
BX_DEBUG(("Async packet deferred"));
|
||||
return 0;
|
||||
}
|
||||
@ -832,7 +833,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, usb_packet.data);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(td->dword3, len, p->packet.data);
|
||||
}
|
||||
} else {
|
||||
len = 0;
|
||||
@ -845,7 +846,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);
|
||||
remove_async_packet(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1045,4 +1046,56 @@ void bx_uhci_core_c::set_port_device(int port, usb_device_c *dev)
|
||||
}
|
||||
}
|
||||
|
||||
// Async packet support
|
||||
|
||||
UHCIAsync* bx_uhci_core_c::create_async_packet(Bit32u addr, int maxlen)
|
||||
{
|
||||
UHCIAsync *p;
|
||||
|
||||
p = new UHCIAsync;
|
||||
usb_packet_init(&p->packet, maxlen);
|
||||
p->td_addr = addr;
|
||||
p->done = 0;
|
||||
p->next = packets;
|
||||
packets = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
void bx_uhci_core_c::remove_async_packet(UHCIAsync *p)
|
||||
{
|
||||
UHCIAsync *last;
|
||||
|
||||
if (packets == p) {
|
||||
packets = p->next;
|
||||
} else {
|
||||
last = packets;
|
||||
while (last != NULL) {
|
||||
if (last->next != p)
|
||||
last = last->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (last) {
|
||||
last->next = p->next;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
usb_packet_cleanup(&p->packet);
|
||||
delete p;
|
||||
}
|
||||
|
||||
UHCIAsync* bx_uhci_core_c::find_async_packet(Bit32u addr)
|
||||
{
|
||||
UHCIAsync *p = packets;
|
||||
|
||||
while (p != NULL) {
|
||||
if (p->td_addr != addr)
|
||||
p = p->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI && BX_SUPPORT_USB_UHCI
|
||||
|
@ -149,8 +149,6 @@ typedef struct {
|
||||
} usb_port[USB_UHCI_PORTS];
|
||||
|
||||
Bit8u devfunc;
|
||||
Bit32u async_td;
|
||||
bx_bool async_complete;
|
||||
} bx_uhci_core_t;
|
||||
|
||||
#pragma pack (push, 1)
|
||||
@ -172,6 +170,13 @@ struct HCSTACK {
|
||||
bx_bool t;
|
||||
};
|
||||
|
||||
typedef struct UHCIAsync {
|
||||
USBPacket packet;
|
||||
Bit32u td_addr;
|
||||
bx_bool done;
|
||||
struct UHCIAsync *next;
|
||||
} UHCIAsync;
|
||||
|
||||
class bx_uhci_core_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
||||
public:
|
||||
bx_uhci_core_c();
|
||||
@ -191,13 +196,17 @@ protected:
|
||||
Bit8u global_reset;
|
||||
bx_bool busy;
|
||||
|
||||
USBPacket usb_packet;
|
||||
UHCIAsync *packets;
|
||||
|
||||
void update_irq(void);
|
||||
|
||||
int broadcast_packet(USBPacket *p);
|
||||
void set_connect_status(Bit8u port, int type, bx_bool connected);
|
||||
|
||||
UHCIAsync* create_async_packet(Bit32u addr, int maxlen);
|
||||
void remove_async_packet(UHCIAsync *packet);
|
||||
UHCIAsync* find_async_packet(Bit32u addr);
|
||||
|
||||
static void uhci_timer_handler(void *);
|
||||
void uhci_timer(void);
|
||||
bx_bool DoTransfer(Bit32u address, Bit32u queue_num, struct TD *);
|
||||
|
Loading…
Reference in New Issue
Block a user