From 3c5ee9ac57cbac4050df1729a28ec39c60d303ff Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 16 Jul 2013 22:23:14 +0200 Subject: hwstub: forgot file Change-Id: Ib79f4ef89c734d7ba2fcbf648aadc346576e1c17 --- utils/hwstub/stub/main.c | 514 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 utils/hwstub/stub/main.c (limited to 'utils') diff --git a/utils/hwstub/stub/main.c b/utils/hwstub/stub/main.c new file mode 100644 index 0000000000..c3cc429949 --- /dev/null +++ b/utils/hwstub/stub/main.c @@ -0,0 +1,514 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2013 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "stddef.h" +#include "protocol.h" +#include "logf.h" +#include "usb_ch9.h" +#include "usb_drv.h" +#include "memory.h" +#include "target.h" + +extern unsigned char oc_codestart[]; +extern unsigned char oc_codeend[]; +extern unsigned char oc_stackstart[]; +extern unsigned char oc_stackend[]; +extern unsigned char oc_bufferstart[]; +extern unsigned char oc_bufferend[]; + +#define oc_codesize ((size_t)(oc_codeend - oc_codestart)) +#define oc_stacksize ((size_t)(oc_stackend - oc_stackstart)) +#define oc_buffersize ((size_t)(oc_bufferend - oc_bufferstart)) + +static bool g_exit = false; + +/** + * + * USB stack + * + */ + +static struct usb_device_descriptor __attribute__((aligned(2))) + device_descriptor= +{ + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = HWSTUB_USB_VID, + .idProduct = HWSTUB_USB_PID, + .bcdDevice = HWSTUB_VERSION_MAJOR << 8 | HWSTUB_VERSION_MINOR, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1 +}; + +#define USB_MAX_CURRENT 200 + +static struct usb_config_descriptor __attribute__((aligned(2))) + config_descriptor = +{ + .bLength = sizeof(struct usb_config_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = 0, /* will be filled in later */ + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = (USB_MAX_CURRENT + 1) / 2, /* In 2mA units */ +}; + +/* main interface */ +static struct usb_interface_descriptor __attribute__((aligned(2))) + interface_descriptor = +{ + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 3, + .bInterfaceClass = HWSTUB_CLASS, + .bInterfaceSubClass = HWSTUB_SUBCLASS, + .bInterfaceProtocol = HWSTUB_PROTOCOL, + .iInterface = 4 +}; + + +static struct usb_endpoint_descriptor __attribute__((aligned(2))) + endpoint_descriptor = +{ + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 0, + .bInterval = 0 +}; + +static const struct usb_string_descriptor __attribute__((aligned(2))) + usb_string_iManufacturer = +{ + 24, + USB_DT_STRING, + {'R', 'o', 'c', 'k', 'b', 'o', 'x', '.', 'o', 'r', 'g'} +}; + +static const struct usb_string_descriptor __attribute__((aligned(2))) + usb_string_iProduct = +{ + 52, + USB_DT_STRING, + {'R', 'o', 'c', 'k', 'b', 'o', 'x', ' ', + 'h', 'a', 'r', 'd', 'w', 'a', 'r', 'e', ' ', + 'e', 'm', 'u', 'l', 'a', 't', 'e', 'r'} +}; + +static struct usb_string_descriptor __attribute__((aligned(2))) + usb_string_iSerial = +{ + 84, + USB_DT_STRING, + {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0'} +}; + +static struct usb_string_descriptor __attribute__((aligned(2))) + usb_string_iInterface = +{ + 28, + USB_DT_STRING, + {'A', 'c', 'i', 'd', ' ', + '0' + (HWSTUB_VERSION_MAJOR >> 4), '0' + (HWSTUB_VERSION_MAJOR & 0xf), '.', + '0' + (HWSTUB_VERSION_MINOR >> 4), '0' + (HWSTUB_VERSION_MINOR & 0xf), '.', + '0' + (HWSTUB_VERSION_REV >> 4), '0' + (HWSTUB_VERSION_REV & 0xf) } +}; + +/* this is stringid #0: languages supported */ +static const struct usb_string_descriptor __attribute__((aligned(2))) + lang_descriptor = +{ + 4, + USB_DT_STRING, + {0x0409} /* LANGID US English */ +}; + +#define USB_NUM_STRINGS 5 + +static const struct usb_string_descriptor* const usb_strings[USB_NUM_STRINGS] = +{ + &lang_descriptor, + &usb_string_iManufacturer, + &usb_string_iProduct, + &usb_string_iSerial, + &usb_string_iInterface +}; + +uint8_t *usb_buffer = oc_bufferstart; +uint32_t usb_buffer_size = 0; + +#define EP_BULK 1 +#define EP_INT 2 + +static void set_config(void) +{ + usb_drv_configure_endpoint(EP_BULK, USB_ENDPOINT_XFER_BULK); + usb_drv_configure_endpoint(EP_INT, USB_ENDPOINT_XFER_INT); +} + +static void handle_std_dev_desc(struct usb_ctrlrequest *req) +{ + int size; + const void* ptr = NULL; + unsigned index = req->wValue & 0xff; + + switch(req->wValue >> 8) + { + case USB_DT_DEVICE: + ptr = &device_descriptor; + size = sizeof(struct usb_device_descriptor); + break; + case USB_DT_OTHER_SPEED_CONFIG: + case USB_DT_CONFIG: + { + int max_packet_size; + + /* config desc */ + if((req->wValue >> 8) ==USB_DT_CONFIG) + { + max_packet_size = (usb_drv_port_speed() ? 512 : 64); + config_descriptor.bDescriptorType = USB_DT_CONFIG; + } + else + { + max_packet_size=(usb_drv_port_speed() ? 64 : 512); + config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG; + } + size = sizeof(struct usb_config_descriptor); + + /* interface */ + memcpy(usb_buffer + size, (void *)&interface_descriptor, + sizeof(interface_descriptor)); + size += sizeof(interface_descriptor); + /* endpoint 1: bulk out */ + endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_OUT; + endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK; + endpoint_descriptor.wMaxPacketSize = 512; + memcpy(usb_buffer + size, (void *)&endpoint_descriptor, + sizeof(endpoint_descriptor)); + size += sizeof(endpoint_descriptor); + /* endpoint 2: bulk in */ + endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_IN; + endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK; + endpoint_descriptor.wMaxPacketSize = 512; + memcpy(usb_buffer + size, (void *)&endpoint_descriptor, + sizeof(endpoint_descriptor)); + size += sizeof(endpoint_descriptor); + /* endpoint 3: int in */ + endpoint_descriptor.bEndpointAddress = EP_INT | USB_DIR_IN; + endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_INT; + endpoint_descriptor.wMaxPacketSize = 1024; + memcpy(usb_buffer + size, (void *)&endpoint_descriptor, + sizeof(endpoint_descriptor)); + size += sizeof(endpoint_descriptor); + + /* fix config descriptor */ + config_descriptor.bNumInterfaces = 1; + config_descriptor.wTotalLength = size; + memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor)); + + ptr = usb_buffer; + break; + } + case USB_DT_STRING: + if(index < USB_NUM_STRINGS) + { + size = usb_strings[index]->bLength; + ptr = usb_strings[index]; + } + else + usb_drv_stall(EP_CONTROL, true, true); + break; + default: + break; + } + + if(ptr) + { + int length = MIN(size, req->wLength); + + if(ptr != usb_buffer) + memcpy(usb_buffer, ptr, length); + + usb_drv_send(EP_CONTROL, usb_buffer, length); + usb_drv_recv(EP_CONTROL, NULL, 0); + } + else + usb_drv_stall(EP_CONTROL, true, true); +} + +static void handle_std_dev_req(struct usb_ctrlrequest *req) +{ + switch(req->bRequest) + { + case USB_REQ_GET_CONFIGURATION: + usb_buffer[0] = 1; + usb_drv_send(EP_CONTROL, usb_buffer, 1); + usb_drv_recv(EP_CONTROL, NULL, 0); + break; + case USB_REQ_SET_CONFIGURATION: + usb_drv_send(EP_CONTROL, NULL, 0); + set_config(); + break; + case USB_REQ_GET_DESCRIPTOR: + handle_std_dev_desc(req); + break; + case USB_REQ_SET_ADDRESS: + usb_drv_send(EP_CONTROL, NULL, 0); + usb_drv_set_address(req->wValue); + break; + case USB_REQ_GET_STATUS: + usb_buffer[0] = 0; + usb_buffer[1] = 0; + usb_drv_send(EP_CONTROL, usb_buffer, 2); + usb_drv_recv(EP_CONTROL, NULL, 0); + break; + default: + usb_drv_stall(EP_CONTROL, true, true); + } +} + +static void handle_std_req(struct usb_ctrlrequest *req) +{ + switch(req->bRequestType & USB_RECIP_MASK) + { + case USB_RECIP_DEVICE: + return handle_std_dev_req(req); + default: + usb_drv_stall(EP_CONTROL, true, true); + } +} + +struct usb_resp_info_version_t g_version = +{ + .major = HWSTUB_VERSION_MAJOR, + .minor = HWSTUB_VERSION_MINOR, + .revision = HWSTUB_VERSION_REV +}; + +struct usb_resp_info_layout_t g_layout; + +struct usb_resp_info_features_t g_features = +{ + .feature_mask = HWSTUB_FEATURE_LOG | HWSTUB_FEATURE_MEM | + HWSTUB_FEATURE_CALL | HWSTUB_FEATURE_JUMP +}; + +static void fill_layout_info(void) +{ + g_layout.oc_code_start = (uint32_t)oc_codestart; + g_layout.oc_code_size = oc_codesize; + g_layout.oc_stack_start = (uint32_t)oc_stackstart; + g_layout.oc_stack_size = oc_stacksize; + g_layout.oc_buffer_start = (uint32_t)oc_bufferstart; + g_layout.oc_buffer_size = oc_buffersize; +} + +static void handle_get_info(struct usb_ctrlrequest *req) +{ + void *ptr = NULL; + int size = 0; + switch(req->wIndex) + { + case HWSTUB_INFO_VERSION: + ptr = &g_version; + size = sizeof(g_version); + break; + case HWSTUB_INFO_LAYOUT: + fill_layout_info(); + ptr = &g_layout; + size = sizeof(g_layout); + break; + case HWSTUB_INFO_FEATURES: + ptr = &g_features; + size = sizeof(g_features); + break; + default: + size = target_get_info(req->wIndex, &ptr); + if(size < 0) + usb_drv_stall(EP_CONTROL, true, true); + } + + if(ptr) + { + int length = MIN(size, req->wLength); + + if(ptr != usb_buffer) + memcpy(usb_buffer, ptr, length); + usb_drv_send(EP_CONTROL, usb_buffer, length); + usb_drv_recv(EP_CONTROL, NULL, 0); + } +} + +static void handle_get_log(struct usb_ctrlrequest *req) +{ + enable_logf(false); + int length = logf_readback(usb_buffer, MIN(req->wLength, usb_buffer_size)); + usb_drv_send(EP_CONTROL, usb_buffer, length); + usb_drv_recv(EP_CONTROL, NULL, 0); + enable_logf(true); +} + +static void handle_rw_mem(struct usb_ctrlrequest *req) +{ + uint32_t addr = req->wValue | req->wIndex << 16; + uint16_t length = req->wLength; + + if(req->bRequestType & USB_DIR_IN) + { + memcpy(usb_buffer, (void *)addr, length); + asm volatile("nop" : : : "memory"); + usb_drv_send(EP_CONTROL, usb_buffer, length); + usb_drv_recv(EP_CONTROL, NULL, 0); + } + else + { + int size = usb_drv_recv(EP_CONTROL, usb_buffer, length); + asm volatile("nop" : : : "memory"); + if(size != length) + usb_drv_stall(EP_CONTROL, true, true); + else + { + memcpy((void *)addr, usb_buffer, length); + usb_drv_send(EP_CONTROL, NULL, 0); + } + } +} + +static void handle_call_jump(struct usb_ctrlrequest *req) +{ + uint32_t addr = req->wValue | req->wIndex << 16; + + if(req->bRequest == HWSTUB_CALL) + ((void (*)(void))addr)(); + else + { + /* disconnect to make sure usb/dma won't interfere */ + usb_drv_exit(); + asm volatile("bx %0\n" : : "r" (addr) : "memory"); + } +} + +static void handle_atexit(struct usb_ctrlrequest *req) +{ + if(target_atexit(req->wIndex) < 0) + usb_drv_stall(EP_CONTROL, true, true); + else + usb_drv_send(EP_CONTROL, NULL, 0); +} + +static void handle_exit(struct usb_ctrlrequest *req) +{ + (void)req; + usb_drv_send(EP_CONTROL, NULL, 0); + g_exit = true; +} + +static void handle_class_dev_req(struct usb_ctrlrequest *req) +{ + switch(req->bRequest) + { + case HWSTUB_GET_INFO: + handle_get_info(req); + break; + case HWSTUB_GET_LOG: + handle_get_log(req); + break; + case HWSTUB_RW_MEM: + handle_rw_mem(req); + break; + case HWSTUB_CALL: + case HWSTUB_JUMP: + handle_call_jump(req); + break; + case HWSTUB_ATEXIT: + handle_atexit(req); + break; + case HWSTUB_EXIT: + handle_exit(req); + break; + default: + usb_drv_stall(EP_CONTROL, true, true); + } +} + +static void handle_class_req(struct usb_ctrlrequest *req) +{ + switch(req->bRequestType & USB_RECIP_MASK) + { + case USB_RECIP_DEVICE: + return handle_class_dev_req(req); + default: + usb_drv_stall(EP_CONTROL, true, true); + } +} + +/** + * + * Main + * + */ + +void main(uint32_t arg) +{ + usb_buffer_size = oc_buffersize; + + logf("hwstub %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, + HWSTUB_VERSION_REV); + logf("argument: 0x%08x\n", arg); + + target_init(); + usb_drv_init(); + + while(!g_exit) + { + struct usb_ctrlrequest req; + usb_drv_recv_setup(&req); + + switch(req.bRequestType & USB_TYPE_MASK) + { + case USB_TYPE_STANDARD: + handle_std_req(&req); + break; + case USB_TYPE_CLASS: + handle_class_req(&req); + break; + default: + usb_drv_stall(EP_CONTROL, true, true); + } + } + usb_drv_exit(); + target_exit(); +} -- cgit v1.2.3