usb: Start implementing Endpoint/Transfer descriptor parsing
This commit is contained in:
@@ -50,9 +50,8 @@ typedef struct usb_t
|
||||
uint32_t ohci_mem_base, irq_level;
|
||||
mem_mapping_t ohci_mmio_mapping;
|
||||
pc_timer_t ohci_frame_timer;
|
||||
pc_timer_t ohci_interrupt_desc_poll_timer;
|
||||
pc_timer_t ohci_port_reset_timer[2];
|
||||
uint8_t ohci_interrupt_counter : 5;
|
||||
uint8_t ohci_interrupt_counter : 3;
|
||||
|
||||
usb_params_t* usb_params;
|
||||
} usb_t;
|
||||
@@ -80,32 +79,6 @@ typedef struct
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t HccaInterrruptTable[32];
|
||||
uint16_t HccaFrameNumber;
|
||||
uint16_t HccaPad1;
|
||||
uint32_t HccaDoneHead;
|
||||
} usb_hcca_t;
|
||||
|
||||
/* Transfer descriptors */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Control;
|
||||
uint32_t CBP;
|
||||
uint32_t NextTD;
|
||||
uint32_t BE;
|
||||
} usb_td_t;
|
||||
|
||||
/* Endpoint descriptors */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Control;
|
||||
uint32_t TailP;
|
||||
uint32_t HeadP;
|
||||
uint32_t NextED;
|
||||
} usb_ed_t;
|
||||
|
||||
/* USB endpoint device struct. Incomplete and unused. */
|
||||
typedef struct
|
||||
{
|
||||
|
141
src/usb.c
141
src/usb.c
@@ -20,6 +20,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
@@ -117,6 +118,16 @@ enum
|
||||
OHCI_HcInterruptEnable_RHSC = 1 << 6,
|
||||
};
|
||||
|
||||
/* OHCI HcControl bits */
|
||||
enum
|
||||
{
|
||||
OHCI_HcControl_ControlBulkServiceRatio = 1 << 0,
|
||||
OHCI_HcControl_PeriodicListEnable = 1 << 1,
|
||||
OHCI_HcControl_IsochronousEnable = 1 << 2,
|
||||
OHCI_HcControl_ControlListEnable = 1 << 3,
|
||||
OHCI_HcControl_BulkListEnable = 1 << 4
|
||||
};
|
||||
|
||||
static void
|
||||
usb_interrupt_ohci(usb_t *dev, uint32_t level)
|
||||
{
|
||||
@@ -216,6 +227,69 @@ uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable)
|
||||
io_sethandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t HccaInterrruptTable[32];
|
||||
uint16_t HccaFrameNumber;
|
||||
uint16_t HccaPad1;
|
||||
uint32_t HccaDoneHead;
|
||||
} usb_hcca_t;
|
||||
|
||||
/* Transfer descriptors */
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t Control;
|
||||
struct
|
||||
{
|
||||
uint32_t Reserved : 18;
|
||||
uint8_t bufferRounding : 1;
|
||||
uint8_t Direction : 2;
|
||||
uint8_t DelayInterrupt : 3;
|
||||
uint8_t DataToggle : 2;
|
||||
uint8_t ErrorCount : 2;
|
||||
uint8_t ConditionCode : 4;
|
||||
} flags;
|
||||
};
|
||||
uint32_t CBP;
|
||||
uint32_t NextTD;
|
||||
uint32_t BE;
|
||||
} usb_td_t;
|
||||
|
||||
/* Endpoint descriptors */
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t Control;
|
||||
struct
|
||||
{
|
||||
uint8_t FunctionAddress : 7;
|
||||
uint8_t EndpointNumber : 4;
|
||||
uint8_t Direction : 2;
|
||||
bool Speed : 1;
|
||||
bool Skip : 1;
|
||||
bool Format : 1;
|
||||
uint16_t MaximumPacketSize : 11;
|
||||
uint8_t Reserved : 5;
|
||||
} flags;
|
||||
};
|
||||
uint32_t TailP;
|
||||
union
|
||||
{
|
||||
uint32_t HeadP;
|
||||
struct
|
||||
{
|
||||
bool Halted : 1;
|
||||
bool toggleCarry : 1;
|
||||
} flags_2;
|
||||
};
|
||||
uint32_t NextED;
|
||||
} usb_ed_t;
|
||||
|
||||
#define ENDPOINT_DESC_LIMIT 32
|
||||
|
||||
static uint8_t
|
||||
ohci_mmio_read(uint32_t addr, void *p)
|
||||
{
|
||||
@@ -297,6 +371,14 @@ ohci_set_interrupt(usb_t *dev, uint8_t bit)
|
||||
ohci_update_irq(dev);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ohci_service_endpoint_desc(usb_t* dev, uint32_t head)
|
||||
{
|
||||
usb_ed_t endpoint_desc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ohci_end_of_frame(usb_t* dev)
|
||||
{
|
||||
@@ -304,7 +386,49 @@ ohci_end_of_frame(usb_t* dev)
|
||||
/* TODO: Put endpoint and transfer descriptor processing here. */
|
||||
dma_bm_read(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4);
|
||||
|
||||
if (dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_PeriodicListEnable) {
|
||||
ohci_service_endpoint_desc(dev, hcca.HccaInterrruptTable[dev->ohci_mmio[OHCI_HcFmNumber].l & 0x1f]);
|
||||
}
|
||||
|
||||
if ((dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_ControlListEnable)
|
||||
&& (dev->ohci_mmio[OHCI_HcCommandStatus].l & 0x2)) {
|
||||
uint8_t result = ohci_service_endpoint_desc(dev, dev->ohci_mmio[OHCI_HcControlHeadED].l);
|
||||
if (!result) {
|
||||
dev->ohci_mmio[OHCI_HcControlHeadED].l = 0;
|
||||
dev->ohci_mmio[OHCI_HcCommandStatus].l &= ~0x2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_BulkListEnable)
|
||||
&& (dev->ohci_mmio[OHCI_HcCommandStatus].l & 0x4)) {
|
||||
uint8_t result = ohci_service_endpoint_desc(dev, dev->ohci_mmio[OHCI_HcBulkHeadED].l);
|
||||
if (!result) {
|
||||
dev->ohci_mmio[OHCI_HcBulkHeadED].l = 0;
|
||||
dev->ohci_mmio[OHCI_HcCommandStatus].l &= ~0x4;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->ohci_interrupt_counter == 0 && !(dev->ohci_mmio[OHCI_HcInterruptStatus].l & OHCI_HcInterruptEnable_WDH)) {
|
||||
if (dev->ohci_mmio[OHCI_HcDoneHead].l == 0) {
|
||||
fatal("OHCI: HcDoneHead is still NULL!");
|
||||
}
|
||||
|
||||
if (dev->ohci_mmio[OHCI_HcInterruptStatus].l & dev->ohci_mmio[OHCI_HcInterruptEnable].l) {
|
||||
dev->ohci_mmio[OHCI_HcDoneHead].l |= 1;
|
||||
}
|
||||
|
||||
hcca.HccaDoneHead = dev->ohci_mmio[OHCI_HcDoneHead].l;
|
||||
dev->ohci_mmio[OHCI_HcDoneHead].l = 0;
|
||||
dev->ohci_interrupt_counter = 7;
|
||||
ohci_set_interrupt(dev, OHCI_HcInterruptEnable_WDH);
|
||||
}
|
||||
|
||||
if (dev->ohci_interrupt_counter != 0 && dev->ohci_interrupt_counter != 7) {
|
||||
dev->ohci_interrupt_counter--;
|
||||
}
|
||||
|
||||
dev->ohci_mmio[OHCI_HcFmNumber].w[0]++;
|
||||
hcca.HccaFrameNumber = dev->ohci_mmio[OHCI_HcFmNumber].w[0];
|
||||
|
||||
dma_bm_write(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4);
|
||||
}
|
||||
@@ -327,21 +451,11 @@ ohci_update_frame_counter(void* priv)
|
||||
dev->ohci_mmio[OHCI_HcFmRemaining].l &= ~(1 << 31);
|
||||
dev->ohci_mmio[OHCI_HcFmRemaining].l |= dev->ohci_mmio[OHCI_HcFmInterval].l & (1 << 31);
|
||||
ohci_start_of_frame(dev);
|
||||
timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.));
|
||||
timer_on_auto(&dev->ohci_frame_timer, 1. / 12.);
|
||||
return;
|
||||
}
|
||||
if (dev->ohci_mmio[OHCI_HcFmRemaining].w[0]) dev->ohci_mmio[OHCI_HcFmRemaining].w[0]--;
|
||||
timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.));
|
||||
}
|
||||
|
||||
void
|
||||
ohci_poll_interrupt_descriptors(void* priv)
|
||||
{
|
||||
usb_t *dev = (usb_t *) priv;
|
||||
|
||||
/* TODO: Actually poll the interrupt descriptors. */
|
||||
|
||||
timer_on_auto(&dev->ohci_interrupt_desc_poll_timer, 1000.);
|
||||
dev->ohci_mmio[OHCI_HcFmRemaining].w[0]--;
|
||||
timer_on_auto(&dev->ohci_frame_timer, 1. / 12.);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -694,7 +808,6 @@ usb_init_ext(const device_t *info, void *params)
|
||||
timer_add(&dev->ohci_frame_timer, ohci_update_frame_counter, dev, 0); /* Unused for now, to be used for frame counting. */
|
||||
timer_add(&dev->ohci_port_reset_timer[0], ohci_port_reset_callback, dev, 0);
|
||||
timer_add(&dev->ohci_port_reset_timer[1], ohci_port_reset_callback_2, dev, 0);
|
||||
timer_add(&dev->ohci_interrupt_desc_poll_timer, ohci_poll_interrupt_descriptors, dev, 0);
|
||||
|
||||
usb_reset(dev);
|
||||
|
||||
|
Reference in New Issue
Block a user