Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| usb:usbperiphapi [2009/05/21 22:31] – AndrewThompson | usb:usbperiphapi [2009/05/22 06:14] (current) – AndrewThompson | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | X | + | Includes |
| + | |||
| + | < | ||
| + | #include < | ||
| + | #include < | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | usb_error_t | ||
| + | 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 | ||
| + | int | ||
| + | int | ||
| + | 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, | ||
| + | .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, | ||
| + | .callback = read_callback, | ||
| + | .min_urb = 8, | ||
| + | .max_urb = 8, | ||
| + | } | ||
| + | |||
| + | attach() | ||
| + | error = usb_pipe_open(uaa-> | ||
| + | & | ||
| + | | ||
| + | |||
| + | detach() | ||
| + | | ||
| + | |||
| + | init() | ||
| + | /* will return up to ' | ||
| + | | ||
| + | m = m_getcl(M_WAIT, | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | | ||
| + | | ||
| + | |||
| + | stop() | ||
| + | | ||
| + | | ||
| + | |||
| + | start(m) | ||
| + | urb = usb_get_urb(sc-> | ||
| + | if (urb == NULL) | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | write_callback(urb, | ||
| + | pipe = urb-> | ||
| + | if (error) | ||
| + | | ||
| + | m = usb_get_priv(urb); | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | read_callback(urb, | ||
| + | pipe = urb-> | ||
| + | if (error) | ||
| + | | ||
| + | m = usb_get_priv(urb); | ||
| + | mnew = m_getcl(M_DONTWAIT, | ||
| + | if (!mnew) { | ||
| + | ifp-> | ||
| + | goto skip; | ||
| + | } | ||
| + | | ||
| + | | ||
| + | | ||
| + | skip: | ||
| + | | ||
| + | </ | ||
| + | |||
| + | ==== example 2, internal buffer ==== | ||
| + | |||
| + | < | ||
| + | ep_config { | ||
| + | .type = UE_BULK, | ||
| + | .endpoint = UE_ADDR_ANY, | ||
| + | .direction = UE_DIR_OUT, | ||
| + | .bufsize = 512, | ||
| + | .flags = {.pipe_bof = 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, | ||
| + | .callback = read_callback, | ||
| + | .max_urb = 4, | ||
| + | } | ||
| + | |||
| + | attach() | ||
| + | error = usb_pipe_open(uaa-> | ||
| + | & | ||
| + | | ||
| + | |||
| + | detach() | ||
| + | | ||
| + | |||
| + | ttyopen() | ||
| + | /* will return up to ' | ||
| + | | ||
| + | | ||
| + | } | ||
| + | | ||
| + | | ||
| + | |||
| + | ttyclose() | ||
| + | | ||
| + | | ||
| + | |||
| + | ttywakeup() | ||
| + | urb = usb_get_urb(sc-> | ||
| + | if (urb == NULL) | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | write_callback(urb, | ||
| + | pipe = urb-> | ||
| + | if (error) | ||
| + | | ||
| + | /* refill buffer */ | ||
| + | if (ttydisc_getc(urb-> | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | read_callback(urb, | ||
| + | pipe = urb-> | ||
| + | if (error) | ||
| + | | ||
| + | | ||
| + | | ||
| + | </ | ||