static void usb_send_desc(setup_t *sp) { // initialize with: // * len = requested length // * dsc = configuration descriptor // * wTotalLength = wTotalLength field of configuration descriptor uint8_t len = HTOUS(sp->asdescreq.len); usbdescr_t *dsc = (usbdescr_t*) &(usbdev.usbdesc[((usbdescr_t*) usbdev.usbdesc)->bLength]); uint16_t wTotalLength = HTOUS(*(uint16_t*) dsc->buf); size_t i; switch(sp->asdescreq.val) { case DEVICE_DESCRIPTOR: PUTS("dev_desc\n"); dsc = (usbdescr_t*) usbdev.usbdesc; len = dsc->bLength; break; case CONFIGURATION_DESCRIPTOR: PUTS("conf_desc\n"); len = MIN(len, wTotalLength); break; case STRING_DESCRIPTOR: PUTS("str_desc\n"); dsc = (usbdescr_t*) &dsc->buf[wTotalLength-sizeof(usbdescr_t)]; /* at the first string now */ for(i=0; i<sp->asdescreq.idx && dsc->bDescriptorType==STRING_DESCRIPTOR; i++) dsc = (usbdescr_t*) &dsc->buf[dsc->bLength-sizeof(usbdescr_t)]; len = dsc->bLength; break; default: PUTS("unknown setup request\n"); STALLEP0(); } { uint8_t wlen = MIN(64, len), *pt = (uint8_t*) dsc; reg_t st = {0x00}; do { wlen = MIN(64, len); /* wait until asserted */ do { rreg(EPIRQ, &st); } while( !st.EPIRQ.IN0BAVIRQ ); /* writing to EP0, also clrs irq */ wregn(EP0FIFO, pt, wlen, false); wregn(EP0BC, &wlen, sizeof(uint8_t), len<64); len -= wlen; pt += wlen; } while(len>0); } }
static bool usb_setup(setup_t *sp) { switch(sp->reqtype.type) { case 0x00: PUTS("usb: std_req - "); return std_req(sp); break; case 0x01: PUTS("usb: class_req - "); break; case 0x02: PUTS("usb: vendor_req - "); break; default: GDB2_PUTS("unknown req - "); STALLEP0(); } GDB2_PUTS(".\n"); return false; }
static void get_status(setup_t *sp) { uint8_t len = sizeof(sp->asstatresp); reg_t st = {0x00}; switch(sp->reqtype.recp) { case TO_DEVICE: sp->asstatresp = (usbdev.status.rwu_enabled)<<9 | (usbdev.status.self_powered)<<8; break; case TO_ENDPOINT: /* XXX: for endpoint the stall status should be returned */ case TO_INTERFACE: sp->asstatresp = 0x0000; break; default: STALLEP0(); } do { rreg(EPIRQ, &st); } while( !st.EPIRQ.IN0BAVIRQ ); wregn(EP0FIFO, (uint8_t*) &sp->asstatresp, len, false); wregn(EP0BC, &len, sizeof(len), true); }
/** * Looks into the SETUPDAT data and dispatches to the callback handlers. * * Note that this code will handshake the packet for all callbacks except * handle_vendorcommand(). This code *used* to handshake those too, but as it * is not required by the specification to do so (for packets with a DATA * segment) it doesn't do it anymore. */ void handle_setupdata() { BOOL handshake = TRUE; //printf ( "Handle setupdat: %02x\n", SETUPDAT[1] ); switch ( SETUPDAT[1] ) { case GET_STATUS: if (!handle_get_status()) STALLEP0(); break; case CLEAR_FEATURE: if (!handle_clear_feature()) { STALLEP0(); } break; case SET_FEATURE: if (!handle_set_feature()) { STALLEP0(); } break; case GET_DESCRIPTOR: handle_get_descriptor(); break; case GET_CONFIGURATION: EP0BUF[0] = handle_get_configuration(); EP0BCH=0; EP0BCL=1; break; case SET_CONFIGURATION: // user callback if( !handle_set_configuration(SETUPDAT[2])) { STALLEP0(); } break; case GET_INTERFACE: { BYTE alt_ifc; if (!handle_get_interface(SETUPDAT[4],&alt_ifc)) { STALLEP0(); } else { EP0BUF[0] = alt_ifc; EP0BCH=0; EP0BCL=1; } } break; case SET_INTERFACE: // user callback if ( !handle_set_interface(SETUPDAT[4],SETUPDAT[2])) { STALLEP0(); } break; default: if (handle_vendorcommand(SETUPDAT[1])) { handshake = FALSE; } else { printf ( "Unhandled Vendor Command: %02x\n" , SETUPDAT[1] ); STALLEP0(); } } // do the handshake if(handshake) { EP0CS |= bmHSNAK; } }
static bool std_req(setup_t *sp) { switch(sp->req) { case SR_SET_ADDRESS: PUTS("set_addr\n"); rregn(FNADDR, NULL, 0, true); break; case SR_GET_DESCRIPTOR: PUTS("get_desc: "); usb_send_desc(sp); break; case SR_SET_FEATURE: /* this either sets that RWU is to be enabled or to halt an EP, * which is mandatory for bulk and interrupt EPs */ PUTS("set_feature\n"); break; case SR_CLEAR_FEATURE: /* clear one of the features which have been set by SET_FEATURE */ PUTS("clear_feature\n"); break; case SR_GET_STATUS: PUTS("get_status\n"); get_status(sp); break; case SR_SET_INTERFACE: /* this is used to set alternative interfaces. For example when * the CDC device will be put up */ PUTS("setif"); ACK(); break; case SR_GET_INTERFACE: PUTS("getif"); /* always report the same alternative: 1 */ { uint8_t i = 0x01; reg_t st = {0x00}; do { rreg(EPIRQ, &st); } while( !st.EPIRQ.IN0BAVIRQ ); wregn(EP0FIFO, &i, sizeof(uint8_t), false); i=sizeof(uint8_t); wregn(EP0BC, &i, i, true); } break; case SR_SET_CONFIGURATION: PUTS("set_conf\n"); usbdev.status.configuration = sp->asconfreq.conf; ACK(); return true; break; case SR_GET_CONFIGURATION: PUTS("get_conf\n"); { uint8_t len = sizeof(usbdev.status.configuration); reg_t st = {0x00}; do { rreg(EPIRQ, &st); } while( !st.EPIRQ.IN0BAVIRQ ); wregn(EP0FIFO, &usbdev.status.configuration, len, false); wregn(EP0BC, &len, sizeof(len), true); } break; default: PUTS("unknown std_req()"); STALLEP0(); } return false; }