Some work for asynchronus USB packet handling (needed by disk/cdrom seek emulation).

- Common USB code prepared for async USB packet handling (ported from an earlier
  Qemu version).
- Added simple async packet handling to OHCI (partly ported from earlier Qemu).
- Implemented USB cdrom seek emulation for hubs with async packet support. The
  legacy code is still present for hubs without this feature.
- For UHCI and xHCI the callback is set to NULL to force the usage of the
  legacy cdrom read code.
TODO: clean up OHCI code, async support for UHCI and xHCI, seek emulation for
USB harddisk and floppy.
This commit is contained in:
Volker Ruppert 2015-09-13 20:04:41 +00:00
parent 8db5305b18
commit 491dc311ca
8 changed files with 260 additions and 122 deletions

View File

@ -91,6 +91,7 @@ scsi_device_t::scsi_device_t(device_image_t *_hdimage, int _tcq,
locked = 0;
inserted = 1;
max_lba = (hdimage->hd_size / 512) - 1;
curr_lba = max_lba;
sprintf(drive_serial_str, "%d", serial_number++);
seek_timer_index =
DEV_register_timer(this, seek_timer_handler, 1000, 0, 0, "USB HD seek");
@ -113,6 +114,7 @@ scsi_device_t::scsi_device_t(cdrom_base_c *_cdrom, int _tcq,
locked = 0;
inserted = 0;
max_lba = 0;
curr_lba = 0;
sprintf(drive_serial_str, "%d", serial_number++);
seek_timer_index =
DEV_register_timer(this, seek_timer_handler, 1000, 0, 0, "USB CD seek");
@ -152,6 +154,7 @@ void scsi_device_t::register_state(bx_list_c *parent, const char *name)
bx_list_c *list = new bx_list_c(parent, name, "");
new bx_shadow_num_c(list, "sense", &sense);
new bx_shadow_bool_c(list, "locked", &locked);
new bx_shadow_num_c(list, "curr_lba", &curr_lba);
bx_param_bool_c *requests = new bx_param_bool_c(list, "requests", NULL, NULL, 0);
requests->set_sr_handlers(this, scsireq_save_handler, scsireq_restore_handler);
}
@ -171,6 +174,8 @@ SCSIRequest* scsi_device_t::scsi_new_request(Bit32u tag)
}
r->tag = tag;
r->sector_count = 0;
r->async_supported = 0;
r->seek_active = 0;
r->buf_len = 0;
r->status = 0;
@ -232,6 +237,8 @@ bx_bool scsi_device_t::save_requests(const char *path)
fprintf(fp, " sector_count = %u\n", r->sector_count);
fprintf(fp, " buf_len = %d\n", r->buf_len);
fprintf(fp, " status = %u\n", r->status);
fprintf(fp, " async_supported = %u\n", r->async_supported);
fprintf(fp, " seek_active = %u\n", r->seek_active);
fprintf(fp, "}\n");
if (r->buf_len > 0) {
sprintf(tmppath, "%s.%u", path, i);
@ -323,6 +330,10 @@ void scsi_device_t::restore_requests(const char *path)
r->buf_len = (int)value;
} else if (!strcmp(pname, "status")) {
r->status = (Bit32u)value;
} else if (!strcmp(pname, "async_supported")) {
r->async_supported = (bx_bool)value;
} else if (!strcmp(pname, "seek_active")) {
r->seek_active = (bx_bool)value;
} else {
BX_ERROR(("restore_requests(): data format error"));
rrq_error = 1;
@ -407,14 +418,19 @@ bx_bool scsi_device_t::scsi_read_data(Bit32u tag)
n = SCSI_DMA_BUF_SIZE / (512 * cluster_size);
r->buf_len = n * 512 * cluster_size;
if (type == SCSIDEV_TYPE_CDROM) {
i = 0;
do {
ret = (int)cdrom->read_block(r->dma_buf + (i * 2048), (Bit32u)(r->sector + i), 2048);
} while ((++i < n) && (ret == 1));
if (ret == 0) {
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_MEDIUM_ERROR);
if (r->async_supported) {
if (!r->seek_active) start_seek(r);
return 1;
} else {
scsi_read_complete((void*)r, 0);
i = 0;
do {
ret = (int)cdrom->read_block(r->dma_buf + (i * 2048), (Bit32u)(r->sector + i), 2048);
} while ((++i < n) && (ret == 1));
if (ret == 0) {
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_MEDIUM_ERROR);
} else {
scsi_read_complete((void*)r, 0);
}
}
} else {
ret = (int)hdimage->lseek(r->sector * 512, SEEK_SET);
@ -511,7 +527,7 @@ Bit8u* scsi_device_t::scsi_get_buf(Bit32u tag)
return r->dma_buf;
}
Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun, bx_bool async)
{
Bit64u nb_sectors;
Bit64u lba;
@ -854,6 +870,7 @@ Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
goto illegal_lba;
r->sector = lba;
r->sector_count = len;
r->async_supported = async;
break;
case 0x0a:
case 0x2a:
@ -989,26 +1006,70 @@ void scsi_device_t::set_inserted(bx_bool value)
inserted = value;
if (inserted) {
max_lba = cdrom->capacity() - 1;
curr_lba = max_lba;
} else {
max_lba = 0;
}
}
void scsi_device_t::start_seek(SCSIRequest *r)
{
Bit64s new_pos, prev_pos, max_pos;
Bit32u seek_time;
double fSeekBase, fSeekTime;
max_pos = max_lba;
prev_pos = curr_lba;
new_pos = r->sector + r->sector_count;
if (type == SCSIDEV_TYPE_CDROM) {
fSeekBase = 80000.0;
} else {
fSeekBase = 5000.0;
}
fSeekTime = fSeekBase * (double)abs((int)(new_pos - prev_pos + 1)) / (max_pos + 1);
seek_time = (fSeekTime > 10.0) ? (Bit32u)fSeekTime : 10;
bx_pc_system.activate_timer(seek_timer_index, seek_time, 0);
bx_pc_system.setTimerParam(seek_timer_index, r->tag);
r->seek_active = 1;
}
void scsi_device_t::seek_timer_handler(void *this_ptr)
{
scsi_device_t *class_ptr = (scsi_device_t *) this_ptr;
class_ptr->seek_timer();
}
void scsi_device_t::seek_timer()
{
Bit32u i, n, tag = bx_pc_system.triggeredTimerParam();
SCSIRequest *r = scsi_find_request(tag);
int ret = 0;
n = r->sector_count;
if (n > (Bit32u)(SCSI_DMA_BUF_SIZE / (512 * cluster_size)))
n = SCSI_DMA_BUF_SIZE / (512 * cluster_size);
if (type == SCSIDEV_TYPE_CDROM) {
i = 0;
curr_lba = r->sector;
do {
ret = (int)cdrom->read_block(r->dma_buf + (i * 2048), (Bit32u)(r->sector + i), 2048);
curr_lba++;
} while ((++i < n) && (ret == 1));
if (ret == 0) {
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_MEDIUM_ERROR);
} else {
scsi_read_complete((void*)r, 0);
}
r->sector += n;
r->sector_count -= n;
r->seek_active = 0;
}
}
// Turn on BX_DEBUG messages at connection time
void scsi_device_t::set_debug_mode()
{
setonoff(LOGLEV_DEBUG, ACT_REPORT);
}
void scsi_device_t::seek_timer()
{
// TODO
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB

View File

@ -61,6 +61,8 @@ typedef struct SCSIRequest {
int buf_len;
Bit8u *dma_buf;
Bit32u status;
bx_bool async_supported;
bx_bool seek_active;
struct SCSIRequest *next;
} SCSIRequest;
@ -74,7 +76,7 @@ public:
virtual ~scsi_device_t(void);
void register_state(bx_list_c *parent, const char *name);
Bit32s scsi_send_command(Bit32u tag, Bit8u *buf, int lun);
Bit32s scsi_send_command(Bit32u tag, Bit8u *buf, int lun, bx_bool async);
void scsi_command_complete(SCSIRequest *r, int status, int sense);
void scsi_cancel_io(Bit32u tag);
void scsi_read_complete(void *req, int ret);
@ -87,7 +89,6 @@ public:
bx_bool get_inserted() {return inserted;}
bx_bool get_locked() {return locked;}
static void seek_timer_handler(void *);
void seek_timer(void);
bx_bool save_requests(const char *path);
void restore_requests(const char *path);
void set_debug_mode();
@ -98,12 +99,16 @@ protected:
SCSIRequest *scsi_find_request(Bit32u tag);
private:
void start_seek(SCSIRequest *r);
void seek_timer(void);
enum scsidev_type type;
device_image_t *hdimage;
cdrom_base_c *cdrom;
SCSIRequest *requests;
int cluster_size;
Bit64u max_lba;
Bit64u curr_lba;
int sense;
int tcq;
scsi_completionfn completion;

View File

@ -117,6 +117,10 @@
// USB 3.0
#define USB_DT_BIN_DEV_OBJ_STORE 0x0F
typedef struct USBPacket USBPacket;
typedef void USBCallback(USBPacket *packet, void *dev);
class usb_device_c;
struct USBPacket {
@ -125,6 +129,8 @@ struct USBPacket {
Bit8u devep;
Bit8u *data;
int len;
USBCallback *complete_cb;
void *complete_dev;
usb_device_c *dev;
};
@ -213,4 +219,9 @@ static BX_CPP_INLINE void usb_cancel_packet(USBPacket *p)
p->dev->cancel_packet(p);
}
static BX_CPP_INLINE void usb_packet_complete(USBPacket *p)
{
p->complete_cb(p, p->complete_dev);
}
#endif

View File

@ -615,6 +615,7 @@ int usb_msd_device_c::handle_data(USBPacket *p)
Bit8u devep = p->devep;
Bit8u *data = p->data;
int len = p->len;
bx_bool async = (p->complete_cb != NULL);
switch (p->pid) {
case USB_TOKEN_OUT:
@ -646,7 +647,7 @@ int usb_msd_device_c::handle_data(USBPacket *p)
BX_DEBUG(("command tag 0x%X flags %08X len %d data %d",
s.tag, cbw.flags, cbw.cmd_len, s.data_len));
s.residue = 0;
s.scsi_dev->scsi_send_command(s.tag, cbw.cmd, cbw.lun);
s.scsi_dev->scsi_send_command(s.tag, cbw.cmd, cbw.lun, async);
if (s.residue == 0) {
if (s.mode == USB_MSDM_DATAIN) {
if (s.scsi_dev->scsi_read_data(s.tag)) {
@ -841,6 +842,7 @@ void usb_msd_device_c::command_complete(int reason, Bit32u tag, Bit32u arg)
s.mode = USB_MSDM_CSW;
}
s.packet = NULL;
usb_packet_complete(p);
} else if (s.data_len == 0) {
s.mode = USB_MSDM_CSW;
}
@ -853,6 +855,7 @@ void usb_msd_device_c::command_complete(int reason, Bit32u tag, Bit32u arg)
if (s.usb_len == 0) {
BX_INFO(("packet complete %p", p));
s.packet = NULL;
usb_packet_complete(p);
}
}
}

View File

@ -174,7 +174,7 @@ void bx_usb_ohci_c::init(void)
return;
}
BX_OHCI_THIS device_buffer = new Bit8u[65536];
BX_OHCI_THIS device_buffer = new Bit8u[8192];
// Call our frame timer routine every 1mS (1,000uS)
// Continuous and active
@ -371,6 +371,11 @@ void bx_usb_ohci_c::reset_hc()
usb_set_connect_status(i, BX_OHCI_THIS hub.usb_port[i].device->get_type(), 1);
}
}
if (BX_OHCI_THIS hub.async_td) {
usb_cancel_packet(&BX_OHCI_THIS usb_packet);
BX_OHCI_THIS hub.async_td = 0;
}
}
void bx_usb_ohci_c::reset_port(int p)
@ -471,6 +476,8 @@ void bx_usb_ohci_c::register_state(void)
new bx_shadow_bool_c(hub, "use_control_head", &BX_OHCI_THIS hub.use_control_head);
new bx_shadow_bool_c(hub, "use_bulk_head", &BX_OHCI_THIS hub.use_bulk_head);
new bx_shadow_num_c(hub, "sof_time", &BX_OHCI_THIS hub.sof_time);
new bx_shadow_num_c(hub, "async_td", &BX_OHCI_THIS hub.async_td);
new bx_shadow_bool_c(hub, "async_complete", &BX_OHCI_THIS hub.async_complete);
register_pci_state(hub);
}
@ -1078,55 +1085,8 @@ void bx_usb_ohci_c::usb_frame_timer(void)
if ((BX_OHCI_THIS hub.ohci_done_count != 7) && (BX_OHCI_THIS hub.ohci_done_count > 0))
BX_OHCI_THIS hub.ohci_done_count--;
// TODO: Rather than just comparing .fr to <8000 here, and <4000 below, see the highlighted
// statement on page 45.
BX_OHCI_THIS process_lists();
// if the control list is enabled *and* the control list filled bit is set, do a control list ED
if (BX_OHCI_THIS hub.op_regs.HcControl.cle) {
if (BX_OHCI_THIS hub.use_control_head) {
BX_OHCI_THIS hub.op_regs.HcControlCurrentED = 0;
BX_OHCI_THIS hub.use_control_head = 0;
}
if (!BX_OHCI_THIS hub.op_regs.HcControlCurrentED && BX_OHCI_THIS hub.op_regs.HcCommandStatus.clf) {
BX_OHCI_THIS hub.op_regs.HcControlCurrentED = BX_OHCI_THIS hub.op_regs.HcControlHeadED;
BX_OHCI_THIS hub.op_regs.HcCommandStatus.clf = 0;
}
while (BX_OHCI_THIS hub.op_regs.HcControlCurrentED) {
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED, 4, (Bit8u*) &cur_ed.dword0);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED + 4, 4, (Bit8u*) &cur_ed.dword1);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED + 8, 4, (Bit8u*) &cur_ed.dword2);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED + 12, 4, (Bit8u*) &cur_ed.dword3);
process_ed(&cur_ed, BX_OHCI_THIS hub.op_regs.HcControlCurrentED);
BX_OHCI_THIS hub.op_regs.HcControlCurrentED = ED_GET_NEXTED(&cur_ed);
if (get_frame_remaining() < 8000)
goto do_bulk_eds;
}
}
do_bulk_eds:
// if the bulk list is enabled *and* the bulk list filled bit is set, do a bulk list ED
if (BX_OHCI_THIS hub.op_regs.HcControl.ble) {
if (BX_OHCI_THIS hub.use_bulk_head) {
BX_OHCI_THIS hub.op_regs.HcBulkCurrentED = 0;
BX_OHCI_THIS hub.use_bulk_head = 0;
}
if (!BX_OHCI_THIS hub.op_regs.HcBulkCurrentED && BX_OHCI_THIS hub.op_regs.HcCommandStatus.blf) {
BX_OHCI_THIS hub.op_regs.HcBulkCurrentED = BX_OHCI_THIS hub.op_regs.HcBulkHeadED;
BX_OHCI_THIS hub.op_regs.HcCommandStatus.blf = 0;
}
while (BX_OHCI_THIS hub.op_regs.HcBulkCurrentED) {
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED, 4, (Bit8u*) &cur_ed.dword0);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED + 4, 4, (Bit8u*) &cur_ed.dword1);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED + 8, 4, (Bit8u*) &cur_ed.dword2);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED + 12, 4, (Bit8u*) &cur_ed.dword3);
process_ed(&cur_ed, BX_OHCI_THIS hub.op_regs.HcBulkCurrentED);
BX_OHCI_THIS hub.op_regs.HcBulkCurrentED = ED_GET_NEXTED(&cur_ed);
if (get_frame_remaining() < 4000)
goto do_iso_eds;
}
}
do_iso_eds:
// do the ED's in the interrupt table
if (BX_OHCI_THIS hub.op_regs.HcControl.ple) {
address = BX_OHCI_THIS hub.op_regs.HcHCCA + ((BX_OHCI_THIS hub.op_regs.HcFmNumber & 0x1F) * 4);
@ -1144,6 +1104,58 @@ do_iso_eds:
} // end run schedule
}
void bx_usb_ohci_c::process_lists(void)
{
struct OHCI_ED cur_ed;
// TODO: Rather than just comparing .fr to <8000 here, and <4000 below, see the highlighted
// statement on page 45.
// if the control list is enabled *and* the control list filled bit is set, do a control list ED
if (BX_OHCI_THIS hub.op_regs.HcControl.cle) {
if (BX_OHCI_THIS hub.use_control_head) {
BX_OHCI_THIS hub.op_regs.HcControlCurrentED = 0;
BX_OHCI_THIS hub.use_control_head = 0;
}
if (!BX_OHCI_THIS hub.op_regs.HcControlCurrentED && BX_OHCI_THIS hub.op_regs.HcCommandStatus.clf) {
BX_OHCI_THIS hub.op_regs.HcControlCurrentED = BX_OHCI_THIS hub.op_regs.HcControlHeadED;
BX_OHCI_THIS hub.op_regs.HcCommandStatus.clf = 0;
}
while (BX_OHCI_THIS hub.op_regs.HcControlCurrentED) {
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED, 4, (Bit8u*) &cur_ed.dword0);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED + 4, 4, (Bit8u*) &cur_ed.dword1);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED + 8, 4, (Bit8u*) &cur_ed.dword2);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcControlCurrentED + 12, 4, (Bit8u*) &cur_ed.dword3);
process_ed(&cur_ed, BX_OHCI_THIS hub.op_regs.HcControlCurrentED);
BX_OHCI_THIS hub.op_regs.HcControlCurrentED = ED_GET_NEXTED(&cur_ed);
if (get_frame_remaining() < 8000)
break;
}
}
// if the bulk list is enabled *and* the bulk list filled bit is set, do a bulk list ED
if (BX_OHCI_THIS hub.op_regs.HcControl.ble) {
if (BX_OHCI_THIS hub.use_bulk_head) {
BX_OHCI_THIS hub.op_regs.HcBulkCurrentED = 0;
BX_OHCI_THIS hub.use_bulk_head = 0;
}
if (!BX_OHCI_THIS hub.op_regs.HcBulkCurrentED && BX_OHCI_THIS hub.op_regs.HcCommandStatus.blf) {
BX_OHCI_THIS hub.op_regs.HcBulkCurrentED = BX_OHCI_THIS hub.op_regs.HcBulkHeadED;
BX_OHCI_THIS hub.op_regs.HcCommandStatus.blf = 0;
}
while (BX_OHCI_THIS hub.op_regs.HcBulkCurrentED) {
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED, 4, (Bit8u*) &cur_ed.dword0);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED + 4, 4, (Bit8u*) &cur_ed.dword1);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED + 8, 4, (Bit8u*) &cur_ed.dword2);
DEV_MEM_READ_PHYSICAL(BX_OHCI_THIS hub.op_regs.HcBulkCurrentED + 12, 4, (Bit8u*) &cur_ed.dword3);
process_ed(&cur_ed, BX_OHCI_THIS hub.op_regs.HcBulkCurrentED);
BX_OHCI_THIS hub.op_regs.HcBulkCurrentED = ED_GET_NEXTED(&cur_ed);
if (get_frame_remaining() < 4000)
break;
}
}
}
void bx_usb_ohci_c::process_ed(struct OHCI_ED *ed, const Bit32u ed_address)
{
struct OHCI_TD cur_td;
@ -1184,10 +1196,35 @@ void bx_usb_ohci_c::process_ed(struct OHCI_ED *ed, const Bit32u ed_address)
}
}
void ohci_async_complete_packet(USBPacket *packet, void *dev)
{
((bx_usb_ohci_c*)dev)->async_complete_packet(packet);
}
void bx_usb_ohci_c::async_complete_packet(USBPacket *packet)
{
BX_INFO(("Experimental async packet completion"));
BX_OHCI_THIS hub.async_complete = 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;
BX_OHCI_THIS hub.op_regs.HcCommandStatus.blf = 1;
BX_OHCI_THIS hub.op_regs.HcCommandStatus.clf = 1;
BX_OHCI_THIS process_lists();
}
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;
bx_bool completion;
addr = ED_GET_HEADP(ed);
completion = (addr == BX_OHCI_THIS hub.async_td);
if (completion && !BX_OHCI_THIS hub.async_complete) {
return 0;
}
// The td->cc field should be 111x if it hasn't been processed yet.
if (TD_GET_CC(td) < NotAccessed) {
@ -1222,62 +1259,75 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
} else
len = 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;
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);
break;
case USB_TOKEN_IN:
BX_OHCI_THIS usb_packet.len = len;
break;
if (completion) {
ret = BX_OHCI_THIS usb_packet.len;
BX_OHCI_THIS hub.async_td = 0;
BX_OHCI_THIS hub.async_complete = 0;
} else {
if (BX_OHCI_THIS hub.async_td) {
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);
break;
case USB_TOKEN_IN:
BX_OHCI_THIS usb_packet.len = len;
break;
}
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",
ED_GET_FA(ed), ED_GET_EN(ed), len, ED_GET_MPS(ed), TD_GET_CBP(td), TD_GET_BE(td)));
BX_DEBUG((" td->t = %i ed->c = %i td->di = %i td->r = %i", TD_GET_T(td), ED_GET_C(ed), TD_GET_DI(td), TD_GET_R(td)));
switch (pid) {
case USB_TOKEN_SETUP:
if (len > 0)
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, device_buffer);
// 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)
ret = 8;
break;
case USB_TOKEN_OUT:
if (len > 0)
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, device_buffer);
ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
break;
case USB_TOKEN_IN:
ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
break;
default:
TD_SET_CC(td, UnexpectedPID);
TD_SET_EC(td, 3);
return 1;
}
if (ret == USB_RET_ASYNC) {
BX_OHCI_THIS hub.async_td = addr;
BX_INFO(("Experimental async packet handling"));
return 0;
}
}
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",
ED_GET_FA(ed), ED_GET_EN(ed), len, ED_GET_MPS(ed), TD_GET_CBP(td), TD_GET_BE(td)));
BX_DEBUG((" td->t = %i ed->c = %i td->di = %i td->r = %i", TD_GET_T(td), ED_GET_C(ed), TD_GET_DI(td), TD_GET_R(td)));
switch (pid) {
case USB_TOKEN_SETUP:
if (len > 0)
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, device_buffer);
// 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)
ret = 8;
break;
case USB_TOKEN_OUT:
if (len > 0)
DEV_MEM_READ_PHYSICAL_DMA(TD_GET_CBP(td), len, device_buffer);
ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
break;
case USB_TOKEN_IN:
ret = BX_OHCI_THIS broadcast_packet(&BX_OHCI_THIS usb_packet);
if (ret > 0) {
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);
} else {
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), ret, device_buffer);
}
}
break;
default:
TD_SET_CC(td, UnexpectedPID);
TD_SET_EC(td, 3);
return 1;
if ((ret > 0) && (pid == USB_TOKEN_IN)) {
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);
} else {
DEV_MEM_WRITE_PHYSICAL_DMA(TD_GET_CBP(td), ret, device_buffer);
}
}
if (ret == USB_RET_ASYNC) {
BX_ERROR(("Async packet handling not implemented yet"));
}
if ((ret == (int)len) || ((pid == USB_TOKEN_IN) && (ret >= 0) &&
TD_GET_R(td)) || ((pid == USB_TOKEN_OUT) && (ret >= 0) &&
(ret <= (int) ED_GET_MPS(ed)))) {
@ -1317,9 +1367,6 @@ bx_bool bx_usb_ohci_c::process_td(struct OHCI_TD *td, struct OHCI_ED *ed)
case USB_RET_BABBLE: // (-4)
TD_SET_CC(td, BufferOverrun);
break;
case USB_RET_ASYNC: // (-5)
TD_SET_CC(td, BufferOverrun);
break;
default:
BX_ERROR(("Unknown error returned: %i", ret));
break;

View File

@ -235,6 +235,8 @@ 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;
@ -253,6 +255,8 @@ public:
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
void async_complete_packet(USBPacket *packet);
static const char *usb_param_handler(bx_param_string_c *param, int set,
const char *oldval, const char *val, int maxlen);
@ -278,6 +282,7 @@ private:
static Bit32u get_frame_remaining(void);
void process_lists();
void process_ed(struct OHCI_ED *, const Bit32u);
bx_bool process_td(struct OHCI_TD *, struct OHCI_ED *);

View File

@ -921,6 +921,8 @@ bx_bool bx_usb_uhci_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *t
BX_UHCI_THIS usb_packet.devep = endpt;
BX_UHCI_THIS usb_packet.data = device_buffer;
BX_UHCI_THIS usb_packet.len = maxlen;
BX_UHCI_THIS usb_packet.complete_cb = NULL;
BX_UHCI_THIS usb_packet.complete_dev = this;
switch (pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:

View File

@ -2007,6 +2007,8 @@ void bx_usb_xhci_c::process_transfer_ring(const int slot, const int ep)
packet.devep = (ep >> 1);
packet.data = BX_XHCI_THIS device_buffer;
packet.len = transfer_length;
packet.complete_cb = NULL;
packet.complete_dev = BX_XHCI_THIS_PTR;
switch (cur_direction) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
@ -2818,6 +2820,8 @@ int bx_usb_xhci_c::send_set_address(const int addr, const int port_num)
packet.devaddr = 0; // default address
packet.len = 8;
packet.data = setup_address;
packet.complete_cb = NULL;
packet.complete_dev = BX_XHCI_THIS_PTR;
ret = BX_XHCI_THIS broadcast_packet(&packet, port_num);
if (ret == 0) {
packet.pid = USB_TOKEN_IN;