123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- #include <stdint.h>
- #include <stdbool.h>
- #include <string.h>
- #include "console.h"
- #include "usb_priv.h"
- static inline void
- usb_ep0_out_queue_bd(bool setup, int ofs, int len, bool stall)
- {
- int bdi = setup ? 1 : 0;
- usb_ep_regs[0].out.bd[bdi].ptr = ofs;
- usb_ep_regs[0].out.bd[bdi].csr = stall ? USB_BD_STATE_RDY_STALL : (USB_BD_STATE_RDY_DATA | USB_BD_LEN(len));
- }
- static inline void
- usb_ep0_in_queue_bd(int ofs, int len, bool stall)
- {
- usb_ep_regs[0].in.bd[0].ptr = ofs;
- usb_ep_regs[0].in.bd[0].csr = stall ? USB_BD_STATE_RDY_STALL : (USB_BD_STATE_RDY_DATA | USB_BD_LEN(len));
- }
- static inline uint32_t
- usb_ep0_out_peek_bd(bool setup)
- {
- int bdi = setup ? 1 : 0;
- return usb_ep_regs[0].out.bd[bdi].csr;
- }
- static inline uint32_t
- usb_ep0_in_peek_bd(void)
- {
- return usb_ep_regs[0].in.bd[0].csr;
- }
- static inline void
- usb_ep0_out_done_bd(bool setup)
- {
- int bdi = setup ? 1 : 0;
- usb_ep_regs[0].out.bd[bdi].csr = 0;
- }
- static inline void
- usb_ep0_in_done_bd(void)
- {
- usb_ep_regs[0].in.bd[0].csr = 0;
- }
- static void
- usb_handle_control_data()
- {
-
- if (g_usb.ctrl.state == DATA_IN) {
-
- int xflen = g_usb.ctrl.len - g_usb.ctrl.ofs;
- if (xflen > 64)
- xflen = 64;
-
- if (xflen)
- usb_data_write(0, &g_usb.ctrl.data.in[g_usb.ctrl.ofs], xflen);
- usb_ep0_in_queue_bd(0, xflen, false);
-
- g_usb.ctrl.ofs += xflen;
-
- if (xflen < 64) {
- usb_ep0_out_queue_bd(false, 0, 0, false);
- g_usb.ctrl.state = STATUS_DONE_OUT;
- }
- }
-
- if (g_usb.ctrl.state == DATA_OUT) {
- if (g_usb.ctrl.ofs == g_usb.ctrl.len)
- {
-
- usb_ep0_in_queue_bd(0, 0, false);
- g_usb.ctrl.state = STATUS_DONE_IN;
- }
- else
- {
-
- }
- }
- }
- static void
- usb_handle_control_request(struct usb_ctrl_req_hdr *req)
- {
- bool handled = false;
-
- g_usb.ctrl.data.in = NULL;
- g_usb.ctrl.data.out = NULL;
- g_usb.ctrl.len = req->wLength;
- g_usb.ctrl.ofs = 0;
-
- switch (req->bRequest)
- {
- case USB_REQ_GET_STATUS:
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- break;
- case USB_REQ_SET_ADDRESS:
- handled = true;
- break;
- case USB_REQ_GET_DESCRIPTOR:
- {
- int idx = req->wValue & 0xff;
- switch (req->wValue & 0xff00)
- {
- case 0x0100:
- g_usb.ctrl.data.out = usb_get_device_desc(&g_usb.ctrl.len);
- break;
- case 0x0200:
- g_usb.ctrl.data.out = usb_get_config_desc(&g_usb.ctrl.len, idx);
- break;
- case 0x0300:
- g_usb.ctrl.data.out = usb_get_string_desc(&g_usb.ctrl.len, idx);
- break;
- }
- handled = g_usb.ctrl.data.out != NULL;
- break;
- }
- case USB_REQ_SET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- break;
- case USB_REQ_SET_CONFIGURATION:
- handled = true;
- break;
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_SET_INTERFACE:
- case USB_REQ_SYNCHFRAME:
- default:
- break;
- }
-
- if (!handled) {
- if (USB_REQ_IS_READ(req)) {
-
- g_usb.ctrl.state = STATUS_DONE_IN;
- usb_ep0_in_queue_bd(0, 0, true);
- } else if (req->wLength) {
-
- g_usb.ctrl.state = STATUS_DONE_OUT;
- usb_ep0_out_queue_bd(false, 0, 0, true);
- } else {
-
- g_usb.ctrl.state = STATUS_DONE_IN;
- usb_ep0_in_queue_bd(0, 0, true);
- }
- return;
- }
-
- g_usb.ctrl.state = USB_REQ_IS_READ(req) ? DATA_IN : DATA_OUT;
- if (g_usb.ctrl.len > req->wLength)
- g_usb.ctrl.len = req->wLength;
- usb_handle_control_data();
- }
- void
- usb_ep0_run(void)
- {
- uint32_t bds_setup, bds_out, bds_in;
- bool acted;
- do {
-
- acted = false;
-
- bds_out = usb_ep0_out_peek_bd(false);
- bds_setup = usb_ep0_out_peek_bd(true);
- bds_in = usb_ep0_in_peek_bd();
-
- if (g_usb.ctrl.state == STATUS_DONE_IN) {
- if ((bds_in & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)
- {
- g_usb.ctrl.state = IDLE;
- usb_ep0_in_done_bd();
- acted = true;
- continue;
- }
- }
-
- if (g_usb.ctrl.state == STATUS_DONE_OUT) {
- if ((bds_out & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)
- {
- if ((bds_out & USB_BD_LEN_MSK) == 2) {
- g_usb.ctrl.state = IDLE;
- usb_ep0_out_done_bd(false);
- acted = true;
- continue;
- } else {
- puts("[!] Got a non ZLP as a status stage packet ?!?\n");
- }
- }
- }
-
- if ((bds_setup & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
- {
- usb_ep0_out_queue_bd(true, 0, 64, false);
- acted = true;
- continue;
- }
- if ((bds_out & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
- {
- usb_ep0_out_queue_bd(false, 64, 64, false);
- acted = true;
- continue;
- }
-
- if ((bds_setup & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)
- {
-
- if (!(bds_setup & USB_BD_IS_SETUP)) {
- puts("[!] Got non-SETUP in the SETUP BD !?!\n");
- }
-
- if (g_usb.ctrl.state != IDLE) {
- puts("[!] Got SETUP while busy !??\n");
- }
-
- usb_ep0_out_done_bd(false);
- usb_ep0_in_done_bd();
-
- usb_ep_regs[0].in.status = USB_EP_TYPE_CTRL | USB_EP_DT_BIT;
-
- usb_data_read(&g_usb.ctrl.req, 0, sizeof(struct usb_ctrl_req_hdr));
- usb_handle_control_request(&g_usb.ctrl.req);
-
- usb_regs->ar = USB_AR_CEL_RELEASE;
- usb_ep0_out_queue_bd(true, 0, 64, false);
- return;
- }
-
- if (((bds_out & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)) {
- usb_ep0_out_done_bd(false);
- if (g_usb.ctrl.state != DATA_OUT) {
- puts("[!] Got unexpected DATA !?!\n");
- continue;
- }
- usb_handle_control_data();
- acted = true;
- }
- if ((bds_in & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK) {
- usb_ep0_in_done_bd();
- if (g_usb.ctrl.state == DATA_IN) {
- usb_handle_control_data();
- acted = true;
- }
- }
- } while (acted);
- }
- void
- usb_ep0_init(void)
- {
-
- usb_ep_regs[0].out.status = USB_EP_TYPE_CTRL | USB_EP_BD_CTRL;
- usb_ep_regs[0].in.status = USB_EP_TYPE_CTRL | USB_EP_DT_BIT;
-
- usb_ep0_out_queue_bd(true, 0, 64, false);
- }
|