Add special memory allocation routines that supports allocation
DMA-able memory in small chunks (USB uses a lot of 8 byte chunks). Using the bus_dma functions directly is inefficient.
This commit is contained in:
parent
91f18e727f
commit
b916de0f86
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: ohci.c,v 1.3 1998/07/23 13:41:04 augustss Exp $ */
|
/* $NetBSD: ohci.c,v 1.4 1998/07/24 21:09:07 augustss Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
@ -52,14 +52,13 @@
|
|||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
|
||||||
#include <dev/usb/usb.h>
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb.h>
|
||||||
#include <dev/usb/usbdi.h>
|
#include <dev/usb/usbdi.h>
|
||||||
#include <dev/usb/usbdivar.h>
|
#include <dev/usb/usbdivar.h>
|
||||||
|
|
||||||
#include <dev/usb/usb_quirks.h>
|
#include <dev/usb/usb_quirks.h>
|
||||||
|
#include <dev/usb/usb_mem.h>
|
||||||
#include <machine/bus.h>
|
|
||||||
|
|
||||||
#include <dev/usb/ohcireg.h>
|
#include <dev/usb/ohcireg.h>
|
||||||
#include <dev/usb/ohcivar.h>
|
#include <dev/usb/ohcivar.h>
|
||||||
@ -82,9 +81,6 @@ void ohci_ctrl_done __P((ohci_softc_t *, usbd_request_handle));
|
|||||||
void ohci_intr_done __P((ohci_softc_t *, usbd_request_handle));
|
void ohci_intr_done __P((ohci_softc_t *, usbd_request_handle));
|
||||||
void ohci_bulk_done __P((ohci_softc_t *, usbd_request_handle));
|
void ohci_bulk_done __P((ohci_softc_t *, usbd_request_handle));
|
||||||
|
|
||||||
usbd_status ohci_allocmem __P((ohci_softc_t *,size_t,size_t, ohci_dma_t*));
|
|
||||||
void ohci_freemem __P((ohci_softc_t *, ohci_dma_t *));
|
|
||||||
|
|
||||||
usbd_status ohci_device_request __P((usbd_request_handle reqh));
|
usbd_status ohci_device_request __P((usbd_request_handle reqh));
|
||||||
void ohci_add_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
|
void ohci_add_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
|
||||||
void ohci_rem_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
|
void ohci_rem_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
|
||||||
@ -146,20 +142,20 @@ struct ohci_pipe {
|
|||||||
union {
|
union {
|
||||||
/* Control pipe */
|
/* Control pipe */
|
||||||
struct {
|
struct {
|
||||||
ohci_dma_t datadma;
|
usb_dma_t datadma;
|
||||||
ohci_dma_t reqdma;
|
usb_dma_t reqdma;
|
||||||
u_int length;
|
u_int length;
|
||||||
ohci_soft_td_t *setup, *xfer, *stat;
|
ohci_soft_td_t *setup, *xfer, *stat;
|
||||||
} ctl;
|
} ctl;
|
||||||
/* Interrupt pipe */
|
/* Interrupt pipe */
|
||||||
struct {
|
struct {
|
||||||
ohci_dma_t datadma;
|
usb_dma_t datadma;
|
||||||
int nslots;
|
int nslots;
|
||||||
int pos;
|
int pos;
|
||||||
} intr;
|
} intr;
|
||||||
/* Bulk pipe */
|
/* Bulk pipe */
|
||||||
struct {
|
struct {
|
||||||
ohci_dma_t datadma;
|
usb_dma_t datadma;
|
||||||
u_int length;
|
u_int length;
|
||||||
} bulk;
|
} bulk;
|
||||||
} u;
|
} u;
|
||||||
@ -197,59 +193,6 @@ struct usbd_methods ohci_device_bulk_methods = {
|
|||||||
ohci_device_bulk_close,
|
ohci_device_bulk_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
usbd_status
|
|
||||||
ohci_allocmem(sc, size, align, p)
|
|
||||||
ohci_softc_t *sc;
|
|
||||||
size_t size;
|
|
||||||
size_t align;
|
|
||||||
ohci_dma_t *p;
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
DPRINTFN(5, ("ohci_allocmem: size=%d align=%d\n", size, align));
|
|
||||||
p->size = size;
|
|
||||||
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
|
|
||||||
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
|
|
||||||
&p->nsegs, BUS_DMA_NOWAIT);
|
|
||||||
if (error)
|
|
||||||
return (USBD_NOMEM);
|
|
||||||
|
|
||||||
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
|
|
||||||
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
|
|
||||||
if (error)
|
|
||||||
goto free;
|
|
||||||
|
|
||||||
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
|
|
||||||
0, BUS_DMA_NOWAIT, &p->map);
|
|
||||||
if (error)
|
|
||||||
goto unmap;
|
|
||||||
|
|
||||||
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->kaddr,p->size, NULL,
|
|
||||||
BUS_DMA_NOWAIT);
|
|
||||||
if (error)
|
|
||||||
goto destroy;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
destroy:
|
|
||||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
|
||||||
unmap:
|
|
||||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
|
||||||
free:
|
|
||||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
|
||||||
return (USBD_NOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ohci_freemem(sc, p)
|
|
||||||
ohci_softc_t *sc;
|
|
||||||
ohci_dma_t *p;
|
|
||||||
{
|
|
||||||
bus_dmamap_unload(sc->sc_dmatag, p->map);
|
|
||||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
|
||||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
|
||||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
|
||||||
}
|
|
||||||
|
|
||||||
ohci_soft_ed_t *
|
ohci_soft_ed_t *
|
||||||
ohci_alloc_sed(sc)
|
ohci_alloc_sed(sc)
|
||||||
ohci_softc_t *sc;
|
ohci_softc_t *sc;
|
||||||
@ -257,7 +200,7 @@ ohci_alloc_sed(sc)
|
|||||||
ohci_soft_ed_t *sed;
|
ohci_soft_ed_t *sed;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int i, offs;
|
int i, offs;
|
||||||
ohci_dma_t dma;
|
usb_dma_t dma;
|
||||||
|
|
||||||
if (!sc->sc_freeeds) {
|
if (!sc->sc_freeeds) {
|
||||||
DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
|
DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
|
||||||
@ -265,8 +208,8 @@ ohci_alloc_sed(sc)
|
|||||||
M_USBDEV, M_NOWAIT);
|
M_USBDEV, M_NOWAIT);
|
||||||
if (!sed)
|
if (!sed)
|
||||||
return 0;
|
return 0;
|
||||||
r = ohci_allocmem(sc, OHCI_ED_SIZE * OHCI_ED_CHUNK,
|
r = usb_allocmem(sc->sc_dmatag, OHCI_ED_SIZE * OHCI_ED_CHUNK,
|
||||||
OHCI_ED_ALIGN, &dma);
|
OHCI_ED_ALIGN, &dma);
|
||||||
if (r != USBD_NORMAL_COMPLETION) {
|
if (r != USBD_NORMAL_COMPLETION) {
|
||||||
free(sed, M_USBDEV);
|
free(sed, M_USBDEV);
|
||||||
return 0;
|
return 0;
|
||||||
@ -303,7 +246,7 @@ ohci_alloc_std(sc)
|
|||||||
ohci_soft_td_t *std;
|
ohci_soft_td_t *std;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int i, offs;
|
int i, offs;
|
||||||
ohci_dma_t dma;
|
usb_dma_t dma;
|
||||||
|
|
||||||
if (!sc->sc_freetds) {
|
if (!sc->sc_freetds) {
|
||||||
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
|
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
|
||||||
@ -311,8 +254,8 @@ ohci_alloc_std(sc)
|
|||||||
M_USBDEV, M_NOWAIT);
|
M_USBDEV, M_NOWAIT);
|
||||||
if (!std)
|
if (!std)
|
||||||
return 0;
|
return 0;
|
||||||
r = ohci_allocmem(sc, OHCI_TD_SIZE * OHCI_TD_CHUNK,
|
r = usb_allocmem(sc->sc_dmatag, OHCI_TD_SIZE * OHCI_TD_CHUNK,
|
||||||
OHCI_TD_ALIGN, &dma);
|
OHCI_TD_ALIGN, &dma);
|
||||||
if (r != USBD_NORMAL_COMPLETION) {
|
if (r != USBD_NORMAL_COMPLETION) {
|
||||||
free(std, M_USBDEV);
|
free(std, M_USBDEV);
|
||||||
return 0;
|
return 0;
|
||||||
@ -367,7 +310,8 @@ ohci_init(sc)
|
|||||||
LIST_INIT(&sc->sc_hash_tds[i]);
|
LIST_INIT(&sc->sc_hash_tds[i]);
|
||||||
|
|
||||||
/* Allocate the HCCA area. */
|
/* Allocate the HCCA area. */
|
||||||
r = ohci_allocmem(sc, OHCI_HCCA_SIZE, OHCI_HCCA_ALIGN,&sc->sc_hccadma);
|
r = usb_allocmem(sc->sc_dmatag, OHCI_HCCA_SIZE,
|
||||||
|
OHCI_HCCA_ALIGN, &sc->sc_hccadma);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
return (r);
|
return (r);
|
||||||
sc->sc_hcca = (struct ohci_hcca *)KERNADDR(&sc->sc_hccadma);
|
sc->sc_hcca = (struct ohci_hcca *)KERNADDR(&sc->sc_hccadma);
|
||||||
@ -516,7 +460,7 @@ ohci_init(sc)
|
|||||||
bad2:
|
bad2:
|
||||||
ohci_free_sed(sc, sc->sc_bulk_head);
|
ohci_free_sed(sc, sc->sc_bulk_head);
|
||||||
bad1:
|
bad1:
|
||||||
ohci_freemem(sc, &sc->sc_hccadma);
|
usb_freemem(sc->sc_dmatag, &sc->sc_hccadma);
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,7 +680,7 @@ ohci_ctrl_done(sc, reqh)
|
|||||||
{
|
{
|
||||||
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
||||||
u_int len = opipe->u.ctl.length;
|
u_int len = opipe->u.ctl.length;
|
||||||
ohci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
|
|
||||||
DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh));
|
DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh));
|
||||||
|
|
||||||
@ -749,7 +693,7 @@ ohci_ctrl_done(sc, reqh)
|
|||||||
dma = &opipe->u.ctl.datadma;
|
dma = &opipe->u.ctl.datadma;
|
||||||
if (reqh->request.bmRequestType & UT_READ)
|
if (reqh->request.bmRequestType & UT_READ)
|
||||||
memcpy(reqh->buffer, KERNADDR(dma), len);
|
memcpy(reqh->buffer, KERNADDR(dma), len);
|
||||||
ohci_freemem(sc, dma);
|
usb_freemem(sc->sc_dmatag, dma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,7 +703,7 @@ ohci_intr_done(sc, reqh)
|
|||||||
usbd_request_handle reqh;
|
usbd_request_handle reqh;
|
||||||
{
|
{
|
||||||
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
||||||
ohci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
ohci_soft_ed_t *sed = opipe->sed;
|
ohci_soft_ed_t *sed = opipe->sed;
|
||||||
ohci_soft_td_t *xfer, *tail;
|
ohci_soft_td_t *xfer, *tail;
|
||||||
|
|
||||||
@ -795,7 +739,7 @@ ohci_intr_done(sc, reqh)
|
|||||||
sed->ed->ed_tailp = tail->physaddr;
|
sed->ed->ed_tailp = tail->physaddr;
|
||||||
opipe->tail = tail;
|
opipe->tail = tail;
|
||||||
} else {
|
} else {
|
||||||
ohci_freemem(sc, dma);
|
usb_freemem(sc->sc_dmatag, dma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,7 +749,7 @@ ohci_bulk_done(sc, reqh)
|
|||||||
usbd_request_handle reqh;
|
usbd_request_handle reqh;
|
||||||
{
|
{
|
||||||
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
||||||
ohci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
|
|
||||||
|
|
||||||
DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n",
|
DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n",
|
||||||
@ -814,7 +758,7 @@ ohci_bulk_done(sc, reqh)
|
|||||||
dma = &opipe->u.bulk.datadma;
|
dma = &opipe->u.bulk.datadma;
|
||||||
if (reqh->request.bmRequestType & UT_READ)
|
if (reqh->request.bmRequestType & UT_READ)
|
||||||
memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
|
memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
|
||||||
ohci_freemem(sc, dma);
|
usb_freemem(sc->sc_dmatag, dma);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -854,7 +798,7 @@ ohci_rhsc(sc, reqh)
|
|||||||
|
|
||||||
if (reqh->pipe->intrreqh != reqh) {
|
if (reqh->pipe->intrreqh != reqh) {
|
||||||
sc->sc_intrreqh = 0;
|
sc->sc_intrreqh = 0;
|
||||||
ohci_freemem(sc, &opipe->u.intr.datadma);
|
usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,7 +847,7 @@ ohci_device_request(reqh)
|
|||||||
int addr = dev->address;
|
int addr = dev->address;
|
||||||
ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail;
|
ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail;
|
||||||
ohci_soft_ed_t *sed;
|
ohci_soft_ed_t *sed;
|
||||||
ohci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
int isread;
|
int isread;
|
||||||
int len;
|
int len;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
@ -946,7 +890,7 @@ ohci_device_request(reqh)
|
|||||||
r = USBD_NOMEM;
|
r = USBD_NOMEM;
|
||||||
goto bad3;
|
goto bad3;
|
||||||
}
|
}
|
||||||
r = ohci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto bad4;
|
goto bad4;
|
||||||
xfer->td->td_flags =
|
xfer->td->td_flags =
|
||||||
@ -1218,8 +1162,9 @@ ohci_open(pipe)
|
|||||||
switch (ed->bmAttributes & UE_XFERTYPE) {
|
switch (ed->bmAttributes & UE_XFERTYPE) {
|
||||||
case UE_CONTROL:
|
case UE_CONTROL:
|
||||||
pipe->methods = &ohci_device_ctrl_methods;
|
pipe->methods = &ohci_device_ctrl_methods;
|
||||||
r = ohci_allocmem(sc, sizeof(ohci_dma_t), 0,
|
r = usb_allocmem(sc->sc_dmatag,
|
||||||
&opipe->u.ctl.reqdma);
|
sizeof(usb_device_request_t),
|
||||||
|
0, &opipe->u.ctl.reqdma);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto bad;
|
goto bad;
|
||||||
s = splusb();
|
s = splusb();
|
||||||
@ -1654,7 +1599,7 @@ ohci_root_intr_transfer(reqh)
|
|||||||
usbd_pipe_handle pipe = reqh->pipe;
|
usbd_pipe_handle pipe = reqh->pipe;
|
||||||
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
|
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
|
||||||
struct ohci_pipe *upipe = (struct ohci_pipe *)pipe;
|
struct ohci_pipe *upipe = (struct ohci_pipe *)pipe;
|
||||||
ohci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
@ -1663,7 +1608,7 @@ ohci_root_intr_transfer(reqh)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (USBD_INVAL); /* XXX should it be? */
|
return (USBD_INVAL); /* XXX should it be? */
|
||||||
|
|
||||||
r = ohci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
return (r);
|
return (r);
|
||||||
sc->sc_intrreqh = reqh;
|
sc->sc_intrreqh = reqh;
|
||||||
@ -1756,7 +1701,7 @@ ohci_device_bulk_transfer(reqh)
|
|||||||
int addr = dev->address;
|
int addr = dev->address;
|
||||||
ohci_soft_td_t *xfer, *tail;
|
ohci_soft_td_t *xfer, *tail;
|
||||||
ohci_soft_ed_t *sed;
|
ohci_soft_ed_t *sed;
|
||||||
ohci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int s, len, isread;
|
int s, len, isread;
|
||||||
|
|
||||||
@ -1773,7 +1718,7 @@ ohci_device_bulk_transfer(reqh)
|
|||||||
|
|
||||||
opipe->u.bulk.length = len;
|
opipe->u.bulk.length = len;
|
||||||
|
|
||||||
r = ohci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto ret1;
|
goto ret1;
|
||||||
|
|
||||||
@ -1820,7 +1765,7 @@ ohci_device_bulk_transfer(reqh)
|
|||||||
return (USBD_IN_PROGRESS);
|
return (USBD_IN_PROGRESS);
|
||||||
|
|
||||||
ret2:
|
ret2:
|
||||||
ohci_freemem(sc, dmap);
|
usb_freemem(sc->sc_dmatag, dmap);
|
||||||
ret1:
|
ret1:
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
@ -1869,7 +1814,7 @@ ohci_device_intr_transfer(reqh)
|
|||||||
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
|
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
|
||||||
ohci_soft_ed_t *sed = opipe->sed;
|
ohci_soft_ed_t *sed = opipe->sed;
|
||||||
ohci_soft_td_t *xfer, *tail;
|
ohci_soft_td_t *xfer, *tail;
|
||||||
ohci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int len;
|
int len;
|
||||||
int s;
|
int s;
|
||||||
@ -1893,7 +1838,7 @@ ohci_device_intr_transfer(reqh)
|
|||||||
}
|
}
|
||||||
tail->reqh = 0;
|
tail->reqh = 0;
|
||||||
|
|
||||||
r = ohci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto ret2;
|
goto ret2;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: ohcivar.h,v 1.1 1998/07/12 19:51:59 augustss Exp $ */
|
/* $NetBSD: ohcivar.h,v 1.2 1998/07/24 21:09:07 augustss Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
@ -36,17 +36,6 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct ohci_dma {
|
|
||||||
bus_dmamap_t map;
|
|
||||||
caddr_t kaddr;
|
|
||||||
bus_dma_segment_t segs[1];
|
|
||||||
int nsegs;
|
|
||||||
size_t size;
|
|
||||||
struct ohci_dma *next;
|
|
||||||
} ohci_dma_t;
|
|
||||||
#define DMAADDR(dma) ((dma)->segs[0].ds_addr)
|
|
||||||
#define KERNADDR(dma) ((void *)((dma)->kaddr))
|
|
||||||
|
|
||||||
typedef struct ohci_soft_ed {
|
typedef struct ohci_soft_ed {
|
||||||
ohci_ed_t *ed;
|
ohci_ed_t *ed;
|
||||||
struct ohci_soft_ed *next;
|
struct ohci_soft_ed *next;
|
||||||
@ -79,7 +68,7 @@ typedef struct ohci_softc {
|
|||||||
bus_dma_tag_t sc_dmatag; /* DMA tag */
|
bus_dma_tag_t sc_dmatag; /* DMA tag */
|
||||||
/* XXX should keep track of all DMA memory */
|
/* XXX should keep track of all DMA memory */
|
||||||
|
|
||||||
ohci_dma_t sc_hccadma;
|
usb_dma_t sc_hccadma;
|
||||||
struct ohci_hcca *sc_hcca;
|
struct ohci_hcca *sc_hcca;
|
||||||
ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
|
ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
|
||||||
u_int sc_bws[OHCI_NO_INTRS];
|
u_int sc_bws[OHCI_NO_INTRS];
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: uhci.c,v 1.6 1998/07/23 13:44:21 augustss Exp $ */
|
/* $NetBSD: uhci.c,v 1.7 1998/07/24 21:09:07 augustss Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
@ -55,15 +55,14 @@
|
|||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
|
||||||
#include <dev/usb/usb.h>
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb.h>
|
||||||
#include <dev/usb/usbdi.h>
|
#include <dev/usb/usbdi.h>
|
||||||
#include <dev/usb/usbdivar.h>
|
#include <dev/usb/usbdivar.h>
|
||||||
|
#include <dev/usb/usb_mem.h>
|
||||||
#include <dev/usb/usb_quirks.h>
|
#include <dev/usb/usb_quirks.h>
|
||||||
|
|
||||||
#include <machine/bus.h>
|
|
||||||
|
|
||||||
#include <dev/usb/uhcireg.h>
|
#include <dev/usb/uhcireg.h>
|
||||||
#include <dev/usb/uhcivar.h>
|
#include <dev/usb/uhcivar.h>
|
||||||
|
|
||||||
@ -78,21 +77,21 @@ struct uhci_pipe {
|
|||||||
/* Control pipe */
|
/* Control pipe */
|
||||||
struct {
|
struct {
|
||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
uhci_dma_t reqdma;
|
usb_dma_t reqdma;
|
||||||
uhci_dma_t datadma;
|
usb_dma_t datadma;
|
||||||
uhci_soft_td_t *setup, *stat, *xferend;
|
uhci_soft_td_t *setup, *stat, *xferend;
|
||||||
u_int length;
|
u_int length;
|
||||||
} ctl;
|
} ctl;
|
||||||
/* Interrupt pipe */
|
/* Interrupt pipe */
|
||||||
struct {
|
struct {
|
||||||
uhci_dma_t datadma;
|
usb_dma_t datadma;
|
||||||
int npoll;
|
int npoll;
|
||||||
uhci_soft_qh_t **qhs;
|
uhci_soft_qh_t **qhs;
|
||||||
} intr;
|
} intr;
|
||||||
/* Bulk pipe */
|
/* Bulk pipe */
|
||||||
struct {
|
struct {
|
||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
uhci_dma_t datadma;
|
usb_dma_t datadma;
|
||||||
u_int length;
|
u_int length;
|
||||||
int isread;
|
int isread;
|
||||||
} bulk;
|
} bulk;
|
||||||
@ -107,8 +106,6 @@ int uhci_global_init_done = 0;
|
|||||||
LIST_HEAD(, uhci_intr_info) uhci_ii_free;
|
LIST_HEAD(, uhci_intr_info) uhci_ii_free;
|
||||||
|
|
||||||
void uhci_busreset __P((uhci_softc_t *));
|
void uhci_busreset __P((uhci_softc_t *));
|
||||||
usbd_status uhci_allocmem __P((uhci_softc_t *,size_t,size_t,uhci_dma_t *));
|
|
||||||
void uhci_freemem __P((uhci_softc_t *, uhci_dma_t *));
|
|
||||||
void uhci_run __P((uhci_softc_t *, int run));
|
void uhci_run __P((uhci_softc_t *, int run));
|
||||||
uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *));
|
uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *));
|
||||||
void uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *));
|
void uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *));
|
||||||
@ -123,7 +120,7 @@ void uhci_exit_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *));
|
|||||||
void uhci_free_std_chain __P((uhci_softc_t *,
|
void uhci_free_std_chain __P((uhci_softc_t *,
|
||||||
uhci_soft_td_t *, uhci_soft_td_t *));
|
uhci_soft_td_t *, uhci_soft_td_t *));
|
||||||
usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, uhci_softc_t *,
|
usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, uhci_softc_t *,
|
||||||
int, int, uhci_dma_t *,
|
int, int, usb_dma_t *,
|
||||||
uhci_soft_td_t **,
|
uhci_soft_td_t **,
|
||||||
uhci_soft_td_t **));
|
uhci_soft_td_t **));
|
||||||
void uhci_timo __P((void *));
|
void uhci_timo __P((void *));
|
||||||
@ -244,7 +241,7 @@ uhci_init(sc)
|
|||||||
int i, j;
|
int i, j;
|
||||||
uhci_soft_qh_t *csqh, *bsqh, *sqh;
|
uhci_soft_qh_t *csqh, *bsqh, *sqh;
|
||||||
uhci_soft_td_t *std;
|
uhci_soft_td_t *std;
|
||||||
uhci_dma_t dma;
|
usb_dma_t dma;
|
||||||
|
|
||||||
DPRINTFN(1,("uhci_init: start\n"));
|
DPRINTFN(1,("uhci_init: start\n"));
|
||||||
|
|
||||||
@ -262,9 +259,9 @@ uhci_init(sc)
|
|||||||
UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
|
UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
|
||||||
|
|
||||||
/* Allocate and initialize real frame array. */
|
/* Allocate and initialize real frame array. */
|
||||||
r = uhci_allocmem(sc, UHCI_FRAMELIST_COUNT *
|
r = usb_allocmem(sc->sc_dmatag,
|
||||||
sizeof(uhci_physaddr_t),
|
UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
|
||||||
UHCI_FRAMELIST_ALIGN, &dma);
|
UHCI_FRAMELIST_ALIGN, &dma);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
return (r);
|
return (r);
|
||||||
sc->sc_pframes = KERNADDR(&dma);
|
sc->sc_pframes = KERNADDR(&dma);
|
||||||
@ -443,7 +440,7 @@ uhci_timo(addr)
|
|||||||
if (reqh->pipe->intrreqh == reqh) {
|
if (reqh->pipe->intrreqh == reqh) {
|
||||||
timeout(uhci_timo, addr, sc->sc_ival);
|
timeout(uhci_timo, addr, sc->sc_ival);
|
||||||
} else {
|
} else {
|
||||||
uhci_freemem(sc, &upipe->u.intr.datadma);
|
usb_freemem(sc->sc_dmatag, &upipe->u.intr.datadma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,13 +693,26 @@ uhci_ii_done(ii, timo)
|
|||||||
u_int32_t tst;
|
u_int32_t tst;
|
||||||
int len, status;
|
int len, status;
|
||||||
|
|
||||||
DPRINTFN(10, ("uhci_check_intr: ii=%p ready\n", ii));
|
DPRINTFN(10, ("uhci_ii_done: ii=%p ready %d\n", ii, timo));
|
||||||
|
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
{
|
||||||
|
int s = splhigh();
|
||||||
|
if (ii->isdone) {
|
||||||
|
printf("uhci_ii_done: is done!\n");
|
||||||
|
splx(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ii->isdone = 1;
|
||||||
|
splx(s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The transfer is done, compute length and status. */
|
/* The transfer is done, compute length and status. */
|
||||||
for (len = status = 0, std = ii->stdstart;
|
for (len = status = 0, std = ii->stdstart;
|
||||||
std != 0;
|
std != 0;
|
||||||
std = std->td->link.std) {
|
std = std->td->link.std) {
|
||||||
tst = std->td->td_status;;
|
tst = std->td->td_status;
|
||||||
status |= tst;
|
status |= tst;
|
||||||
#ifdef USB_DEBUG
|
#ifdef USB_DEBUG
|
||||||
if ((tst & UHCI_TD_ERROR) && uhcidebug) {
|
if ((tst & UHCI_TD_ERROR) && uhcidebug) {
|
||||||
@ -743,6 +753,7 @@ uhci_ii_done(ii, timo)
|
|||||||
break;
|
break;
|
||||||
case UE_ISOCHRONOUS:
|
case UE_ISOCHRONOUS:
|
||||||
printf("uhci_ii_done: ISO??\n");
|
printf("uhci_ii_done: ISO??\n");
|
||||||
|
break;
|
||||||
case UE_BULK:
|
case UE_BULK:
|
||||||
uhci_bulk_done(ii);
|
uhci_bulk_done(ii);
|
||||||
break;
|
break;
|
||||||
@ -842,69 +853,14 @@ uhci_run(sc, run)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Memory management routines.
|
* Memory management routines.
|
||||||
* uhci_allocmem allocates DMAable memory.
|
|
||||||
* uhci_alloc_std allocates TDs
|
* uhci_alloc_std allocates TDs
|
||||||
* uhci_alloc_sqh allocates QHs
|
* uhci_alloc_sqh allocates QHs
|
||||||
* uhci_alloc_buffer allocates transfer buffers.
|
* These two routines do their own free list management,
|
||||||
* The latter three routines do their own free list management,
|
|
||||||
* partly for speed, partly because allocating DMAable memory
|
* partly for speed, partly because allocating DMAable memory
|
||||||
* has page size granularaity so much memory would be wasted if
|
* has page size granularaity so much memory would be wasted if
|
||||||
* only one TD/QH (32 bytes) was placed in each alloacted chunk.
|
* only one TD/QH (32 bytes) was placed in each alloacted chunk.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
usbd_status
|
|
||||||
uhci_allocmem(sc, size, align, p)
|
|
||||||
uhci_softc_t *sc;
|
|
||||||
size_t size;
|
|
||||||
size_t align;
|
|
||||||
uhci_dma_t *p;
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
DPRINTFN(5, ("uhci_allocmem: size=%d align=%d\n", size, align));
|
|
||||||
p->size = size;
|
|
||||||
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
|
|
||||||
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
|
|
||||||
&p->nsegs, BUS_DMA_NOWAIT);
|
|
||||||
if (error)
|
|
||||||
return (USBD_NOMEM);
|
|
||||||
|
|
||||||
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
|
|
||||||
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
|
|
||||||
if (error)
|
|
||||||
goto free;
|
|
||||||
|
|
||||||
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
|
|
||||||
0, BUS_DMA_NOWAIT, &p->map);
|
|
||||||
if (error)
|
|
||||||
goto unmap;
|
|
||||||
|
|
||||||
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->kaddr,p->size, NULL,
|
|
||||||
BUS_DMA_NOWAIT);
|
|
||||||
if (error)
|
|
||||||
goto destroy;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
destroy:
|
|
||||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
|
||||||
unmap:
|
|
||||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
|
||||||
free:
|
|
||||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
|
||||||
return (USBD_NOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
uhci_freemem(sc, p)
|
|
||||||
uhci_softc_t *sc;
|
|
||||||
uhci_dma_t *p;
|
|
||||||
{
|
|
||||||
bus_dmamap_unload(sc->sc_dmatag, p->map);
|
|
||||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
|
||||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
|
||||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
|
||||||
}
|
|
||||||
|
|
||||||
uhci_soft_td_t *
|
uhci_soft_td_t *
|
||||||
uhci_alloc_std(sc)
|
uhci_alloc_std(sc)
|
||||||
uhci_softc_t *sc;
|
uhci_softc_t *sc;
|
||||||
@ -912,7 +868,7 @@ uhci_alloc_std(sc)
|
|||||||
uhci_soft_td_t *std;
|
uhci_soft_td_t *std;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int i;
|
int i;
|
||||||
uhci_dma_t dma;
|
usb_dma_t dma;
|
||||||
|
|
||||||
if (!sc->sc_freetds) {
|
if (!sc->sc_freetds) {
|
||||||
DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
|
DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
|
||||||
@ -920,8 +876,8 @@ uhci_alloc_std(sc)
|
|||||||
M_USBDEV, M_NOWAIT);
|
M_USBDEV, M_NOWAIT);
|
||||||
if (!std)
|
if (!std)
|
||||||
return 0;
|
return 0;
|
||||||
r = uhci_allocmem(sc, UHCI_TD_SIZE * UHCI_TD_CHUNK,
|
r = usb_allocmem(sc->sc_dmatag, UHCI_TD_SIZE * UHCI_TD_CHUNK,
|
||||||
UHCI_TD_ALIGN, &dma);
|
UHCI_TD_ALIGN, &dma);
|
||||||
if (r != USBD_NORMAL_COMPLETION) {
|
if (r != USBD_NORMAL_COMPLETION) {
|
||||||
free(std, M_USBDEV);
|
free(std, M_USBDEV);
|
||||||
return 0;
|
return 0;
|
||||||
@ -946,6 +902,14 @@ uhci_free_std(sc, std)
|
|||||||
uhci_softc_t *sc;
|
uhci_softc_t *sc;
|
||||||
uhci_soft_td_t *std;
|
uhci_soft_td_t *std;
|
||||||
{
|
{
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
#define TD_IS_FREE 0x12345678
|
||||||
|
if (std->td->td_token == TD_IS_FREE) {
|
||||||
|
printf("uhci_free_std: freeing free TD %p\n", std);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std->td->td_token = TD_IS_FREE;
|
||||||
|
#endif
|
||||||
std->td->link.std = sc->sc_freetds;
|
std->td->link.std = sc->sc_freetds;
|
||||||
sc->sc_freetds = std;
|
sc->sc_freetds = std;
|
||||||
}
|
}
|
||||||
@ -957,7 +921,7 @@ uhci_alloc_sqh(sc)
|
|||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int i, offs;
|
int i, offs;
|
||||||
uhci_dma_t dma;
|
usb_dma_t dma;
|
||||||
|
|
||||||
if (!sc->sc_freeqhs) {
|
if (!sc->sc_freeqhs) {
|
||||||
DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
|
DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
|
||||||
@ -965,8 +929,8 @@ uhci_alloc_sqh(sc)
|
|||||||
M_USBDEV, M_NOWAIT);
|
M_USBDEV, M_NOWAIT);
|
||||||
if (!sqh)
|
if (!sqh)
|
||||||
return 0;
|
return 0;
|
||||||
r = uhci_allocmem(sc, UHCI_QH_SIZE * UHCI_QH_CHUNK,
|
r = usb_allocmem(sc->sc_dmatag, UHCI_QH_SIZE * UHCI_QH_CHUNK,
|
||||||
UHCI_QH_ALIGN, &dma);
|
UHCI_QH_ALIGN, &dma);
|
||||||
if (r != USBD_NORMAL_COMPLETION) {
|
if (r != USBD_NORMAL_COMPLETION) {
|
||||||
free(sqh, M_USBDEV);
|
free(sqh, M_USBDEV);
|
||||||
return 0;
|
return 0;
|
||||||
@ -995,47 +959,6 @@ uhci_free_sqh(sc, sqh)
|
|||||||
sc->sc_freeqhs = sqh;
|
sc->sc_freeqhs = sqh;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
void *
|
|
||||||
uhci_alloc_buffer(sc, size)
|
|
||||||
uhci_softc_t *sc;
|
|
||||||
size_t size;
|
|
||||||
{
|
|
||||||
struct uhci_buffer *buf;
|
|
||||||
usbd_status r;
|
|
||||||
int i, offs;
|
|
||||||
uhci_dma_t dma;
|
|
||||||
|
|
||||||
if (!sc->sc_freebuffers) {
|
|
||||||
DPRINTFN(2, ("uhci_alloc_buffer: allocating chunk\n"));
|
|
||||||
r = uhci_allocmem(sc, UHCI_BUFFER_SIZE * BUFFER_CHUNK,
|
|
||||||
0, &dma);
|
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
|
||||||
return 0;
|
|
||||||
for(i = 0; i < BUFFER_CHUNK; i++, sqh++) {
|
|
||||||
offs = i * UHCI_BUFFER_SIZE;
|
|
||||||
sqh->physaddr = DMAADDR(&dma) + offs;
|
|
||||||
sqh->qh = (uhci_qh_t *)
|
|
||||||
((char *)KERNADDR(&dma) + offs);
|
|
||||||
sqh->qh->hlink = sc->sc_freeqhs;
|
|
||||||
sc->sc_freeqhs = sqh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sqh = sc->sc_freeqhs;
|
|
||||||
sc->sc_freeqhs = sqh->qh->hlink;
|
|
||||||
memset(sqh->qh, 0, UHCI_QH_SIZE);
|
|
||||||
return sqh;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
uhci_free_buffer(sc, p, size)
|
|
||||||
uhci_softc_t *sc;
|
|
||||||
void *p;
|
|
||||||
size_t size;
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter a list of transfers onto a control queue.
|
* Enter a list of transfers onto a control queue.
|
||||||
* Called at splusb()
|
* Called at splusb()
|
||||||
@ -1069,7 +992,7 @@ uhci_alloc_std_chain(upipe, sc, len, rd, dma, sp, ep)
|
|||||||
struct uhci_pipe *upipe;
|
struct uhci_pipe *upipe;
|
||||||
uhci_softc_t *sc;
|
uhci_softc_t *sc;
|
||||||
int len, rd;
|
int len, rd;
|
||||||
uhci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
uhci_soft_td_t **sp, **ep;
|
uhci_soft_td_t **sp, **ep;
|
||||||
{
|
{
|
||||||
uhci_soft_td_t *p, *lastp;
|
uhci_soft_td_t *p, *lastp;
|
||||||
@ -1140,7 +1063,7 @@ uhci_device_bulk_transfer(reqh)
|
|||||||
uhci_intr_info_t *ii = upipe->iinfo;
|
uhci_intr_info_t *ii = upipe->iinfo;
|
||||||
uhci_soft_td_t *xfer, *xferend;
|
uhci_soft_td_t *xfer, *xferend;
|
||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
uhci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int len, isread;
|
int len, isread;
|
||||||
int s;
|
int s;
|
||||||
@ -1159,7 +1082,7 @@ uhci_device_bulk_transfer(reqh)
|
|||||||
upipe->u.bulk.isread = isread;
|
upipe->u.bulk.isread = isread;
|
||||||
upipe->u.bulk.length = len;
|
upipe->u.bulk.length = len;
|
||||||
|
|
||||||
r = uhci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto ret1;
|
goto ret1;
|
||||||
r = uhci_alloc_std_chain(upipe, sc, len, isread,
|
r = uhci_alloc_std_chain(upipe, sc, len, isread,
|
||||||
@ -1182,6 +1105,9 @@ uhci_device_bulk_transfer(reqh)
|
|||||||
ii->reqh = reqh;
|
ii->reqh = reqh;
|
||||||
ii->stdstart = xfer;
|
ii->stdstart = xfer;
|
||||||
ii->stdend = xferend;
|
ii->stdend = xferend;
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
ii->isdone = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
sqh->qh->elink = xfer;
|
sqh->qh->elink = xfer;
|
||||||
sqh->qh->qh_elink = xfer->physaddr;
|
sqh->qh->qh_elink = xfer->physaddr;
|
||||||
@ -1206,7 +1132,7 @@ uhci_device_bulk_transfer(reqh)
|
|||||||
|
|
||||||
ret2:
|
ret2:
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
uhci_freemem(sc, dmap);
|
usb_freemem(sc->sc_dmatag, dmap);
|
||||||
ret1:
|
ret1:
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
@ -1263,7 +1189,7 @@ uhci_device_intr_transfer(reqh)
|
|||||||
uhci_intr_info_t *ii = upipe->iinfo;
|
uhci_intr_info_t *ii = upipe->iinfo;
|
||||||
uhci_soft_td_t *xfer, *xferend;
|
uhci_soft_td_t *xfer, *xferend;
|
||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
uhci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int len, i;
|
int len, i;
|
||||||
int s;
|
int s;
|
||||||
@ -1279,7 +1205,7 @@ uhci_device_intr_transfer(reqh)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (USBD_INVAL); /* XXX should it be? */
|
return (USBD_INVAL); /* XXX should it be? */
|
||||||
|
|
||||||
r = uhci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto ret1;
|
goto ret1;
|
||||||
r = uhci_alloc_std_chain(upipe, sc, len, 1, dmap, &xfer, &xferend);
|
r = uhci_alloc_std_chain(upipe, sc, len, 1, dmap, &xfer, &xferend);
|
||||||
@ -1300,6 +1226,9 @@ uhci_device_intr_transfer(reqh)
|
|||||||
ii->reqh = reqh;
|
ii->reqh = reqh;
|
||||||
ii->stdstart = xfer;
|
ii->stdstart = xfer;
|
||||||
ii->stdend = xferend;
|
ii->stdend = xferend;
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
ii->isdone = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n", upipe->u.intr.qhs[0]));
|
DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n", upipe->u.intr.qhs[0]));
|
||||||
for (i = 0; i < upipe->u.intr.npoll; i++) {
|
for (i = 0; i < upipe->u.intr.npoll; i++) {
|
||||||
@ -1321,7 +1250,7 @@ DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n", upipe->u.intr.qhs[0]));
|
|||||||
|
|
||||||
ret2:
|
ret2:
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
uhci_freemem(sc, dmap);
|
usb_freemem(sc->sc_dmatag, dmap);
|
||||||
ret1:
|
ret1:
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
@ -1354,6 +1283,7 @@ uhci_device_intr_abort(reqh)
|
|||||||
{
|
{
|
||||||
struct uhci_pipe *upipe;
|
struct uhci_pipe *upipe;
|
||||||
|
|
||||||
|
DPRINTFN(1, ("uhci_device_intr_abort: reqh=%p\n", reqh));
|
||||||
/* XXX inactivate */
|
/* XXX inactivate */
|
||||||
usbd_delay_ms(2); /* make sure it is finished */
|
usbd_delay_ms(2); /* make sure it is finished */
|
||||||
if (reqh->pipe->intrreqh == reqh) {
|
if (reqh->pipe->intrreqh == reqh) {
|
||||||
@ -1414,7 +1344,7 @@ uhci_device_request(reqh)
|
|||||||
uhci_intr_info_t *ii = upipe->iinfo;
|
uhci_intr_info_t *ii = upipe->iinfo;
|
||||||
uhci_soft_td_t *setup, *xfer, *stat, *next, *xferend;
|
uhci_soft_td_t *setup, *xfer, *stat, *next, *xferend;
|
||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
uhci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
int len;
|
int len;
|
||||||
u_int32_t ls;
|
u_int32_t ls;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
@ -1437,7 +1367,7 @@ uhci_device_request(reqh)
|
|||||||
|
|
||||||
/* Set up data transaction */
|
/* Set up data transaction */
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
r = uhci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
goto ret1;
|
goto ret1;
|
||||||
upipe->pipe.endpoint->toggle = 1;
|
upipe->pipe.endpoint->toggle = 1;
|
||||||
@ -1487,6 +1417,9 @@ uhci_device_request(reqh)
|
|||||||
ii->reqh = reqh;
|
ii->reqh = reqh;
|
||||||
ii->stdstart = setup;
|
ii->stdstart = setup;
|
||||||
ii->stdend = stat;
|
ii->stdend = stat;
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
ii->isdone = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
sqh->qh->elink = setup;
|
sqh->qh->elink = setup;
|
||||||
sqh->qh->qh_elink = setup->physaddr;
|
sqh->qh->qh_elink = setup->physaddr;
|
||||||
@ -1524,7 +1457,7 @@ uhci_device_request(reqh)
|
|||||||
|
|
||||||
ret2:
|
ret2:
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
uhci_freemem(sc, dmap);
|
usb_freemem(sc->sc_dmatag, dmap);
|
||||||
ret1:
|
ret1:
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
@ -1536,7 +1469,7 @@ uhci_intr_done(ii)
|
|||||||
uhci_softc_t *sc = ii->sc;
|
uhci_softc_t *sc = ii->sc;
|
||||||
usbd_request_handle reqh = ii->reqh;
|
usbd_request_handle reqh = ii->reqh;
|
||||||
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
||||||
uhci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
uhci_soft_qh_t *sqh;
|
uhci_soft_qh_t *sqh;
|
||||||
int i, npoll;
|
int i, npoll;
|
||||||
|
|
||||||
@ -1571,13 +1504,16 @@ uhci_intr_done(ii)
|
|||||||
|
|
||||||
ii->stdstart = xfer;
|
ii->stdstart = xfer;
|
||||||
ii->stdend = xferend;
|
ii->stdend = xferend;
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
ii->isdone = 0;
|
||||||
|
#endif
|
||||||
for (i = 0; i < npoll; i++) {
|
for (i = 0; i < npoll; i++) {
|
||||||
sqh = upipe->u.intr.qhs[i];
|
sqh = upipe->u.intr.qhs[i];
|
||||||
sqh->qh->elink = xfer;
|
sqh->qh->elink = xfer;
|
||||||
sqh->qh->qh_elink = xfer->physaddr;
|
sqh->qh->qh_elink = xfer->physaddr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uhci_freemem(sc, dma);
|
usb_freemem(sc->sc_dmatag, dma);
|
||||||
ii->stdstart = 0; /* mark as inactive */
|
ii->stdstart = 0; /* mark as inactive */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1591,11 +1527,13 @@ uhci_ctrl_done(ii)
|
|||||||
usbd_request_handle reqh = ii->reqh;
|
usbd_request_handle reqh = ii->reqh;
|
||||||
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
||||||
u_int len = upipe->u.ctl.length;
|
u_int len = upipe->u.ctl.length;
|
||||||
uhci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
uhci_td_t *htd = ii->stdstart->td;
|
uhci_td_t *htd = ii->stdstart->td;
|
||||||
|
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
if (!reqh->isreq)
|
if (!reqh->isreq)
|
||||||
panic("uhci_ctrl_done: not a request\n");
|
panic("uhci_ctrl_done: not a request\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
LIST_REMOVE(ii, list); /* remove from active list */
|
LIST_REMOVE(ii, list); /* remove from active list */
|
||||||
|
|
||||||
@ -1606,7 +1544,7 @@ uhci_ctrl_done(ii)
|
|||||||
if (reqh->request.bmRequestType & UT_READ)
|
if (reqh->request.bmRequestType & UT_READ)
|
||||||
memcpy(reqh->buffer, KERNADDR(dma), len);
|
memcpy(reqh->buffer, KERNADDR(dma), len);
|
||||||
uhci_free_std_chain(sc, htd->link.std, ii->stdend);
|
uhci_free_std_chain(sc, htd->link.std, ii->stdend);
|
||||||
uhci_freemem(sc, dma);
|
usb_freemem(sc->sc_dmatag, dma);
|
||||||
}
|
}
|
||||||
DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", reqh->actlen));
|
DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", reqh->actlen));
|
||||||
}
|
}
|
||||||
@ -1620,7 +1558,7 @@ uhci_bulk_done(ii)
|
|||||||
usbd_request_handle reqh = ii->reqh;
|
usbd_request_handle reqh = ii->reqh;
|
||||||
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
||||||
u_int len = upipe->u.bulk.length;
|
u_int len = upipe->u.bulk.length;
|
||||||
uhci_dma_t *dma;
|
usb_dma_t *dma;
|
||||||
uhci_td_t *htd = ii->stdstart->td;
|
uhci_td_t *htd = ii->stdstart->td;
|
||||||
|
|
||||||
LIST_REMOVE(ii, list); /* remove from active list */
|
LIST_REMOVE(ii, list); /* remove from active list */
|
||||||
@ -1632,7 +1570,7 @@ uhci_bulk_done(ii)
|
|||||||
if (upipe->u.bulk.isread && len != 0)
|
if (upipe->u.bulk.isread && len != 0)
|
||||||
memcpy(reqh->buffer, KERNADDR(dma), len);
|
memcpy(reqh->buffer, KERNADDR(dma), len);
|
||||||
uhci_free_std_chain(sc, htd->link.std, 0);
|
uhci_free_std_chain(sc, htd->link.std, 0);
|
||||||
uhci_freemem(sc, dma);
|
usb_freemem(sc->sc_dmatag, dma);
|
||||||
}
|
}
|
||||||
DPRINTFN(4, ("uhci_bulk_done: length=%d\n", reqh->actlen));
|
DPRINTFN(4, ("uhci_bulk_done: length=%d\n", reqh->actlen));
|
||||||
/* XXX compute new toggle */
|
/* XXX compute new toggle */
|
||||||
@ -1796,8 +1734,9 @@ uhci_open(pipe)
|
|||||||
uhci_free_std(sc, upipe->u.ctl.setup);
|
uhci_free_std(sc, upipe->u.ctl.setup);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
r = uhci_allocmem(sc, sizeof(uhci_dma_t), 0,
|
r = usb_allocmem(sc->sc_dmatag,
|
||||||
&upipe->u.ctl.reqdma);
|
sizeof(usb_device_request_t),
|
||||||
|
0, &upipe->u.ctl.reqdma);
|
||||||
if (r != USBD_NORMAL_COMPLETION) {
|
if (r != USBD_NORMAL_COMPLETION) {
|
||||||
uhci_free_sqh(sc, upipe->u.ctl.sqh);
|
uhci_free_sqh(sc, upipe->u.ctl.sqh);
|
||||||
uhci_free_std(sc, upipe->u.ctl.setup);
|
uhci_free_std(sc, upipe->u.ctl.setup);
|
||||||
@ -2269,7 +2208,7 @@ uhci_root_intr_transfer(reqh)
|
|||||||
usbd_pipe_handle pipe = reqh->pipe;
|
usbd_pipe_handle pipe = reqh->pipe;
|
||||||
uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
|
uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
|
||||||
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
|
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
|
||||||
uhci_dma_t *dmap;
|
usb_dma_t *dmap;
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
@ -2281,7 +2220,7 @@ uhci_root_intr_transfer(reqh)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (USBD_INVAL); /* XXX should it be? */
|
return (USBD_INVAL); /* XXX should it be? */
|
||||||
|
|
||||||
r = uhci_allocmem(sc, len, 0, dmap);
|
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||||
if (r != USBD_NORMAL_COMPLETION)
|
if (r != USBD_NORMAL_COMPLETION)
|
||||||
return (r);
|
return (r);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: uhcivar.h,v 1.1 1998/07/12 19:51:59 augustss Exp $ */
|
/* $NetBSD: uhcivar.h,v 1.2 1998/07/24 21:09:08 augustss Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
@ -54,17 +54,6 @@
|
|||||||
typedef struct uhci_soft_qh uhci_soft_qh_t;
|
typedef struct uhci_soft_qh uhci_soft_qh_t;
|
||||||
typedef struct uhci_soft_td uhci_soft_td_t;
|
typedef struct uhci_soft_td uhci_soft_td_t;
|
||||||
|
|
||||||
typedef struct uhci_dma {
|
|
||||||
bus_dmamap_t map;
|
|
||||||
caddr_t kaddr;
|
|
||||||
bus_dma_segment_t segs[1];
|
|
||||||
int nsegs;
|
|
||||||
size_t size;
|
|
||||||
struct uhci_dma *next;
|
|
||||||
} uhci_dma_t;
|
|
||||||
#define DMAADDR(dma) ((dma)->segs[0].ds_addr)
|
|
||||||
#define KERNADDR(dma) ((void *)((dma)->kaddr))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An interrupt info struct contains the information needed to
|
* An interrupt info struct contains the information needed to
|
||||||
* execute a requested routine when the controller generates an
|
* execute a requested routine when the controller generates an
|
||||||
@ -78,6 +67,9 @@ typedef struct uhci_intr_info {
|
|||||||
uhci_soft_td_t *stdstart;
|
uhci_soft_td_t *stdstart;
|
||||||
uhci_soft_td_t *stdend;
|
uhci_soft_td_t *stdend;
|
||||||
LIST_ENTRY(uhci_intr_info) list;
|
LIST_ENTRY(uhci_intr_info) list;
|
||||||
|
#ifdef DIAGNOSTIC
|
||||||
|
int isdone;
|
||||||
|
#endif
|
||||||
} uhci_intr_info_t;
|
} uhci_intr_info_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -158,7 +150,7 @@ typedef struct uhci_softc {
|
|||||||
#define UHCI_HAS_LOCK 1
|
#define UHCI_HAS_LOCK 1
|
||||||
#define UHCI_WANT_LOCK 2
|
#define UHCI_WANT_LOCK 2
|
||||||
|
|
||||||
uhci_dma_t *sc_mallocs;
|
usb_dma_t *sc_mallocs;
|
||||||
} uhci_softc_t;
|
} uhci_softc_t;
|
||||||
|
|
||||||
usbd_status uhci_init __P((uhci_softc_t *));
|
usbd_status uhci_init __P((uhci_softc_t *));
|
||||||
|
238
sys/dev/usb/usb_mem.c
Normal file
238
sys/dev/usb/usb_mem.c
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/* $NetBSD: usb_mem.c,v 1.1 1998/07/24 21:09:08 augustss Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||||
|
* Carlstedt Research & Technology
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the NetBSD
|
||||||
|
* Foundation, Inc. and its contributors.
|
||||||
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USB DMA memory allocation.
|
||||||
|
* We need to allocate a lot of small (many 8 byte, some larger)
|
||||||
|
* memory blocks that can be used for DMA. Using the bus_dma
|
||||||
|
* routines directly would uncur large overheads in space and time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/usb/usb.h>
|
||||||
|
#include <dev/usb/usbdi.h>
|
||||||
|
#include <dev/usb/usb_mem.h>
|
||||||
|
|
||||||
|
#ifdef USB_DEBUG
|
||||||
|
#define DPRINTF(x) if (usbdebug) printf x
|
||||||
|
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||||
|
extern int usbdebug;
|
||||||
|
#else
|
||||||
|
#define DPRINTF(x)
|
||||||
|
#define DPRINTFN(n,x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USB_MEM_SMALL 64
|
||||||
|
#define USB_MEM_CHUNKS 64
|
||||||
|
#define USB_MEM_BLOCK (USB_MEM_SMALL * USB_MEM_CHUNKS)
|
||||||
|
|
||||||
|
/* This struct is overlayed on free fragments. */
|
||||||
|
struct usb_frag_dma {
|
||||||
|
usb_dma_block_t *block;
|
||||||
|
u_int offs;
|
||||||
|
LIST_ENTRY(usb_frag_dma) next;
|
||||||
|
};
|
||||||
|
|
||||||
|
usbd_status usb_block_allocmem
|
||||||
|
__P((bus_dma_tag_t, size_t, size_t, usb_dma_block_t **));
|
||||||
|
void usb_block_real_freemem __P((usb_dma_block_t *));
|
||||||
|
void usb_block_freemem __P((usb_dma_block_t *));
|
||||||
|
|
||||||
|
LIST_HEAD(, usb_block_dma) usb_blk_freelist =
|
||||||
|
LIST_HEAD_INITIALIZER(usb_blk_freelist);
|
||||||
|
/* XXX should have different free list for different tags */
|
||||||
|
LIST_HEAD(, usb_frag_dma) usb_frag_freelist =
|
||||||
|
LIST_HEAD_INITIALIZER(usb_frag_freelist);
|
||||||
|
|
||||||
|
usbd_status
|
||||||
|
usb_block_allocmem(tag, size, align, dmap)
|
||||||
|
bus_dma_tag_t tag;
|
||||||
|
size_t size;
|
||||||
|
size_t align;
|
||||||
|
usb_dma_block_t **dmap;
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
usb_dma_block_t *p;
|
||||||
|
|
||||||
|
DPRINTFN(5, ("usb_block_allocmem: size=%d align=%d\n", size, align));
|
||||||
|
|
||||||
|
/* First check the free list. */
|
||||||
|
for (p = LIST_FIRST(&usb_blk_freelist); p; p = LIST_NEXT(p, next)) {
|
||||||
|
if (p->tag == tag && p->size >= size && p->align >= align) {
|
||||||
|
LIST_REMOVE(p, next);
|
||||||
|
*dmap = p;
|
||||||
|
DPRINTFN(6, ("usb_block_allocmem: free list size=%d\n",
|
||||||
|
p->size));
|
||||||
|
return (USBD_NORMAL_COMPLETION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTFN(6, ("usb_block_allocmem: no free\n"));
|
||||||
|
p = malloc(sizeof *p, M_USB, M_NOWAIT);
|
||||||
|
if (p == 0)
|
||||||
|
return (USBD_NOMEM);
|
||||||
|
*dmap = p;
|
||||||
|
|
||||||
|
p->tag = tag;
|
||||||
|
p->size = size;
|
||||||
|
p->align = align;
|
||||||
|
error = bus_dmamem_alloc(tag, p->size, align, 0,
|
||||||
|
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
|
||||||
|
&p->nsegs, BUS_DMA_NOWAIT);
|
||||||
|
if (error)
|
||||||
|
return (USBD_NOMEM);
|
||||||
|
|
||||||
|
error = bus_dmamem_map(tag, p->segs, p->nsegs, p->size,
|
||||||
|
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
|
||||||
|
if (error)
|
||||||
|
goto free;
|
||||||
|
|
||||||
|
error = bus_dmamap_create(tag, p->size, 1, p->size,
|
||||||
|
0, BUS_DMA_NOWAIT, &p->map);
|
||||||
|
if (error)
|
||||||
|
goto unmap;
|
||||||
|
|
||||||
|
error = bus_dmamap_load(tag, p->map, p->kaddr,p->size, NULL,
|
||||||
|
BUS_DMA_NOWAIT);
|
||||||
|
if (error)
|
||||||
|
goto destroy;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
destroy:
|
||||||
|
bus_dmamap_destroy(tag, p->map);
|
||||||
|
unmap:
|
||||||
|
bus_dmamem_unmap(tag, p->kaddr, p->size);
|
||||||
|
free:
|
||||||
|
bus_dmamem_free(tag, p->segs, p->nsegs);
|
||||||
|
return (USBD_NOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_block_real_freemem(p)
|
||||||
|
usb_dma_block_t *p;
|
||||||
|
{
|
||||||
|
bus_dmamap_unload(p->tag, p->map);
|
||||||
|
bus_dmamap_destroy(p->tag, p->map);
|
||||||
|
bus_dmamem_unmap(p->tag, p->kaddr, p->size);
|
||||||
|
bus_dmamem_free(p->tag, p->segs, p->nsegs);
|
||||||
|
free(p, M_USB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not free the memory unconditionally since we might be called
|
||||||
|
* from an interrupt context and that is BAD.
|
||||||
|
* XXX when you we really free?
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
usb_block_freemem(p)
|
||||||
|
usb_dma_block_t *p;
|
||||||
|
{
|
||||||
|
DPRINTFN(6, ("usb_block_freemem: size=%d\n", p->size));
|
||||||
|
LIST_INSERT_HEAD(&usb_blk_freelist, p, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
usbd_status
|
||||||
|
usb_allocmem(tag, size, align, p)
|
||||||
|
bus_dma_tag_t tag;
|
||||||
|
size_t size;
|
||||||
|
size_t align;
|
||||||
|
usb_dma_t *p;
|
||||||
|
{
|
||||||
|
usbd_status r;
|
||||||
|
struct usb_frag_dma *f;
|
||||||
|
usb_dma_block_t *b;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* If the request is large then just use a full block. */
|
||||||
|
if (size > USB_MEM_SMALL || align > USB_MEM_SMALL) {
|
||||||
|
DPRINTFN(1, ("usb_allocmem: large alloc %d\n", (int)size));
|
||||||
|
size = (size + USB_MEM_BLOCK - 1) & ~(USB_MEM_BLOCK - 1);
|
||||||
|
r = usb_block_allocmem(tag, size, align, &p->block);
|
||||||
|
if (r == USBD_NORMAL_COMPLETION) {
|
||||||
|
p->block->fullblock = 1;
|
||||||
|
p->offs = 0;
|
||||||
|
}
|
||||||
|
return (r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for free fragments. */
|
||||||
|
for (f = LIST_FIRST(&usb_frag_freelist); f; f = LIST_NEXT(f, next))
|
||||||
|
if (f->block->tag == tag)
|
||||||
|
break;
|
||||||
|
if (!f) {
|
||||||
|
DPRINTFN(1, ("usb_allocmem: adding fragments\n"));
|
||||||
|
r = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL, &b);
|
||||||
|
for (i = 0; i < USB_MEM_BLOCK; i += USB_MEM_SMALL) {
|
||||||
|
f = (struct usb_frag_dma *)(b->kaddr + i);
|
||||||
|
f->block = b;
|
||||||
|
f->offs = i;
|
||||||
|
LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
|
||||||
|
}
|
||||||
|
f = LIST_FIRST(&usb_frag_freelist);
|
||||||
|
}
|
||||||
|
p->block = f->block;
|
||||||
|
p->offs = f->offs;
|
||||||
|
LIST_REMOVE(f, next);
|
||||||
|
DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size));
|
||||||
|
return (USBD_NORMAL_COMPLETION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_freemem(tag, p)
|
||||||
|
bus_dma_tag_t tag;
|
||||||
|
usb_dma_t *p;
|
||||||
|
{
|
||||||
|
struct usb_frag_dma *f;
|
||||||
|
|
||||||
|
if (p->block->fullblock) {
|
||||||
|
usb_block_freemem(p->block);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f = KERNADDR(p);
|
||||||
|
f->block = p->block;
|
||||||
|
f->offs = p->offs;
|
||||||
|
LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
|
||||||
|
DPRINTFN(5, ("usb_freemem: frag=%p\n", f));
|
||||||
|
}
|
60
sys/dev/usb/usb_mem.h
Normal file
60
sys/dev/usb/usb_mem.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/* $NetBSD: usb_mem.h,v 1.1 1998/07/24 21:09:08 augustss Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||||
|
* Carlstedt Research & Technology
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the NetBSD
|
||||||
|
* Foundation, Inc. and its contributors.
|
||||||
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct usb_block_dma {
|
||||||
|
bus_dma_tag_t tag;
|
||||||
|
bus_dmamap_t map;
|
||||||
|
caddr_t kaddr;
|
||||||
|
bus_dma_segment_t segs[1];
|
||||||
|
int nsegs;
|
||||||
|
size_t size;
|
||||||
|
size_t align;
|
||||||
|
int fullblock;
|
||||||
|
LIST_ENTRY(usb_block_dma) next;
|
||||||
|
} usb_dma_block_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
usb_dma_block_t *block;
|
||||||
|
u_int offs;
|
||||||
|
} usb_dma_t;
|
||||||
|
|
||||||
|
#define DMAADDR(dma) ((dma)->block->segs[0].ds_addr + (dma)->offs)
|
||||||
|
#define KERNADDR(dma) ((void *)((dma)->block->kaddr + (dma)->offs))
|
||||||
|
|
||||||
|
usbd_status usb_allocmem __P((bus_dma_tag_t, size_t, size_t, usb_dma_t *));
|
||||||
|
void usb_freemem __P((bus_dma_tag_t, usb_dma_t *));
|
Loading…
Reference in New Issue
Block a user