diff --git a/bochs/iodev/usb/scsi_device.cc b/bochs/iodev/usb/scsi_device.cc index 4e52b1044..f7578cfb3 100644 --- a/bochs/iodev/usb/scsi_device.cc +++ b/bochs/iodev/usb/scsi_device.cc @@ -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 diff --git a/bochs/iodev/usb/scsi_device.h b/bochs/iodev/usb/scsi_device.h index b64e48445..e55c00f49 100644 --- a/bochs/iodev/usb/scsi_device.h +++ b/bochs/iodev/usb/scsi_device.h @@ -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; diff --git a/bochs/iodev/usb/usb_common.h b/bochs/iodev/usb/usb_common.h index 2d8bceae3..3b36c4fef 100644 --- a/bochs/iodev/usb/usb_common.h +++ b/bochs/iodev/usb/usb_common.h @@ -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 diff --git a/bochs/iodev/usb/usb_msd.cc b/bochs/iodev/usb/usb_msd.cc index e505c1743..029a00e50 100644 --- a/bochs/iodev/usb/usb_msd.cc +++ b/bochs/iodev/usb/usb_msd.cc @@ -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); } } } diff --git a/bochs/iodev/usb/usb_ohci.cc b/bochs/iodev/usb/usb_ohci.cc index 59a85ad21..772214b3f 100644 --- a/bochs/iodev/usb/usb_ohci.cc +++ b/bochs/iodev/usb/usb_ohci.cc @@ -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; diff --git a/bochs/iodev/usb/usb_ohci.h b/bochs/iodev/usb/usb_ohci.h index 4fed17743..07a740e00 100644 --- a/bochs/iodev/usb/usb_ohci.h +++ b/bochs/iodev/usb/usb_ohci.h @@ -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 *); diff --git a/bochs/iodev/usb/usb_uhci.cc b/bochs/iodev/usb/usb_uhci.cc index 678302384..96c3b3393 100644 --- a/bochs/iodev/usb/usb_uhci.cc +++ b/bochs/iodev/usb/usb_uhci.cc @@ -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: diff --git a/bochs/iodev/usb/usb_xhci.cc b/bochs/iodev/usb/usb_xhci.cc index dcd415b3c..f501156da 100644 --- a/bochs/iodev/usb/usb_xhci.cc +++ b/bochs/iodev/usb/usb_xhci.cc @@ -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;