Added support for multiple async packets on OHCI.
- Moved UHCI async packet functions to usb_common.h for using then on both UHCI and OHCI. - Modified OHCI packet handling based on the UHCI implementation. - Renamed EHCI helper function to avoid conflicts. - TODO: async packet support on xHCI.
This commit is contained in:
parent
ff3b20be1a
commit
a22e66ef13
@ -59,12 +59,6 @@
|
||||
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()
|
||||
@ -170,7 +164,7 @@ void bx_uhci_core_c::reset_uhci(unsigned type)
|
||||
}
|
||||
while (packets != NULL) {
|
||||
usb_cancel_packet(&packets->packet);
|
||||
remove_async_packet(packets);
|
||||
remove_async_packet(&packets, packets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -752,14 +746,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"));
|
||||
UHCIAsync *p = container_of_usb_packet(packet);
|
||||
USBAsync *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;
|
||||
USBAsync *p;
|
||||
bx_bool completion;
|
||||
|
||||
Bit16u maxlen = (td->dword2 >> 21);
|
||||
@ -770,7 +764,7 @@ 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));
|
||||
|
||||
p = find_async_packet(address);
|
||||
p = find_async_packet(&packets, address);
|
||||
completion = (p != NULL);
|
||||
if (completion && !p->done) {
|
||||
return 0;
|
||||
@ -797,7 +791,7 @@ bx_bool bx_uhci_core_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *
|
||||
if (completion) {
|
||||
ret = p->packet.len;
|
||||
} else {
|
||||
p = create_async_packet(address, maxlen);
|
||||
p = create_async_packet(&packets, address, maxlen);
|
||||
p->packet.pid = pid;
|
||||
p->packet.devaddr = addr;
|
||||
p->packet.devep = endpt;
|
||||
@ -846,7 +840,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
|
||||
}
|
||||
remove_async_packet(p);
|
||||
remove_async_packet(&packets, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1046,56 +1040,4 @@ 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
|
||||
|
@ -170,13 +170,6 @@ 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();
|
||||
@ -196,17 +189,13 @@ protected:
|
||||
Bit8u global_reset;
|
||||
bx_bool busy;
|
||||
|
||||
UHCIAsync *packets;
|
||||
USBAsync *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 *);
|
||||
|
@ -135,6 +135,13 @@ struct USBPacket {
|
||||
usb_device_c *dev;
|
||||
};
|
||||
|
||||
typedef struct USBAsync {
|
||||
USBPacket packet;
|
||||
Bit32u td_addr;
|
||||
bx_bool done;
|
||||
struct USBAsync *next;
|
||||
} USBAsync;
|
||||
|
||||
enum usbdev_type {
|
||||
USB_DEV_TYPE_NONE=0,
|
||||
USB_DEV_TYPE_MOUSE,
|
||||
@ -249,4 +256,62 @@ static BX_CPP_INLINE void usb_packet_complete(USBPacket *p)
|
||||
p->complete_cb(p, p->complete_dev);
|
||||
}
|
||||
|
||||
// Async packet support
|
||||
|
||||
static BX_CPP_INLINE USBAsync* create_async_packet(USBAsync **base, Bit32u addr, int maxlen)
|
||||
{
|
||||
USBAsync *p;
|
||||
|
||||
p = new USBAsync;
|
||||
usb_packet_init(&p->packet, maxlen);
|
||||
p->td_addr = addr;
|
||||
p->done = 0;
|
||||
p->next = *base;
|
||||
*base = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static BX_CPP_INLINE void remove_async_packet(USBAsync **base, USBAsync *p)
|
||||
{
|
||||
USBAsync *last;
|
||||
|
||||
if (*base == p) {
|
||||
*base = p->next;
|
||||
} else {
|
||||
last = *base;
|
||||
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;
|
||||
}
|
||||
|
||||
static BX_CPP_INLINE USBAsync* find_async_packet(USBAsync **base, Bit32u addr)
|
||||
{
|
||||
USBAsync *p = *base;
|
||||
|
||||
while (p != NULL) {
|
||||
if (p->td_addr != addr)
|
||||
p = p->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static BX_CPP_INLINE struct USBAsync *container_of_usb_packet(void *ptr)
|
||||
{
|
||||
return reinterpret_cast<struct USBAsync*>(static_cast<char*>(ptr) -
|
||||
reinterpret_cast<size_t>(&(static_cast<struct USBAsync*>(0)->packet)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -117,7 +117,7 @@ typedef enum {
|
||||
*data = val; \
|
||||
} while(0)
|
||||
|
||||
static inline struct EHCIPacket *container_of_usb_packet(void *ptr)
|
||||
static inline struct EHCIPacket *ehci_container_of_usb_packet(void *ptr)
|
||||
{
|
||||
return reinterpret_cast<struct EHCIPacket*>(static_cast<char*>(ptr) -
|
||||
reinterpret_cast<size_t>(&(static_cast<struct EHCIPacket*>(0)->packet)));
|
||||
@ -1290,7 +1290,7 @@ void bx_usb_ehci_c::async_complete_packet(USBPacket *packet)
|
||||
EHCIPacket *p;
|
||||
|
||||
BX_DEBUG(("Experimental async packet completion"));
|
||||
p = container_of_usb_packet(packet);
|
||||
p = ehci_container_of_usb_packet(packet);
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
BX_EHCI_THIS transfer(p);
|
||||
}
|
||||
|
@ -367,9 +367,9 @@ void bx_usb_ohci_c::reset_hc()
|
||||
}
|
||||
}
|
||||
|
||||
if (BX_OHCI_THIS hub.async_td) {
|
||||
usb_cancel_packet(&BX_OHCI_THIS usb_packet);
|
||||
BX_OHCI_THIS hub.async_td = 0;
|
||||
while (BX_OHCI_THIS packets != NULL) {
|
||||
usb_cancel_packet(&BX_OHCI_THIS packets->packet);
|
||||
remove_async_packet(&BX_OHCI_THIS packets, BX_OHCI_THIS packets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,8 +469,7 @@ void bx_usb_ohci_c::register_state(void)
|
||||
BXRS_PARAM_BOOL(hub, use_control_head, BX_OHCI_THIS hub.use_control_head);
|
||||
BXRS_PARAM_BOOL(hub, use_bulk_head, BX_OHCI_THIS hub.use_bulk_head);
|
||||
BXRS_DEC_PARAM_FIELD(hub, sof_time, BX_OHCI_THIS hub.sof_time);
|
||||
BXRS_DEC_PARAM_FIELD(hub, async_td, BX_OHCI_THIS hub.async_td);
|
||||
BXRS_PARAM_BOOL(hub, async_complete, BX_OHCI_THIS hub.async_complete);
|
||||
// TODO: handle async packets
|
||||
register_pci_state(hub);
|
||||
}
|
||||
|
||||
@ -1192,7 +1191,8 @@ void ohci_async_complete_packet(USBPacket *packet, void *dev)
|
||||
void bx_usb_ohci_c::async_complete_packet(USBPacket *packet)
|
||||
{
|
||||
BX_DEBUG(("Async packet completion"));
|
||||
BX_OHCI_THIS hub.async_complete = 1;
|
||||
USBAsync *p = container_of_usb_packet(packet);
|
||||
p->done = 1;
|
||||
// These hacks are currently required for async completion
|
||||
BX_OHCI_THIS hub.use_control_head = 1;
|
||||
BX_OHCI_THIS hub.use_bulk_head = 1;
|
||||
@ -1207,11 +1207,13 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
int ilen, ret = 0, ret2 = 1;
|
||||
Bit32u addr;
|
||||
Bit16u maxlen = 0;
|
||||
USBAsync *p;
|
||||
bx_bool completion;
|
||||
|
||||
addr = ED_GET_HEADP(ed);
|
||||
completion = (addr == BX_OHCI_THIS hub.async_td);
|
||||
if (completion && !BX_OHCI_THIS hub.async_complete) {
|
||||
p = find_async_packet(&packets, addr);
|
||||
completion = (p != NULL);
|
||||
if (completion && !p->done) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1249,14 +1251,8 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
len = 0;
|
||||
|
||||
if (completion) {
|
||||
ret = BX_OHCI_THIS usb_packet.len;
|
||||
BX_OHCI_THIS hub.async_td = 0;
|
||||
BX_OHCI_THIS hub.async_complete = 0;
|
||||
ret = p->packet.len;
|
||||
} else {
|
||||
if (BX_OHCI_THIS hub.async_td) {
|
||||
BX_ERROR(("too many pending packets"));
|
||||
return 0;
|
||||
}
|
||||
switch (pid) {
|
||||
case USB_TOKEN_SETUP:
|
||||
case USB_TOKEN_OUT:
|
||||
@ -1266,12 +1262,12 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
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;
|
||||
p = create_async_packet(&packets, addr, maxlen);
|
||||
p->packet.pid = pid;
|
||||
p->packet.devaddr = ED_GET_FA(ed);
|
||||
p->packet.devep = ED_GET_EN(ed);
|
||||
p->packet.complete_cb = ohci_async_complete_packet;
|
||||
p->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",
|
||||
@ -1281,19 +1277,19 @@ 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, BX_OHCI_THIS usb_packet.data);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, p->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)
|
||||
if ((ret = BX_OHCI_THIS broadcast_packet(&p->packet)) >= 0)
|
||||
ret = 8;
|
||||
break;
|
||||
case USB_TOKEN_OUT:
|
||||
if (len > 0)
|
||||
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);
|
||||
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), maxlen, p->packet.data);
|
||||
ret = BX_OHCI_THIS broadcast_packet(&p->packet);
|
||||
break;
|
||||
case USB_TOKEN_IN:
|
||||
ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
|
||||
ret = BX_OHCI_THIS broadcast_packet(&p->packet);
|
||||
break;
|
||||
default:
|
||||
TD_SET_CC(td, UnexpectedPID);
|
||||
@ -1302,7 +1298,6 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
|
||||
}
|
||||
|
||||
if (ret == USB_RET_ASYNC) {
|
||||
BX_OHCI_THIS hub.async_td = addr;
|
||||
BX_DEBUG(("Async packet deferred"));
|
||||
return 0;
|
||||
}
|
||||
@ -1311,10 +1306,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, BX_OHCI_THIS usb_packet.data);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA((TD_GET_BE(td) & ~0xfff), len2, BX_OHCI_THIS usb_packet.data+len1);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), len1, p->packet.data);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA((TD_GET_BE(td) & ~0xfff), len2, p->packet.data+len1);
|
||||
} else {
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), ret, BX_OHCI_THIS usb_packet.data);
|
||||
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), ret, p->packet.data);
|
||||
}
|
||||
}
|
||||
if ((ret == (int)len) || ((pid == USB_TOKEN_IN) && (ret >= 0) &&
|
||||
@ -1369,7 +1364,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);
|
||||
remove_async_packet(&packets, p);
|
||||
|
||||
return ret2;
|
||||
}
|
||||
|
@ -235,8 +235,6 @@ typedef struct {
|
||||
bx_bool use_control_head;
|
||||
bx_bool use_bulk_head;
|
||||
Bit64u sof_time;
|
||||
Bit32u async_td;
|
||||
bx_bool async_complete;
|
||||
|
||||
Bit8u device_change;
|
||||
int rt_conf_id;
|
||||
@ -264,7 +262,7 @@ private:
|
||||
|
||||
bx_usb_ohci_t hub;
|
||||
|
||||
USBPacket usb_packet;
|
||||
USBAsync *packets;
|
||||
|
||||
static void reset_hc();
|
||||
static void reset_port(int);
|
||||
|
Loading…
Reference in New Issue
Block a user