Includes
#include <dev/usb/usb.h> #include <dev/usb/usbdi.h>
usb_error_t usb_pipe_open(struct usb_device *udev,
const uint8_t *ifaces, struct usb_pipe **,
const struct usb_config *, int count,
void *priv);
void usb_pipe_halt(struct usb_pipe *);
void usb_pipe_ready(struct usb_pipe *);
void usb_pipe_drain(struct usb_pipe *);
void usb_pipe_close(struct usb_pipe **, int count);
void usb_clear_stall(struct usb_pipe *);
struct usb_urb *usb_get_urb(struct usb_pipe *, int flags);
int usb_set_frame_data(struct usb_urb *, int index, void *, int len);
int usb_copyin_urb(struct usb_urb *, void *, int offset, int len);
int usb_copyout_urb(struct usb_urb *, void *, int offset, int len);
void usb_cancel_urb(struct usb_urb *);
void usb_free_urb(struct usb_urb *);
void usb_submit_urb(struct usb_pipe *, struct usb_urb *, int flags);
Structs
struct usb_pipe
A queue for processing urb pointers. Has one dma map and will reload the dma if the current urb is different to the one previously loaded. The pipe has a private mutex for queueing and dequeueing, it does not need to share the mutex with the driver.
struct usb_urb
A data buffer. The memory can be preallocated (fixed size) or passed in from an external buffer. The urb has a single reference and does not need to be locked.
Notes:
- usb_pipe_open() will preallocate the requested number of urb structures and keep on a free list
- usb_get_urb() will get a urb from the free list.
- usb_free_urb() does not actually free the memory, it puts the urb on the pipe free list
- usb_pipe_halt() cancels all pending urbs and sets the pipe to blocking
- usb_pipe_ready() will unblock the pipe and start processing anything in the urb queue
- usb_submit_urb() will put the urb on the processing list
Examples (overly simplified to show basic working)
example 1, external buffer
ep_config {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.bufsize = 0, /* external */
.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
.callback = write_callback,
.timeout = 5000, /* ms */
.min_urb = 8,
.max_urb = 8,
} {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.bufsize = 0, /* external */
.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
.callback = read_callback,
.min_urb = 8,
.max_urb = 8,
}
attach()
error = usb_pipe_open(uaa->device,
&iface_index, sc->sc_xfer, ep_config,
XXX_N_TRANSFER, sc);
detach()
usb_pipe_close(sc->sc_xfer, XXX_N_TRANSFER);
init()
/* will return up to 'max_urb' times */
while((urb = usb_get_urb(sc->sc_readxfer) != NULL) {
m = m_getcl(M_WAIT, MT_DATA, M_PKTHDR);
usb_set_frame_data(urb, 0, m->data, m->len);
usb_set_priv(urb, m);
usb_submit_urb(urb);
}
usb_pipe_ready(sc->sc_readxfer);
usb_pipe_ready(sc->sc_writexfer);
stop()
usb_pipe_halt(sc->sc_readxfer);
usb_pipe_halt(sc->sc_writexfer);
start(m)
urb = usb_get_urb(sc->sc_writexfer);
if (urb == NULL)
return;
usb_set_frame_data(urb, 0, m->data, m->len);
usb_set_priv(urb, m);
usb_submit_urb(urb);
write_callback(urb, error)
pipe = urb->pipe;
if (error)
usb_clear_stall(pipe);
m = usb_get_priv(urb);
usb_free_urb(urb);
m_freem(m);
start() /* try to send more */
read_callback(urb, error)
pipe = urb->pipe;
if (error)
usb_clear_stall(pipe);
m = usb_get_priv(urb);
mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (!mnew) {
ifp->if_ierrors++;
goto skip;
}
m_input(m);
usb_set_frame_data(urb, 0, mnew->data, mnew->len);
usb_set_priv(urb, mnew);
skip:
usb_submit_urb(urb);
example 2, internal buffer
ep_config {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.bufsize = 512,
.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
.callback = write_callback,
.timeout = 5000, /* ms */
.min_urb = 4,
.max_urb = 4,
} {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.bufsize = 512,
.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
.callback = read_callback,
.max_urb = 4,
}
attach()
error = usb_pipe_open(uaa->device,
&iface_index, sc->sc_xfer, ep_config,
XXX_N_TRANSFER, sc);
detach()
usb_pipe_close(sc->sc_xfer, XXX_N_TRANSFER);
ttyopen()
/* will return up to 'max_urb' times */
while((urb = usb_get_urb(sc->sc_readxfer) != NULL) {
usb_submit_urb(urb);
}
usb_pipe_ready(sc->sc_readxfer);
usb_pipe_ready(sc->sc_writexfer);
ttyclose()
usb_pipe_halt(sc->sc_readxfer);
usb_pipe_halt(sc->sc_writexfer);
ttywakeup()
urb = usb_get_urb(sc->sc_writexfer);
if (urb == NULL)
return; /* all buffers in flight */
ttydisc_getc(urb->data, urb->len);
usb_submit_urb(urb);
write_callback(urb, error)
pipe = urb->pipe;
if (error)
usb_clear_stall(pipe);
/* refill buffer */
if (ttydisc_getc(urb->data, urb->len))
usb_submit_urb(urb);
else
usb_free_urb(urb);
read_callback(urb, error)
pipe = urb->pipe;
if (error)
usb_clear_stall(pipe);
tty_rint(urb->data, urb->len);
usb_submit_urb(urb);