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:

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);

USB/USBPeriphAPI (last edited 2009-05-22T06:14:20+0000 by AndrewThompson)