Merge pull request #3306 from Cacodemon345/usb-work
usb: start hooking up USB interrupts to chipsets
This commit is contained in:
@@ -83,6 +83,8 @@ typedef struct sis_5571_t {
|
|||||||
smram_t *smram;
|
smram_t *smram;
|
||||||
usb_t *usb;
|
usb_t *usb;
|
||||||
|
|
||||||
|
usb_params_t usb_params;
|
||||||
|
|
||||||
} sis_5571_t;
|
} sis_5571_t;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -638,6 +640,36 @@ pci_isa_bridge_read(int func, int addr, void *priv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sis_5571_usb_raise_interrupt(usb_t* usb, void* priv)
|
||||||
|
{
|
||||||
|
sis_5571_t *dev = (sis_5571_t *) priv;
|
||||||
|
|
||||||
|
if (dev->pci_conf_sb[0][0x68] & 0x80) {
|
||||||
|
/* TODO: Is the normal PCI interrupt inhibited when USB IRQ remapping is enabled? */
|
||||||
|
switch (dev->pci_conf_sb[0][0x68] & 0x0F) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x01:
|
||||||
|
case 0x02:
|
||||||
|
case 0x08:
|
||||||
|
case 0x0d:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
picint(1 << dev->pci_conf_sb[0][0x68] & 0x0F);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pci_set_irq(dev->sb_pci_slot, PCI_INTA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
sis_5571_usb_handle_smi(usb_t* usb, void* priv)
|
||||||
|
{
|
||||||
|
/* Left unimplemented for now. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sis_5571_reset(void *priv)
|
sis_5571_reset(void *priv)
|
||||||
{
|
{
|
||||||
@@ -722,7 +754,10 @@ sis_5571_init(const device_t *info)
|
|||||||
dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2);
|
dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2);
|
||||||
|
|
||||||
/* USB */
|
/* USB */
|
||||||
dev->usb = device_add(&usb_device);
|
dev->usb_params.parent_priv = dev;
|
||||||
|
dev->usb_params.raise_interrupt = sis_5571_usb_raise_interrupt;
|
||||||
|
dev->usb_params.smi_handle = sis_5571_usb_handle_smi;
|
||||||
|
dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
|
||||||
|
|
||||||
sis_5571_reset(dev);
|
sis_5571_reset(dev);
|
||||||
|
|
||||||
|
@@ -28,6 +28,8 @@ typedef struct usb_t usb_t;
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
void (*raise_interrupt)(usb_t*, void*);
|
void (*raise_interrupt)(usb_t*, void*);
|
||||||
|
/* Handle (but do not raise) SMI. Returns 1 if SMI can be raised, 0 otherwise. */
|
||||||
|
uint8_t (*smi_handle)(usb_t*, void*);
|
||||||
void* parent_priv;
|
void* parent_priv;
|
||||||
} usb_params_t;
|
} usb_params_t;
|
||||||
|
|
||||||
@@ -54,6 +56,18 @@ typedef struct
|
|||||||
uint8_t bLength;
|
uint8_t bLength;
|
||||||
uint8_t bDescriptorType;
|
uint8_t bDescriptorType;
|
||||||
} usb_desc_base_t;
|
} usb_desc_base_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
usb_desc_base_t base;
|
||||||
|
|
||||||
|
uint16_t wTotalLength;
|
||||||
|
uint8_t bNumInterfaces;
|
||||||
|
uint8_t bConfigurationValue;
|
||||||
|
uint8_t iConfiguration;
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint8_t bMaxPower;
|
||||||
|
} usb_desc_conf_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
/* USB endpoint device struct. Incomplete and unused. */
|
/* USB endpoint device struct. Incomplete and unused. */
|
||||||
@@ -72,12 +86,22 @@ typedef struct
|
|||||||
void* priv;
|
void* priv;
|
||||||
} usb_device_t;
|
} usb_device_t;
|
||||||
|
|
||||||
|
enum usb_bus_types
|
||||||
|
{
|
||||||
|
USB_BUS_OHCI = 0,
|
||||||
|
USB_BUS_UHCI = 1
|
||||||
|
};
|
||||||
|
|
||||||
/* Global variables. */
|
/* Global variables. */
|
||||||
extern const device_t usb_device;
|
extern const device_t usb_device;
|
||||||
|
|
||||||
/* Functions. */
|
/* Functions. */
|
||||||
extern void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable);
|
extern void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable);
|
||||||
extern void ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, int enable);
|
extern void ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, int enable);
|
||||||
|
/* Attach USB device to a port of a USB bus. Returns the port to which it got attached to. */
|
||||||
|
extern uint8_t usb_attach_device(usb_t *dev, usb_device_t* device, uint8_t bus_type);
|
||||||
|
/* Detach USB device from a port. */
|
||||||
|
extern void usb_detach_device(usb_t *dev, uint8_t port, uint8_t bus_type);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
104
src/usb.c
104
src/usb.c
@@ -76,10 +76,25 @@ enum
|
|||||||
OHCI_HcRhPortStatus3 = 0x5C
|
OHCI_HcRhPortStatus3 = 0x5C
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* OHCI HcInterruptEnable/Disable bits */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OHCI_HcInterruptEnable_SO = 1 << 0,
|
||||||
|
OHCI_HcInterruptEnable_WDH = 1 << 1,
|
||||||
|
OHCI_HcInterruptEnable_SF = 1 << 2,
|
||||||
|
OHCI_HcInterruptEnable_RD = 1 << 3,
|
||||||
|
OHCI_HcInterruptEnable_UE = 1 << 4,
|
||||||
|
OHCI_HcInterruptEnable_HNO = 1 << 5,
|
||||||
|
OHCI_HcInterruptEnable_RHSC = 1 << 6,
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usb_interrupt_ohci(usb_t* usb)
|
usb_interrupt_ohci(usb_t* usb)
|
||||||
{
|
{
|
||||||
if (usb->ohci_mmio[OHCI_HcControl + 1] & 1) {
|
if (usb->ohci_mmio[OHCI_HcControl + 1] & 1) {
|
||||||
|
if (usb->usb_params && usb->usb_params->smi_handle && !usb->usb_params->smi_handle(usb, usb->usb_params->parent_priv))
|
||||||
|
return;
|
||||||
|
|
||||||
smi_raise();
|
smi_raise();
|
||||||
}
|
}
|
||||||
else if (usb->usb_params != NULL) {
|
else if (usb->usb_params != NULL) {
|
||||||
@@ -183,6 +198,25 @@ ohci_mmio_read(uint32_t addr, void *p)
|
|||||||
|
|
||||||
ret = dev->ohci_mmio[addr];
|
ret = dev->ohci_mmio[addr];
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case 0x101:
|
||||||
|
ret = (ret & 0xfe) | (!!mem_a20_key);
|
||||||
|
break;
|
||||||
|
case OHCI_HcRhPortStatus1 + 1:
|
||||||
|
case OHCI_HcRhPortStatus2 + 1:
|
||||||
|
case OHCI_HcRhPortStatus3 + 1:
|
||||||
|
ret |= 0x1;
|
||||||
|
break;
|
||||||
|
case OHCI_HcInterruptDisable:
|
||||||
|
case OHCI_HcInterruptDisable + 1:
|
||||||
|
case OHCI_HcInterruptDisable + 2:
|
||||||
|
case OHCI_HcInterruptDisable + 3:
|
||||||
|
ret = dev->ohci_mmio[OHCI_HcInterruptEnable + (addr - OHCI_HcInterruptDisable)];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (addr == 0x101)
|
if (addr == 0x101)
|
||||||
ret = (ret & 0xfe) | (!!mem_a20_key);
|
ret = (ret & 0xfe) | (!!mem_a20_key);
|
||||||
|
|
||||||
@@ -212,6 +246,7 @@ ohci_port_reset_callback(void* priv)
|
|||||||
usb_t *dev = (usb_t *) priv;
|
usb_t *dev = (usb_t *) priv;
|
||||||
|
|
||||||
dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x10;
|
dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x10;
|
||||||
|
dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] |= 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -220,6 +255,23 @@ ohci_port_reset_callback_2(void* priv)
|
|||||||
usb_t *dev = (usb_t *) priv;
|
usb_t *dev = (usb_t *) priv;
|
||||||
|
|
||||||
dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x10;
|
dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x10;
|
||||||
|
dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ohci_set_interrupt(usb_t* usb, uint8_t bit)
|
||||||
|
{
|
||||||
|
if (!(usb->ohci_mmio[OHCI_HcInterruptEnable + 3] & 0x80))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(usb->ohci_mmio[OHCI_HcInterruptEnable] & bit))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (usb->ohci_mmio[OHCI_HcInterruptDisable] & bit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
usb->ohci_mmio[OHCI_HcInterruptStatus] |= bit;
|
||||||
|
usb_interrupt_ohci(usb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -256,6 +308,36 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p)
|
|||||||
break;
|
break;
|
||||||
case OHCI_HcHCCA:
|
case OHCI_HcHCCA:
|
||||||
return;
|
return;
|
||||||
|
case OHCI_HcInterruptEnable:
|
||||||
|
dev->ohci_mmio[addr] = (val & 0x7f);
|
||||||
|
dev->ohci_mmio[OHCI_HcInterruptDisable] &= ~(val & 0x7f);
|
||||||
|
return;
|
||||||
|
case OHCI_HcInterruptEnable + 1:
|
||||||
|
case OHCI_HcInterruptEnable + 2:
|
||||||
|
return;
|
||||||
|
case OHCI_HcInterruptEnable + 3:
|
||||||
|
dev->ohci_mmio[addr] = (val & 0x40);
|
||||||
|
dev->ohci_mmio[addr] |= (val & 0x80);
|
||||||
|
if (val & 0x80)
|
||||||
|
dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x80;
|
||||||
|
if (val & 0x40)
|
||||||
|
dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x40;
|
||||||
|
return;
|
||||||
|
case OHCI_HcInterruptDisable:
|
||||||
|
dev->ohci_mmio[addr] = (val & 0x7f);
|
||||||
|
dev->ohci_mmio[OHCI_HcInterruptEnable] &= ~(val & 0x7f);
|
||||||
|
return;
|
||||||
|
case OHCI_HcInterruptDisable + 1:
|
||||||
|
case OHCI_HcInterruptDisable + 2:
|
||||||
|
return;
|
||||||
|
case OHCI_HcInterruptDisable + 3:
|
||||||
|
dev->ohci_mmio[addr] = (val & 0x40);
|
||||||
|
dev->ohci_mmio[addr] |= (val & 0x80);
|
||||||
|
if (val & 0x80)
|
||||||
|
dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x80;
|
||||||
|
if (val & 0x40)
|
||||||
|
dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x40;
|
||||||
|
return;
|
||||||
case OHCI_HcInterruptStatus:
|
case OHCI_HcInterruptStatus:
|
||||||
dev->ohci_mmio[addr] &= ~(val & 0x7f);
|
dev->ohci_mmio[addr] &= ~(val & 0x7f);
|
||||||
return;
|
return;
|
||||||
@@ -365,7 +447,6 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p)
|
|||||||
if (old & 0x01) {
|
if (old & 0x01) {
|
||||||
dev->ohci_mmio[addr] |= 0x10;
|
dev->ohci_mmio[addr] |= 0x10;
|
||||||
timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_HcRhPortStatus1) / 4], 10000.);
|
timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_HcRhPortStatus1) / 4], 10000.);
|
||||||
dev->ohci_mmio[addr + 2] |= 0x10;
|
|
||||||
} else
|
} else
|
||||||
dev->ohci_mmio[addr + 2] |= 0x01;
|
dev->ohci_mmio[addr + 2] |= 0x01;
|
||||||
}
|
}
|
||||||
@@ -416,6 +497,14 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p)
|
|||||||
case OHCI_HcRhPortStatus1 + 3:
|
case OHCI_HcRhPortStatus1 + 3:
|
||||||
case OHCI_HcRhPortStatus2 + 3:
|
case OHCI_HcRhPortStatus2 + 3:
|
||||||
return;
|
return;
|
||||||
|
case OHCI_HcDoneHead:
|
||||||
|
case OHCI_HcBulkCurrentED:
|
||||||
|
case OHCI_HcBulkHeadED:
|
||||||
|
case OHCI_HcControlCurrentED:
|
||||||
|
case OHCI_HcControlHeadED:
|
||||||
|
case OHCI_HcPeriodCurrentED:
|
||||||
|
dev->ohci_mmio[addr] = (val & 0xf0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->ohci_mmio[addr] = val;
|
dev->ohci_mmio[addr] = val;
|
||||||
@@ -433,6 +522,18 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3,
|
|||||||
mem_mapping_set_addr(&dev->ohci_mmio_mapping, dev->ohci_mem_base, 0x1000);
|
mem_mapping_set_addr(&dev->ohci_mmio_mapping, dev->ohci_mem_base, 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
usb_attach_device(usb_t *dev, usb_device_t* device, uint8_t bus_type)
|
||||||
|
{
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_detach_device(usb_t *dev, uint8_t port, uint8_t bus_type)
|
||||||
|
{
|
||||||
|
/* Unused. */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usb_reset(void *priv)
|
usb_reset(void *priv)
|
||||||
{
|
{
|
||||||
@@ -446,6 +547,7 @@ usb_reset(void *priv)
|
|||||||
dev->ohci_mmio[OHCI_HcRevision] = 0x10;
|
dev->ohci_mmio[OHCI_HcRevision] = 0x10;
|
||||||
dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01;
|
dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01;
|
||||||
dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02;
|
dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02;
|
||||||
|
dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] = 0x02;
|
||||||
|
|
||||||
io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev);
|
io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev);
|
||||||
dev->uhci_enable = 0;
|
dev->uhci_enable = 0;
|
||||||
|
Reference in New Issue
Block a user