Skip to content

Commit

Permalink
OHCI Isochronous transfers now work
Browse files Browse the repository at this point in the history
UHCI Isochronous transfers do not work as intended
  • Loading branch information
Cacodemon345 committed Dec 14, 2024
1 parent 6214d98 commit bf6d98f
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 15 deletions.
14 changes: 10 additions & 4 deletions src/usb/usb_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static const uint8_t bx_audio_config_descriptor[] =
0x24, /* u8 bDescriptor Type (CS_INTERFACE); */
0x01, /* u8 bDescriptorSubType (HEADER); */
0x00, 0x01, /* u16 bcdADC; */
0x09 + 0x0c + 0x0d + 0x09, 0x00, /* u16 wTotalLength; */
0x09 + 0x0c + 0x09 + 0x09, 0x00, /* u16 wTotalLength; */
0x01, /* u8 bInCollection; */
0x01, /* u8 baInterfaceNr; */

Expand Down Expand Up @@ -165,7 +165,7 @@ static const uint8_t bx_audio_config_descriptor[] =
0x25, /* u8 bDescriptorType; */
0x01, /* u8 bDescriptorSubtype; */
// Reminder to ask the host to pad packets if this is not sufficient enough.
0x00, /* u8 bmAttributes; */
0x80, /* u8 bmAttributes; */
0x00, /* u8 bLockDelayUnits; */
0x00, 0x00 /* u16 wLockDelay; */
};
Expand Down Expand Up @@ -232,6 +232,7 @@ usb_device_audio_handle_data(usb_device_c *device, USBPacket *p)
// Null packets must be accepted as well.
if (p->len > 0)
fifo8_push_all(&usb_audio->audio_buf, p->data, p->len);
ret = p->len;
}
else
{
Expand Down Expand Up @@ -263,6 +264,8 @@ usb_device_audio_handle_iface_change(usb_device_c* device, int iface)
usb_device_audio* usb_audio = (usb_device_audio*) device->priv;

usb_audio->alt_iface_enabled = !!iface;
if (usb_audio->alt_iface_enabled == 0)
fifo8_drop(&usb_audio->audio_buf, fifo8_num_used(&usb_audio->audio_buf));
}

