Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/bhnd/cores/usb/bhnd_usb.c
Show First 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | bhnd_usb_attach(device_t dev) | ||||
sc->mem_rman.rm_type = RMAN_ARRAY; | sc->mem_rman.rm_type = RMAN_ARRAY; | ||||
sc->mem_rman.rm_descr = "BHND USB core I/O memory addresses"; | sc->mem_rman.rm_descr = "BHND USB core I/O memory addresses"; | ||||
if (rman_init(&sc->mem_rman) != 0 || | if (rman_init(&sc->mem_rman) != 0 || | ||||
rman_manage_region(&sc->mem_rman, sc->mem_rman.rm_start, | rman_manage_region(&sc->mem_rman, sc->mem_rman.rm_start, | ||||
sc->mem_rman.rm_end) != 0) { | sc->mem_rman.rm_end) != 0) { | ||||
panic("%s: sc->mem_rman", __func__); | panic("%s: sc->mem_rman", __func__); | ||||
} | } | ||||
sc->irq_rman.rm_start = sc->sc_irqn; | |||||
sc->irq_rman.rm_end = sc->sc_irqn; | |||||
sc->irq_rman.rm_type = RMAN_ARRAY; | |||||
sc->irq_rman.rm_descr = "BHND USB core IRQ"; | |||||
/* | |||||
* BHND USB share same IRQ between OHCI and EHCI | |||||
*/ | |||||
if (rman_init(&sc->irq_rman) != 0 || | |||||
rman_manage_region(&sc->irq_rman, sc->irq_rman.rm_start, | |||||
sc->irq_rman.rm_end) != 0) | |||||
panic("%s: failed to set up IRQ rman", __func__); | |||||
/* TODO: macros for registers */ | /* TODO: macros for registers */ | ||||
bus_write_4(sc->sc_mem, 0x200, 0x7ff); | bus_write_4(sc->sc_mem, 0x200, 0x7ff); | ||||
DELAY(100); | DELAY(100); | ||||
#define OHCI_CONTROL 0x04 | #define OHCI_CONTROL 0x04 | ||||
bus_write_4(sc->sc_mem, OHCI_CONTROL, 0); | bus_write_4(sc->sc_mem, OHCI_CONTROL, 0); | ||||
if ( bhnd_get_device(dev) == BHND_COREID_USB20H) { | if ( bhnd_get_device(dev) == BHND_COREID_USB20H) { | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
static struct resource * | static struct resource * | ||||
bhnd_usb_alloc_resource(device_t bus, device_t child, int type, int *rid, | bhnd_usb_alloc_resource(device_t bus, device_t child, int type, int *rid, | ||||
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) | rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) | ||||
{ | { | ||||
struct resource *rv; | struct resource *rv; | ||||
struct resource_list *rl; | struct resource_list *rl; | ||||
struct resource_list_entry *rle; | struct resource_list_entry *rle; | ||||
int isdefault, needactivate; | int passthrough, isdefault, needactivate; | ||||
struct bhnd_usb_softc *sc = device_get_softc(bus); | struct bhnd_usb_softc *sc = device_get_softc(bus); | ||||
isdefault = RMAN_IS_DEFAULT_RANGE(start,end); | isdefault = RMAN_IS_DEFAULT_RANGE(start,end); | ||||
passthrough = (device_get_parent(child) != bus); | |||||
needactivate = flags & RF_ACTIVE; | needactivate = flags & RF_ACTIVE; | ||||
rl = BUS_GET_RESOURCE_LIST(bus, child); | |||||
rle = NULL; | rle = NULL; | ||||
if (isdefault) { | if (!passthrough && isdefault) { | ||||
BHND_INFO_DEV(bus, "trying allocate def %d - %d for %s", type, | BHND_INFO_DEV(bus, "trying allocate def %d - %d for %s", type, | ||||
*rid, device_get_nameunit(child) ); | *rid, device_get_nameunit(child) ); | ||||
rl = BUS_GET_RESOURCE_LIST(bus, child); | |||||
rle = resource_list_find(rl, type, *rid); | rle = resource_list_find(rl, type, *rid); | ||||
if (rle == NULL) | if (rle == NULL) | ||||
return (NULL); | return (NULL); | ||||
if (rle->res != NULL) | if (rle->res != NULL) | ||||
panic("%s: resource entry is busy", __func__); | panic("%s: resource entry is busy", __func__); | ||||
start = rle->start; | start = rle->start; | ||||
end = rle->end; | end = rle->end; | ||||
count = rle->count; | count = rle->count; | ||||
Show All 22 Lines | if (needactivate && | ||||
BHND_ERROR_DEV(bus, "could not activate resource"); | BHND_ERROR_DEV(bus, "could not activate resource"); | ||||
rman_release_resource(rv); | rman_release_resource(rv); | ||||
return (0); | return (0); | ||||
} | } | ||||
return (rv); | return (rv); | ||||
} | } | ||||
if (type == SYS_RES_IRQ) { | |||||
rv = rman_reserve_resource(&sc->irq_rman, start, end, count, | |||||
flags, child); | |||||
if (rv == NULL) { | |||||
BHND_ERROR_DEV(bus, "could not reserve resource"); | |||||
return (0); | |||||
} | |||||
rman_set_rid(rv, *rid); | |||||
if (needactivate && | |||||
bus_activate_resource(child, type, *rid, rv)) { | |||||
BHND_ERROR_DEV(bus, "could not activate resource"); | |||||
rman_release_resource(rv); | |||||
return (0); | |||||
} | |||||
return (rv); | |||||
} | |||||
/* | /* | ||||
* Pass the request to the parent. | * Pass the request to the parent. | ||||
*/ | */ | ||||
return (resource_list_alloc(rl, bus, child, type, rid, | return (bus_generic_rl_alloc_resource(bus, child, type, rid, start, end, | ||||
start, end, count, flags)); | count, flags)); | ||||
} | } | ||||
static struct resource_list * | static struct resource_list * | ||||
bhnd_usb_get_reslist(device_t dev, device_t child) | bhnd_usb_get_reslist(device_t dev, device_t child) | ||||
{ | { | ||||
struct bhnd_usb_devinfo *sdi; | struct bhnd_usb_devinfo *sdi; | ||||
sdi = device_get_ivars(child); | sdi = device_get_ivars(child); | ||||
return (&sdi->sdi_rl); | return (&sdi->sdi_rl); | ||||
} | } | ||||
static int | static int | ||||
bhnd_usb_release_resource(device_t dev, device_t child, int type, | bhnd_usb_release_resource(device_t dev, device_t child, int type, | ||||
int rid, struct resource *r) | int rid, struct resource *r) | ||||
{ | { | ||||
struct resource_list *rl; | struct bhnd_usb_softc *sc; | ||||
struct resource_list_entry *rle; | struct resource_list_entry *rle; | ||||
bool passthrough; | |||||
int error; | |||||
rl = bhnd_usb_get_reslist(dev, child); | sc = device_get_softc(dev); | ||||
if (rl == NULL) | passthrough = (device_get_parent(child) != dev); | ||||
return (EINVAL); | |||||
rle = resource_list_find(rl, type, rid); | /* Delegate to our parent device's bus if the requested resource type | ||||
if (rle == NULL) | * isn't handled locally. */ | ||||
return (EINVAL); | if (type != SYS_RES_MEMORY) { | ||||
rman_release_resource(r); | return (bus_generic_rl_release_resource(dev, child, type, rid, | ||||
r)); | |||||
} | |||||
/* Deactivate resources */ | |||||
if (rman_get_flags(r) & RF_ACTIVE) { | |||||
error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
if ((error = rman_release_resource(r))) | |||||
return (error); | |||||
if (!passthrough) { | |||||
/* Clean resource list entry */ | |||||
rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), | |||||
type, rid); | |||||
if (rle != NULL) | |||||
rle->res = NULL; | rle->res = NULL; | ||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
bhnd_usb_print_all_resources(device_t dev) | bhnd_usb_print_all_resources(device_t dev) | ||||
{ | { | ||||
struct bhnd_usb_devinfo *sdi; | struct bhnd_usb_devinfo *sdi; | ||||
Show All 28 Lines | |||||
} | } | ||||
static device_t | static device_t | ||||
bhnd_usb_add_child(device_t dev, u_int order, const char *name, int unit) | bhnd_usb_add_child(device_t dev, u_int order, const char *name, int unit) | ||||
{ | { | ||||
struct bhnd_usb_softc *sc; | struct bhnd_usb_softc *sc; | ||||
struct bhnd_usb_devinfo *sdi; | struct bhnd_usb_devinfo *sdi; | ||||
device_t child; | device_t child; | ||||
int error; | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
child = device_add_child_ordered(dev, order, name, unit); | |||||
if (child == NULL) | |||||
return (NULL); | |||||
sdi = malloc(sizeof(struct bhnd_usb_devinfo), M_DEVBUF, M_NOWAIT|M_ZERO); | sdi = malloc(sizeof(struct bhnd_usb_devinfo), M_DEVBUF, M_NOWAIT|M_ZERO); | ||||
if (sdi == NULL) | if (sdi == NULL) | ||||
return (NULL); | return (NULL); | ||||
resource_list_init(&sdi->sdi_rl); | |||||
sdi->sdi_irq_mapped = false; | |||||
if (strncmp(name, "ohci", 4) == 0) | if (strncmp(name, "ohci", 4) == 0) | ||||
{ | { | ||||
sdi->sdi_maddr = sc->sc_maddr + 0x000; | sdi->sdi_maddr = sc->sc_maddr + 0x000; | ||||
sdi->sdi_msize = 0x200; | sdi->sdi_msize = 0x200; | ||||
sdi->sdi_irq = sc->sc_irqn; | |||||
BHND_INFO_DEV(dev, "ohci: irq=%d maddr=0x%jx", sdi->sdi_irq, | |||||
sdi->sdi_maddr); | |||||
} | } | ||||
else if (strncmp(name, "ehci", 4) == 0) | else if (strncmp(name, "ehci", 4) == 0) | ||||
{ | { | ||||
sdi->sdi_maddr = sc->sc_maddr + 0x000; | sdi->sdi_maddr = sc->sc_maddr + 0x000; | ||||
sdi->sdi_msize = 0x1000; | sdi->sdi_msize = 0x1000; | ||||
sdi->sdi_irq = sc->sc_irqn; | |||||
BHND_INFO_DEV(dev, "ehci: irq=%d maddr=0x%jx", sdi->sdi_irq, | |||||
sdi->sdi_maddr); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
panic("Unknown subdevice"); | panic("Unknown subdevice"); | ||||
/* Unknown subdevice */ | |||||
sdi->sdi_maddr = 1; | |||||
sdi->sdi_msize = 1; | |||||
sdi->sdi_irq = 1; | |||||
} | } | ||||
resource_list_init(&sdi->sdi_rl); | /* Map the child's IRQ */ | ||||
if ((error = bhnd_map_intr(dev, 0, &sdi->sdi_irq))) { | |||||
BHND_ERROR_DEV(dev, "could not map %s interrupt: %d", name, | |||||
error); | |||||
goto failed; | |||||
} | |||||
sdi->sdi_irq_mapped = true; | |||||
BHND_INFO_DEV(dev, "%s: irq=%ju maddr=0x%jx", name, sdi->sdi_irq, | |||||
sdi->sdi_maddr); | |||||
/* | /* | ||||
* Determine memory window on bus and irq if one is needed. | * Add memory window and irq to child's resource list. | ||||
*/ | */ | ||||
resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, 0, | resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, 0, sdi->sdi_maddr, | ||||
sdi->sdi_maddr, sdi->sdi_maddr + sdi->sdi_msize - 1, sdi->sdi_msize); | sdi->sdi_maddr + sdi->sdi_msize - 1, sdi->sdi_msize); | ||||
resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, 0, | resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, 0, sdi->sdi_irq, | ||||
sdi->sdi_irq, sdi->sdi_irq, 1); | sdi->sdi_irq, 1); | ||||
child = device_add_child_ordered(dev, order, name, unit); | |||||
if (child == NULL) { | |||||
BHND_ERROR_DEV(dev, "could not add %s", name); | |||||
goto failed; | |||||
} | |||||
device_set_ivars(child, sdi); | device_set_ivars(child, sdi); | ||||
return (child); | return (child); | ||||
failed: | |||||
if (sdi->sdi_irq_mapped) | |||||
bhnd_unmap_intr(dev, sdi->sdi_irq); | |||||
resource_list_free(&sdi->sdi_rl); | |||||
free(sdi, M_DEVBUF); | |||||
return (NULL); | |||||
} | } | ||||
static void | |||||
bhnd_usb_child_deleted(device_t dev, device_t child) | |||||
{ | |||||
struct bhnd_usb_devinfo *dinfo; | |||||
if ((dinfo = device_get_ivars(child)) == NULL) | |||||
return; | |||||
if (dinfo->sdi_irq_mapped) | |||||
bhnd_unmap_intr(dev, dinfo->sdi_irq); | |||||
resource_list_free(&dinfo->sdi_rl); | |||||
free(dinfo, M_DEVBUF); | |||||
} | |||||
static device_method_t bhnd_usb_methods[] = { | static device_method_t bhnd_usb_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_attach, bhnd_usb_attach), | DEVMETHOD(device_attach, bhnd_usb_attach), | ||||
DEVMETHOD(device_probe, bhnd_usb_probe), | DEVMETHOD(device_probe, bhnd_usb_probe), | ||||
/* Bus interface */ | /* Bus interface */ | ||||
DEVMETHOD(bus_add_child, bhnd_usb_add_child), | DEVMETHOD(bus_add_child, bhnd_usb_add_child), | ||||
DEVMETHOD(bus_child_deleted, bhnd_usb_child_deleted), | |||||
DEVMETHOD(bus_alloc_resource, bhnd_usb_alloc_resource), | DEVMETHOD(bus_alloc_resource, bhnd_usb_alloc_resource), | ||||
DEVMETHOD(bus_get_resource_list, bhnd_usb_get_reslist), | DEVMETHOD(bus_get_resource_list, bhnd_usb_get_reslist), | ||||
DEVMETHOD(bus_print_child, bhnd_usb_print_child), | DEVMETHOD(bus_print_child, bhnd_usb_print_child), | ||||
DEVMETHOD(bus_release_resource, bhnd_usb_release_resource), | DEVMETHOD(bus_release_resource, bhnd_usb_release_resource), | ||||
/* Bus interface: generic part */ | /* Bus interface: generic part */ | ||||
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), | DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), | ||||
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), | DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), | ||||
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), | DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), | ||||
Show All 12 Lines |