diff options
Diffstat (limited to 'firmware/src/os/usb_handler.c')
-rw-r--r-- | firmware/src/os/usb_handler.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/firmware/src/os/usb_handler.c b/firmware/src/os/usb_handler.c new file mode 100644 index 0000000..274353c --- /dev/null +++ b/firmware/src/os/usb_handler.c @@ -0,0 +1,88 @@ +/* OpenPCD USB handler - handle incoming USB requests on OUT pipe + * (C) 2006 by Harald Welte + */ + +#include <sys/types.h> +#include <errno.h> +#include <string.h> + +#include <openpcd.h> + +#include <os/pcd_enumerate.h> +#include <os/usb_handler.h> +#include <os/req_ctx.h> +#include <os/led.h> +#include <os/dbgu.h> + +#include "../openpcd.h" + +static usb_cmd_fn *cmd_hdlrs[16]; + +int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class) +{ + cmd_hdlrs[class] = hdlr; + return 0; +} + +void usb_hdlr_unregister(u_int8_t class) +{ + cmd_hdlrs[class] = NULL; +} + +static int usb_in(struct req_ctx *rctx) +{ + struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0]; + struct openpcd_hdr *pih = (struct openpcd_hdr *) &rctx->tx.data[0]; + usb_cmd_fn *hdlr; + + DEBUGP("usb_in(cls=%d) ", OPENPCD_CMD_CLS(poh->cmd)); + + if (rctx->rx.tot_len < sizeof(*poh)) + return -EINVAL; + + memcpy(pih, poh, sizeof(*poh)); + rctx->tx.tot_len = sizeof(*poh); + + hdlr = cmd_hdlrs[OPENPCD_CMD_CLS(poh->cmd)]; + if (hdlr) + return (hdlr)(rctx); + else + DEBUGPCR("no handler for this class\n"); +} + +/* Process all pending request contexts that want to Tx on either + * IN or INTERRUPT endpoint */ +void usb_out_process(void) +{ + struct req_ctx *rctx; + + while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_PENDING, + RCTX_STATE_UDP_EP3_BUSY)) { + DEBUGPCRF("EP3_BUSY for ctx %u", req_ctx_num(rctx)); + if (udp_refill_ep(3, rctx) < 0) + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP3_PENDING); + } + + while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_PENDING, + RCTX_STATE_UDP_EP2_BUSY)) { + DEBUGPCRF("EP2_BUSY for ctx %u", req_ctx_num(rctx)); + if (udp_refill_ep(2, rctx) < 0) + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + } +} + +/* process incoming USB packets (OUT pipe) that have already been + * put into request contexts by the UDP IRQ handler */ +void usb_in_process(void) +{ + struct req_ctx *rctx; + + while (rctx = req_ctx_find_get(RCTX_STATE_UDP_RCV_DONE, + RCTX_STATE_MAIN_PROCESSING)) { + DEBUGPCRF("found used ctx %u: len=%u", + req_ctx_num(rctx), rctx->rx.tot_len); + usb_in(rctx); + } + udp_unthrottle(); +} + |