/*
Expand Down Expand Up @@ -406,6 +409,8 @@ usb_audio_get_buffer(int32_t *buffer, int len, void *priv)

if (fifo8_num_used(&usb_audio->audio_buf) < (SOUNDBUFLEN * 2 * 2))
{
static int buffer_underrun = 0;
//pclog("USB Audio: Buffer underrun! (%d)\n", buffer_underrun++);
return;
}

Expand Down Expand Up @@ -433,7 +438,7 @@ usb_audio_device_create(const device_t *info)

usb_device_create(&usb_audio->device);
usb_audio->device.type = 0;
usb_audio->device.minspeed = USB_SPEED_LOW;
usb_audio->device.minspeed = USB_SPEED_FULL;
usb_audio->device.maxspeed = USB_SPEED_FULL;
usb_audio->device.speed = usb_audio->device.minspeed;
usb_audio->device.priv = usb_audio;
Expand All @@ -453,6 +458,7 @@ usb_audio_device_create(const device_t *info)
usb_audio->device.endpoint_info[1].max_burst_size = 0;
usb_audio->device.connected = true;
usb_audio->device.iface_alt = 1;
usb_audio->device.alt_iface_max = 1;

usb_audio->device.handle_iface_change = usb_device_audio_handle_iface_change;
usb_audio->device.handle_control = usb_device_audio_handle_control;
Expand All @@ -464,7 +470,7 @@ usb_audio_device_create(const device_t *info)
return NULL;
}

fifo8_create(&usb_audio->audio_buf, 65536);
fifo8_create(&usb_audio->audio_buf, 65536 * 4);

sound_add_handler(usb_audio_get_buffer, usb_audio);
return usb_audio;
Expand Down
5 changes: 3 additions & 2 deletions src/usb/usb_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ int usb_device_handle_control_common(usb_device_c* device, int request, int valu
BX_DEBUG(("USB_REQ_GET_INTERFACE:"));
// with InterfaceRequest, the wValue field must be zero and wLength field must be 1
if ((value != device->iface_alt) || (length != 1)) {
//BX_ERROR(("USB_REQ_GET_INTERFACE: This type of request requires the wValue field to be zero and wLength field to be one."));
BX_ERROR(("USB_REQ_GET_INTERFACE: This type of request requires the wValue field to be zero and wLength field to be one."));
}
// all our devices only have one interface, and that value must be zero
// if we ever add a device that has more than one interface (a video cam ?), we will need to modify this
Expand All @@ -377,7 +377,7 @@ int usb_device_handle_control_common(usb_device_c* device, int request, int valu
BX_DEBUG(("USB_REQ_SET_INTERFACE: value=%d", value));
// with InterfaceRequest, the wIndex and wLength fields must be zero
if ((index != device->iface_alt) || (length != 0)) {
//BX_ERROR(("USB_REQ_SET_INTERFACE: This type of request requires the wIndex and wLength fields to be zero."));
BX_ERROR(("USB_REQ_SET_INTERFACE: This type of request requires the wIndex and wLength fields to be zero."));
}
// all our devices only have one interface, and that value must be zero
// if we ever add a device that has more than one interface (a video cam ?), we will need to modify this
Expand Down Expand Up @@ -674,6 +674,7 @@ int usb_device_handle_packet(usb_device_c* device, USBPacket *p)
ret = USB_RET_STALL;
break;
}
//pclog("ret = %d\n", ret);
return ret;
}

Expand Down
25 changes: 17 additions & 8 deletions src/usb/usb_ohci_bochs.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ ohci_log(const char *fmt, ...)

if (ohci_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
ohci_log_ex(fmt, ap);
va_end(ap);
}
}
Expand All @@ -305,7 +305,7 @@ ohci_log(const char *fmt, ...)
#define BX_ERROR(x) ohci_log x ; ohci_log ("\n")
#define BX_INFO(x) ohci_log x ; ohci_log ("\n")
#define BX_DEBUG(x) ohci_log x ; ohci_log ("\n")
#define BX_PANIC(x) fatal x ; pclog ("\n")
#define BX_PANIC(x) fatal x ; ohci_log ("\n")

#define DEV_MEM_WRITE_PHYSICAL(addr, size, data) dma_bm_write(addr, (uint8_t*)data, size, 4);
#define DEV_MEM_READ_PHYSICAL(addr, size, data) dma_bm_read(addr, (uint8_t*)data, size, 4);
Expand Down Expand Up @@ -1312,17 +1312,20 @@ int usb_ohci_process_iso_td(bx_ohci_core_t* hub, struct OHCI_ISO_TD *td, struct
p = find_async_packet(&hub->packets, addr);
completion = (p != NULL);
if (completion && !p->done) {
return 0;
return 1;
}

starting_frame = ISO_TD_GET_SF(td);
frame_count = ISO_TD_GET_FC(td);
relative_frame_number = (int16_t)((uint16_t)(hub->op_regs.HcFmNumber) - (uint16_t)(starting_frame));

if (relative_frame_number < 0)
if (relative_frame_number < 0){
ohci_log("Relative frame number < 0\n");
return 1;
}
else if (relative_frame_number > frame_count) {
const uint32_t temp = ED_GET_HEADP(ed);
ohci_log("Relative frame number > Frame Count\n");
if (ISO_TD_GET_CC(td) == DataOverrun)
return 1;
else {
Expand All @@ -1340,13 +1343,15 @@ int usb_ohci_process_iso_td(bx_ohci_core_t* hub, struct OHCI_ISO_TD *td, struct
pid = USB_TOKEN_OUT;
else if (ED_GET_D(ed) == 2)
pid = USB_TOKEN_IN;
else if (ED_GET_D(ed) == 0)
else if (ED_GET_D(ed) == 0 || ED_GET_D(ed) == 3)
pid = USB_TOKEN_SETUP;
else
return 1;

if (ISO_TD_GET_BE(td) == 0 || ISO_TD_GET_BP0(td) == 0)
if (ISO_TD_GET_BE(td) == 0 || ISO_TD_GET_BP0(td) == 0) {
ohci_log("Zero-ed BE/BP0\n");
return 1;
}

start_offset = td->offset[relative_frame_number];
if (relative_frame_number < frame_count) {
Expand All @@ -1357,11 +1362,13 @@ int usb_ohci_process_iso_td(bx_ohci_core_t* hub, struct OHCI_ISO_TD *td, struct

if (!((start_offset >> 12) & 0xe) ||
((relative_frame_number < frame_count) &&
!((start_offset >> 12) & 0xe))) {
!((next_offset >> 12) & 0xe))) {
ohci_log("NOTACCESSED\n");
return 1;
}

if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
ohci_log("NOTACCESSED (2)\n");
return 1;
}

Expand All @@ -1388,6 +1395,7 @@ int usb_ohci_process_iso_td(bx_ohci_core_t* hub, struct OHCI_ISO_TD *td, struct
}

if (start_addr > end_addr) {
ohci_log("start_addr > end_addr\n");
return 1;
}

Expand Down Expand Up @@ -1459,6 +1467,7 @@ int usb_ohci_process_iso_td(bx_ohci_core_t* hub, struct OHCI_ISO_TD *td, struct
}

dma_bm_write(addr, (uint8_t*)td, sizeof(struct OHCI_ISO_TD), 4);
remove_async_packet(&hub->packets, p);
return 1;
}

Expand Down Expand Up @@ -1656,7 +1665,7 @@ bool usb_ohci_process_ed(bx_ohci_core_t* hub, struct OHCI_ED *ed, const uint32_t
if (ED_GET_F(ed)) {
if (hub->op_regs.HcControl.ie) {
// load and do a isochronous TD list
BX_DEBUG(("Found a valid ED that points to an isochronous TD"));
ohci_log("Found a valid ED that points to an isochronous TD\n");
while (!ED_GET_H(ed) && (ED_GET_HEADP(ed) != ED_GET_TAILP(ed))) {
dma_bm_read(ED_GET_HEADP(ed), (uint8_t*)&cur_iso_td, sizeof(struct OHCI_ISO_TD), 4);
if (usb_ohci_process_iso_td(hub, &cur_iso_td, ed))
Expand Down
7 changes: 6 additions & 1 deletion src/usb/usb_uhci_bochs.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* FIXME: Isochronous transfer work but cause massive problems in Windows 2000 and Windows 98 SE.*/

#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
Expand Down Expand Up @@ -202,7 +204,7 @@ const char *usb_speed[4] = {
"high", // USB_SPEED_HIGH = 2
"super" // USB_SPEED_SUPER = 3
};

#define ENABLE_UHCI_LOG 1
#ifdef ENABLE_UHCI_LOG
int uhci_do_log = ENABLE_UHCI_LOG;

Expand Down Expand Up @@ -653,6 +655,9 @@ usb_uhci_do_transfer(bx_uhci_core_t *hub, uint32_t address, struct TD *td)
BX_INFO(("UHCI Core: Reserved bit in the Link Pointer is not zero."));
}

if (td->dword1 & (1 << 25))
BX_INFO(("UHCI Core: Encountered Isochronous Packet.\n"));

// the device should remain in a stall state until the next setup packet is recieved
// For some reason, this doesn't work yet.
// if (dev && dev->in_stall && (pid != USB_TOKEN_SETUP))
Expand Down

0 comments on commit bf6d98f

Please sign in to comment.