void cdc_req_handler(req_t *req) { U8 i; usb_pcb_t *pcb = usb_pcb_get(); switch (req->req) { case GET_LINE_CODING: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { // send the line coding to the host for (i=0; i<LINE_CODE_SZ; i++) { usb_buf_write(EP_CTRL, line_code[i]); } ep_write(EP_CTRL); } break; case SET_LINE_CODING: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wait for the setup data to be sent to the control endpoint while (pcb->fifo[EP_CTRL].len == 0) { // keep the nop for a place to set a breakpoint on and to make it obvious we're // waiting for something. asm("nop"); } // clear the setup flag if needed pcb->flags &= ~(1<<SETUP_DATA_AVAIL); // send out a zero-length packet to ack to the host that we received // the new line coding ep_send_zlp(EP_CTRL); // set the new line code. the first 8 bytes in the fifo are just // for the setup packet so we want to write the next 7 bytes for the // line code. for (i=0; i<LINE_CODE_SZ; i++) { line_code[i] = usb_buf_read(EP_CTRL); } } break; case SET_CTRL_LINE_STATE: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { ep_send_zlp(EP_CTRL); } break; default: ep_set_stall(EP_CTRL); break; } }
/* * This is the putchar function that is used by avr-libc's printf. We need * to hook this function into the stdout file stream using the FDEV_SETUP_STREAM * macro in avr-libc. Once the stream is set up, we hook the stream to stdout * and we can do printfs via USB. */ int freakusb_putchar(char c, FILE *unused) { usb_pcb_t *pcb = usb_pcb_get(); if (!(pcb->flags & (1 << ENUMERATED))) return 0; if (c == '\n') { usb_buf_write(EP_1, '\n'); usb_buf_write(EP_1, '\r'); } else { usb_buf_write(EP_1, (U8)c); } ep_write(EP_1); return 0; }
void dfu_req_handler(req_t *req) { U8 i; usb_pcb_t *pcb = usb_pcb_get(); switch (req->req) { case DFU_DETACH: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is wTimeout // wLength is zero // data is none dfu_status.bState = appDETACH; dfu_status.bStatus = OK; } break; case DFU_DNLOAD: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is wBlockNum // wlength is Length // data is firmware if( dfu_status.bState == dfuIDLE ) { if( req->len > 0 ) { hw_state_indicator( HW_STATE_TRANSFER ); dfu_status.bState = dfuDNLOAD_SYNC; } else { dfu_status.bState = dfuERROR; dfu_status.bStatus = errNOTDONE; hw_state_indicator( HW_STATE_ERROR ); ep_send_zlp(EP_CTRL); return; } } i = req->val; if( dfu_status.bState == dfuDNLOAD_IDLE ) { if( req->len > 0 ) { dfu_status.bState = dfuDNLOAD_SYNC; } else { if( flash_buffer_ptr > flash_buffer ) { need_to_write = 1; //flash_buffer_ptr = flash_buffer; } dfu_status.bState = dfuMANIFEST_SYNC; ep_send_zlp(EP_CTRL); return; } } SI32_USB_A_clear_out_packet_ready_ep0(SI32_USB_0); while(pcb->fifo[EP_CTRL].len < req->len) { //ep_read(EP_CTRL); i = pcb->fifo[EP_CTRL].len; } // clear the setup flag if needed pcb->flags &= ~(1<<SETUP_DATA_AVAIL); // send out a zero-length packet to ack to the host that we received // the new line coding U8* byte_buf_ptr = ( U8* )flash_buffer_ptr; U8 tmp_len = pcb->fifo[EP_CTRL].len; for(i = 0; i < tmp_len; i++) { *byte_buf_ptr = usb_buf_read(EP_CTRL); byte_buf_ptr++; } flash_buffer_ptr += i/4; if( flash_buffer_ptr == flash_buffer + BLOCK_SIZE_U32 ) { // Reset buffer pointer //flash_buffer_ptr = flash_buffer; need_to_write = 1; } if( flash_buffer_ptr > flash_buffer + BLOCK_SIZE_U32) { dfu_status.bState = dfuERROR; hw_state_indicator( HW_STATE_ERROR ); } ep_send_zlp(EP_CTRL); } break; case DFU_UPLOAD: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is length // data is firmware // NOT SUPPORTED ep_set_stall(EP_CTRL); } break; case DFU_GETSTATUS: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { if( dfu_communication_started == 0 ) hw_state_indicator( HW_STATE_CONNECTED ); dfu_communication_started = 1; // If we're still transmitting blocks if( dfu_status.bState == dfuDNLOAD_SYNC ) { if( need_to_write == 0 ) { dfu_status.bState=dfuDNLOAD_IDLE; dfu_status.bwPollTimeout0 = 0x00; } else { dfu_status.bState=dfuDNBUSY; dfu_status.bwPollTimeout0 = 0x3F; } } else if( dfu_status.bState == dfuDNBUSY ) { if( need_to_write == 0) dfu_status.bState=dfuDNLOAD_SYNC; } else if( dfu_status.bState == dfuMANIFEST_SYNC) { dfu_status.bState=dfuMANIFEST; dfu_status.bwPollTimeout0 = 0xFF; hw_state_indicator( HW_STATE_DONE ); } else if( dfu_status.bState == dfuMANIFEST && need_to_write == 0) { // Finish erasing flash while( flash_target < SI32_MCU_FLASH_SIZE) { if( 0 != hw_flash_erase( flash_target, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errERASE; hw_state_indicator( HW_STATE_ERROR ); } flash_target += BLOCK_SIZE_U8; } dfu_status.bState=dfuMANIFEST_WAIT_RESET; } for (i=0; i<STATUS_SZ; i++) { usb_buf_write(EP_CTRL, *((U8 *)&dfu_status + i)); } ep_write(EP_CTRL); if( dfu_status.bState == dfuMANIFEST_WAIT_RESET ) { hw_wait_ms(200); hw_boot_image( 1 ); } if( need_to_write ) { if( 0 != hw_flash_erase( flash_target, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errERASE; hw_state_indicator( HW_STATE_ERROR ); } if( 0 != hw_flash_write( flash_target, ( U32* )flash_buffer, flash_buffer_ptr - flash_buffer, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errVERIFY; hw_state_indicator( HW_STATE_ERROR ); } flash_buffer_ptr = flash_buffer; flash_target += BLOCK_SIZE_U8; need_to_write = 0; if( dfu_status.bState != dfuMANIFEST ) dfu_status.bState=dfuDNLOAD_SYNC; } } break; case DFU_CLRSTATUS: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is 0 // data is none if( dfu_status.bState == dfuERROR ) { dfu_status.bStatus = OK; dfu_status.bState = dfuIDLE; hw_state_indicator( HW_STATE_ERROR_CLR ); } } break; case DFU_GETSTATE: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is 1 // data is state // Transition?: No State Transition usb_buf_write( EP_CTRL, dfu_status.bState ); ep_write(EP_CTRL); } break; case DFU_ABORT: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is 0 // data is none if( dfu_status.bState == dfuIDLE ) { dfu_status.bStatus = OK; dfu_status.bState = dfuIDLE; } else if ( dfu_status.bState == dfuDNLOAD_IDLE ) { flash_target = FLASH_TARGET; if( 0 != hw_flash_erase( flash_target, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errERASE; hw_state_indicator( HW_STATE_ERROR ); } dfu_status.bStatus = OK; dfu_status.bState = dfuIDLE; ep_send_zlp(EP_CTRL); } } break; default: ep_set_stall(EP_CTRL); break; } }
int main(int argc, char *argv[]) { int result; libusb_context *ctx; libusb_device_handle *usb_device; unsigned char *txbuf; int size; int retcode; int last_serial = -1; FILE *fp1, *fp2, *fp; char def1_inst[] = "/usr/share/rpiboot/usbbootcode.bin"; char def2_inst[] = "/usr/share/rpiboot/msd.elf"; char def3_inst[] = "/usr/share/rpiboot/buildroot.elf"; char def1_loc[] = "./usbbootcode.bin"; char def2_loc[] = "./msd.elf"; char def3_loc[] = "./buildroot.elf"; char *def1, *def2, *def3; char *stage1 = NULL, *stage2 = NULL; char *fatimage = NULL, *executable = NULL; int loop = 0; // if local file version exists use it else use installed if( access( def1_loc, F_OK ) != -1 ) { def1 = def1_loc; } else { def1 = def1_inst; } if( access( def2_loc, F_OK ) != -1 ) { def2 = def2_loc; } else { def2 = def2_inst; } if( access( def3_loc, F_OK ) != -1 ) { def3 = def3_loc; } else { def3 = def3_inst; } stage1 = def1; stage2 = def2; struct MESSAGE_S { int length; unsigned char signature[20]; } message; #if defined (__CYGWIN__) //printf("Running under Cygwin\n"); #else //exit if not run as sudo if(getuid() != 0) { printf("Must be run with sudo...\n"); exit(-1); } #endif // Skip the command name argv++; argc--; while(*argv) { if(strcmp(*argv, "-b") == 0) { argv++; argc--; if(argc < 1) usage(1); stage1 = def1; stage2 = def3; fatimage = *argv; } else if(strcmp(*argv, "-h") == 0 || strcmp(*argv, "--help") == 0) { usage(0); } else if(strcmp(*argv, "-x") == 0) { argv++; argc--; executable = *argv; } else if(strcmp(*argv, "-l") == 0) { loop = 1; } else if(strcmp(*argv, "-v") == 0) { verbose = 1; } else { usage(1); } argv++; argc--; } fp1 = fopen(stage1, "rb"); if (fp1 == NULL) { printf("Cannot open file %s\n", stage1); exit(-1); } fp2 = fopen(stage2, "rb"); if (fp2 == NULL) { printf("Cannot open file %s\n", stage2); exit(-1); } if(strcmp(stage2 + strlen(stage2) - 4, ".elf")) { printf("Third stage needs to be .elf format\n"); exit(-1); } int ret = libusb_init(&ctx); if (ret) { printf("Failed to initialise libUSB\n"); exit(-1); } libusb_set_debug(ctx, 0); do { FILE *fp_img = NULL; struct libusb_device_descriptor desc; printf("Waiting for BCM2835 ...\n"); // Wait for a device to get plugged in do { result = Initialize_Device(&ctx, &usb_device); if(result == 0) { libusb_get_device_descriptor(libusb_get_device (usb_device), &desc); // Make sure we've re-enumerated since the last time if(desc.iSerialNumber == last_serial) { result = -1; libusb_close(usb_device); } } if (result) { usleep(100); } } while (result); last_serial = desc.iSerialNumber; printf("Found serial = %d: writing file %s\n", desc.iSerialNumber, desc.iSerialNumber == 0 ? stage1 : stage2); fp = desc.iSerialNumber == 0 ? fp1 : fp2; fseek(fp, 0, SEEK_END); message.length = ftell(fp); fseek(fp, 0, SEEK_SET); if(desc.iSerialNumber == 1 && fatimage != NULL) { // Been given a filesystem image fp_img = fopen(fatimage, "rb"); if(fp_img == NULL) { printf("Failed to open image %s\n", fatimage); exit(-1); } fseek(fp_img, 0, SEEK_END); message.length += ftell(fp_img); if(verbose) printf("Adding %ld bytes of binary to end of elf\n", ftell(fp_img)); fseek(fp_img, 0, SEEK_SET); } txbuf = (unsigned char *)malloc(message.length); if (txbuf == NULL) { printf("Failed to allocate memory\n"); exit(-1); } size = fread(txbuf, 1, message.length, fp); if(fp_img) { size += fread(txbuf + size, 1, message.length - size, fp_img); } size = ep_write((unsigned char *)&message, sizeof(message), usb_device); if (size != sizeof(message)) { printf("Failed to write correct length, returned %d\n", size); exit(-1); } if(verbose) printf("Writing %d bytes\n", message.length); size = ep_write(txbuf, message.length, usb_device); if (size != message.length) { printf("Failed to read correct length, returned %d\n", size); exit(-1); } size = ep_read((unsigned char *)&retcode, sizeof(retcode), usb_device); if (retcode == 0) { if(verbose) printf("Successful\n"); if(fp == fp2 && executable) { system(executable); } } else printf("Failed : 0x%x", retcode); libusb_close(usb_device); } while(fp == fp1 || loop); libusb_exit(ctx); return 0; }