first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
# Copyright (C) 2007-2013 Apple Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
# Base USB Device stack
ALL_OBJS += \
$(LOCAL_DIR)/usb.o \
$(LOCAL_DIR)/usb_controller.o \
$(LOCAL_DIR)/usb_core.o
ifneq ($(filter $(DOCKFIFOS), bulk),)
ALL_OBJS += \
$(LOCAL_DIR)/usb_dockfifo_controller.o
endif
# SecureROM and LLB-DFU support
ifneq ($(filter $(OPTIONS), WITH_DFU_MODE=1), )
OPTIONS += \
WITH_USB_DFU=1 \
WITH_USB_MODE_DFU=1
ALL_OBJS += \
$(LOCAL_DIR)/usb_dfu.o
endif
# Recovery mode support
ifneq ($(filter $(OPTIONS), WITH_RECOVERY_MODE=1), )
OPTIONS += \
WITH_USB_MODE_RECOVERY=1
ifeq ($(filter RELEASE ROMRELEASE,$(BUILD)),)
OPTIONS += \
WITH_BULK_UPLOAD=1
endif
MODULES += \
lib/cbuf \
lib/cksum
ALL_OBJS += \
$(LOCAL_DIR)/usb_debug.o \
$(LOCAL_DIR)/usb_serial.o \
$(LOCAL_DIR)/usb_transfer.o
endif
+128
View File
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2010-2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <string.h>
#include <drivers/usb/usb_public.h>
#include <drivers/usb/usb_controller.h>
#include <drivers/usb/usb_core.h>
#define require(assertion, exception_label) \
do { \
if (__builtin_expect(!(assertion), 0)) \
{ \
goto exception_label; \
} \
} while (0)
#define DFU_MODE_CONFIG_STRING "Apple Mobile Device (DFU Mode)"
#define RECOVERY_MODE_CONFIG_STRING "Apple Mobile Device (Recovery Mode)"
///////////////////////////////////
// USB DFU mode - SecureROM only
// USB Recovery mode - iBoot only
///////////////////////////////////
static bool usb_inited;
static void usb_free()
{
if(!usb_inited) goto early_inited_free;
#if WITH_USB_MODE_DFU
usb_dfu_exit();
#elif WITH_USB_MODE_RECOVERY
usb_transfer_exit();
usb_serial_exit();
#endif
return;
early_inited_free:
#if WITH_USB_MODE_RECOVERY
usb_serial_exit();
#endif
return;
}
int usb_early_init()
{
#if WITH_USB_MODE_RECOVERY
if(usb_serial_early_init() != 0) {
usb_free();
return -1;
}
#endif
return 0;
}
int usb_init_with_controller(struct usb_controller_functions *controller_funcs)
{
if(usb_inited) return 0;
usb_controller_register(controller_funcs);
#if WITH_USB_MODE_DFU
require((usb_core_init(DFU_MODE_CONFIG_STRING) != -1), error);
require((usb_dfu_init() != -1), error);
#elif WITH_USB_MODE_RECOVERY
require((usb_core_init(RECOVERY_MODE_CONFIG_STRING) != -1), error);
require((usb_transfer_init() != -1), error);
require((usb_serial_init() != -1), error);
#endif
require((usb_core_start() != -1), error);
usb_inited = true;
dprintf(DEBUG_INFO, "USB inited \n");
return 0;
error:
dprintf(DEBUG_INFO, "failed to start the core\n");
usb_free();
return -1;
}
int usb_init()
{
// default to Synopsys OTG controller
#if WITH_HW_SYNOPSYS_OTG
extern struct usb_controller_functions *synopsys_otg_controller_init();
return usb_init_with_controller(synopsys_otg_controller_init());
#else
# error "usb_init used without defined USB controller";
#endif
}
void usb_quiesce()
{
if (usb_inited == false) return;
usb_core_stop();
usb_free();
usb_controller_register(NULL);
usb_inited = false;
}
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <drivers/usb/usb_controller.h>
static struct usb_controller_functions usb_controller_funcs;
static bool usb_controller_registered;
int usb_controller_register(const struct usb_controller_functions *controller_functions)
{
dprintf(DEBUG_INFO, "usb_controller_register, %p\n", controller_functions);
if (controller_functions != NULL) {
bcopy((const void *)controller_functions, (void *)&usb_controller_funcs, sizeof(struct usb_controller_functions));
usb_controller_registered = true;
}
else {
bzero((void *)&usb_controller_funcs, sizeof(struct usb_controller_functions));
usb_controller_registered = false;
}
return 0;
}
int usb_controller_init(void)
{
RELEASE_ASSERT(usb_controller_funcs.init != NULL);
return usb_controller_funcs.init();
}
void usb_controller_free(void)
{
RELEASE_ASSERT(usb_controller_funcs.free_func != NULL);
usb_controller_funcs.free_func();
}
int usb_controller_start(void)
{
RELEASE_ASSERT(usb_controller_funcs.start != NULL);
return usb_controller_funcs.start();
}
void usb_controller_stop(void)
{
RELEASE_ASSERT(usb_controller_funcs.stop != NULL);
usb_controller_funcs.stop();
}
void usb_controller_set_address(u_int32_t new_address)
{
RELEASE_ASSERT(usb_controller_funcs.set_address != NULL);
usb_controller_funcs.set_address(new_address);
}
int usb_controller_get_connection_speed(void)
{
RELEASE_ASSERT(usb_controller_funcs.get_connection_speed != NULL);
return usb_controller_funcs.get_connection_speed();
}
void usb_controller_activate_endpoint(u_int32_t endpoint, int type, int max_packet_size, int interval)
{
RELEASE_ASSERT(usb_controller_funcs.activate_endpoint != NULL);
usb_controller_funcs.activate_endpoint(endpoint, type, max_packet_size, interval);
}
void usb_controller_do_endpoint_io(struct usb_device_io_request *req)
{
RELEASE_ASSERT(usb_controller_funcs.do_endpoint_io != NULL);
usb_controller_funcs.do_endpoint_io(req);
}
void usb_controller_stall_endpoint(u_int32_t endpoint, bool stall)
{
RELEASE_ASSERT(usb_controller_funcs.stall_endpoint != NULL);
usb_controller_funcs.stall_endpoint(endpoint, stall);
}
void usb_controller_reset_endpoint_data_toggle(u_int32_t endpoint)
{
RELEASE_ASSERT(usb_controller_funcs.reset_endpoint_data_toggle != NULL);
usb_controller_funcs.reset_endpoint_data_toggle(endpoint);
}
bool usb_controller_is_endpoint_stalled(u_int32_t endpoint)
{
RELEASE_ASSERT(usb_controller_funcs.is_endpoint_stalled != NULL);
return usb_controller_funcs.is_endpoint_stalled(endpoint);
}
void usb_controller_do_test_mode(u_int32_t selector)
{
RELEASE_ASSERT(usb_controller_funcs.do_test_mode != NULL);
usb_controller_funcs.do_test_mode(selector);
}
void usb_controller_abort_endpoint(u_int32_t endpoint)
{
RELEASE_ASSERT(usb_controller_funcs.abort_endpoint != NULL);
usb_controller_funcs.abort_endpoint(endpoint);
}
void usb_controller_deactivate_endpoint(u_int32_t endpoint)
{
RELEASE_ASSERT(usb_controller_funcs.deactivate_endpoint != NULL);
usb_controller_funcs.deactivate_endpoint(endpoint);
}
File diff suppressed because it is too large. Load diff
+263
View File
@@ -0,0 +1,263 @@
/*
* Copyright (C) 2010-2014 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <sys/menu.h>
#include <lib/cksum.h>
#include <lib/env.h>
#include <platform/memmap.h>
#include <drivers/usb/usb_core.h>
#include <drivers/usb/usb_public.h>
#include <drivers/usb/usb_debug.h>
//===================================================================================
// USB command stuff
//===================================================================================
#if defined(WITH_MENU) && WITH_MENU
#define USB_CMD_STRING_LEN 1024
#define USB_SERIAL_CMD_START 0xfc
#define USB_SERIAL_CMD_END 0xfd
#define USB_SERIAL_CMD_START_OFFSET 1
#define USB_SERIAL_CMD_END_OFFSET 1
static u_int8_t usb_cmd_string[USB_CMD_STRING_LEN] __attribute__ ((aligned(CPU_CACHELINE_SIZE)));
static int usb_cmd_main(int argc, struct cmd_arg * args);
MENU_COMMAND_DEVELOPMENT(usb, usb_cmd_main, "run a USB command", NULL);
static void usb_print_usage(const char * s)
{
printf("Usage: \n");
printf("\t%s get <filename> [address] [amount] \n", s);
printf( "\t%s get tftp://servername.com/file.bin [address] [amount] \n", s );
#if WITH_BULK_UPLOAD
printf( "\t%s put <filename> <amount> [address] \n", s );
#endif // WITH_BULK_UPLOAD
}
#if WITH_BULK_UPLOAD
static int usb_cmd_put(const char *fileName, uint64_t amount, uintptr_t address, int printCompletionStatus)
{
int ret = -1;
if(!fileName) {
printf("File Name is NULL!\n");
goto error;
}
if(!amount) {
printf("Amount is 0!\n");
goto error;
}
if(usb_serial_is_active() == false) {
printf("PUT failed, run usbterm\n");
return ret;
}
const char *prefix = "put ";
int notifyHostLen = strlen(prefix) + strlen(fileName) +
USB_SERIAL_CMD_START_OFFSET + USB_SERIAL_CMD_END_OFFSET;
if(notifyHostLen > USB_CMD_STRING_LEN) {
printf("File length too long \n");
goto error;
}
if(address == 0) {
address = env_get_uint("loadaddr", DEFAULT_LOAD_ADDRESS);
printf("Defaulting to address %p\n", (void *)address);
}
if(!security_allow_memory((void *)address, amount)) {
dprintf(DEBUG_INFO, "Permission Denied\n");
goto error;
}
usb_transfer_prepare(USB_TRANSFER_TYPE_BULK_PUT, (void *)address, amount);
bzero(usb_cmd_string, USB_CMD_STRING_LEN);
usb_cmd_string[0] = USB_SERIAL_CMD_START;
memcpy(usb_cmd_string + USB_SERIAL_CMD_START_OFFSET, prefix, strlen(prefix));
memcpy(usb_cmd_string + USB_SERIAL_CMD_START_OFFSET + strlen(prefix), fileName,
notifyHostLen - USB_SERIAL_CMD_START_OFFSET - USB_SERIAL_CMD_END_OFFSET);
usb_cmd_string[notifyHostLen - 1] = USB_SERIAL_CMD_END;
ret = usb_serial_send_cmd_string(usb_cmd_string, notifyHostLen);
if(ret != 0)
goto error;
ret = usb_transfer_start();
if(ret <= 0) {
goto error;
}
amount = ret;
if (printCompletionStatus)
printf("PUT complete, amount %llu\n", amount);
// set the file size and return code
env_set_uint("filesize", amount, 0 );
return 0;
error:
printf("PUT failed. \n");
env_set_uint("filesize", 0, 0);
return -1;
}
int usb_send_data_to_file(const char *filename, size_t amount, uintptr_t address, int printCompletionStatus)
{
return usb_cmd_put(filename, amount, address, printCompletionStatus);
}
#endif // WITH_BULK_UPLOAD
static int usb_cmd_get(int argc, struct cmd_arg *args)
{
int ret = -1;
if(usb_core_get_cable_state() == CABLE_DISCONNECTED) {
printf("GET failed, cable missing\n");
return ret;
}
if(usb_serial_is_active() == false) {
printf("GET failed, run usbterm\n");
return ret;
}
const char *prefix = "get ";
const char * fileName = args[0].str;
int notifyHostLen = strlen(prefix) + strlen(fileName) +
USB_SERIAL_CMD_START_OFFSET + USB_SERIAL_CMD_END_OFFSET;
addr_t address = 0;
uint64_t amount = 0;
if(notifyHostLen > USB_CMD_STRING_LEN) {
printf("File length too long \n");
goto error;
}
if(argc >= 2) {
address = args[1].u;
if(argc >= 3) {
amount = args[2].u;
}
}
if(address == 0) {
address = env_get_uint("loadaddr", DEFAULT_LOAD_ADDRESS);
printf("Defaulting to address %p\n", (void *)address);
}
if(amount > DEFAULT_RAMDISK_SIZE) {
printf("Amount too large \n");
goto error;
}
if(amount == 0) {
amount = DEFAULT_RAMDISK_SIZE;
}
if(!security_allow_memory((void *)address, amount)) {
dprintf(DEBUG_INFO, "Permission Denied\n");
goto error;
}
usb_transfer_prepare(USB_TRANSFER_TYPE_BULK_GET, (void *)address, amount);
bzero((void *)usb_cmd_string, USB_CMD_STRING_LEN);
usb_cmd_string[0] = USB_SERIAL_CMD_START;
memcpy(usb_cmd_string + USB_SERIAL_CMD_START_OFFSET, prefix, strlen(prefix));
memcpy(usb_cmd_string + USB_SERIAL_CMD_START_OFFSET + strlen(prefix), fileName,
notifyHostLen - USB_SERIAL_CMD_START_OFFSET - USB_SERIAL_CMD_END_OFFSET);
usb_cmd_string[notifyHostLen - 1] = USB_SERIAL_CMD_END;
ret = usb_serial_send_cmd_string(usb_cmd_string, notifyHostLen);
if(ret != 0) {
goto error;
}
ret = usb_transfer_start();
if(ret <= 0) {
goto error;
}
amount = ret;
printf("GET complete, amount %llu\n", amount);
// set the file size and return code
env_set_uint( "filesize", amount, 0 );
ret = 0;
return 0;
error:
printf("GET failed. \n");
env_set_uint("filesize", 0, 0);
return -1;
}
static int usb_cmd_main(int argc, struct cmd_arg *args)
{
int ret = 0;
const char *s = args[1].str;
if(!s) {
ret = -1;
}
else {
if(!strcmp(s, "get")) {
if((argc < 3) || (argc > 5)) {
goto print_usage;
}
ret = usb_cmd_get(argc - 2, args + 2);
}
#if WITH_BULK_UPLOAD
else if(!strcmp(s, "put")) {
if((argc < 4) || (argc > 5)) {
goto print_usage;
}
ret = usb_cmd_put(args[2].str, args[3].u, (argc == 5) ? args[4].u : 0, 1);
}
#endif // WITH_BULK_UPLOAD
else {
goto print_usage;
}
}
return ret;
print_usage:
usb_print_usage( args[0].str );
return 0;
}
#endif
+364
View File
@@ -0,0 +1,364 @@
/*
* Copyright (C) 2007-2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
////////////////////////////////////////////////////////////////////
// USB DFU
//
// This file implements usb dfu protocol (just download). This is used
// in SecureROM.
////////////////////////////////////////////////////////////////////
#include <debug.h>
#include <sys/task.h>
#include <sys/security.h>
#include <drivers/usb/usb_chap9.h>
#include <drivers/usb/usb_public.h>
#include <drivers/usb/usb_core.h>
#include <platform.h>
#define DEBUG 0
#if DEBUG
#define print(fmt, args...) printf("%s --- " fmt, __FUNCTION__, ##args)
#else
#define print(fmt, args...) (void)0
#endif
struct usb_dfu_run_time_descriptor {
uint8_t length;
uint8_t type;
uint8_t bmAttributes;
uint16_t wDetachTimeOut;
uint16_t wTransferSize;
} __attribute__((packed));
struct usb_dfu_status_request
{
UInt8 bStatus;
UInt8 bwPollTimeout[3];
UInt8 bState;
UInt8 iString;
} __attribute__((packed));
enum {
DFU_DETACH = 0,
DFU_DNLOAD,
DFU_UPLOAD,
DFU_GETSTATUS,
DFU_CLR_STATUS,
DFU_GETSTATE,
DFU_ABORT
};
enum {
appIDLE,
appDETACH,
dfuIDLE,
dfuDNLOAD_SYNC,
dfuDNBUSY,
dfuDNLOAD_IDLE,
dfuMANIFEST_SYNC,
dfuMANIFEST,
dfuMANIFEST_WAIT_RESET,
dfuUPLOAD_IDLE,
dfuERROR
};
enum {
errOK = 0,
errADDRESS = 0x08,
errNOTDONE = 0x09,
errSTALLEDPKT = 0x0f
};
#define DD_DFU (0x21)
#define USB_DFU_RUN_TIME_DT_SIZE (7)
#define DFU_MAX_TRANSFER_SIZE (2 * 1024)
#define DETACH_TIMEOUT_MS (10)
#define DFU_FILE_SUFFIX_LENGTH (16)
//the polling delay we generally report in GETSTATUS requests
#define STANDARD_DELAY_MS 50
//the delay we report after completing the file download. I don't think it needs to be different
//from the standard delay but this is what m68 h1 rom does.
#define DL_DONE_DELAY_MS 3000
#define DFU_BMATTRIBUTES (1 << 0) // download only
struct usb_dfu_io_buffer {
u_int8_t bytes[DFU_MAX_TRANSFER_SIZE];
};
static const struct usb_interface_descriptor usb_dfu_interface_descriptor = {
USB_DT_INTERFACE_SIZE,
USB_DT_INTERFACE,
APPLE_USB_DFU_INTF,
0,
0,
APPLE_USB_DFU_CLASS,
APPLE_USB_DFU_SUBCLASS,
APPLE_USB_DFU_PROTOCOL,
0
};
static const struct usb_dfu_run_time_descriptor usb_dfu_run_time_desc = {
USB_DFU_RUN_TIME_DT_SIZE,
DD_DFU,
DFU_BMATTRIBUTES,
DETACH_TIMEOUT_MS,
DFU_MAX_TRANSFER_SIZE
};
static bool usb_dfu_inited;
static struct usb_interface_instance usb_dfu_interface_instance;
static struct usb_dfu_status_request status_req;
static struct task_event dfu_event;
static volatile uint8_t dfu_state;
static volatile bool dfu_done;
static struct usb_dfu_io_buffer *io_buffer;
static int completion_status;
static u_int8_t *image_buffer;
static u_int32_t image_buffer_size;
static u_int32_t total_received;
static u_int32_t expecting;
static void set_status(u_int8_t bStatus, int bwPollTimeout, u_int8_t bState, u_int8_t iString);
static int handle_interface_request(struct usb_device_request *request, uint8_t **out_buffer);
static int handle_dfu_request(struct usb_device_request *setup, uint8_t **buffer);
static void handle_bus_reset(void);
static void data_received(u_int32_t received);
int getDFUImage(void* buffer, int maxlen)
{
dprintf(DEBUG_INFO, "Trying to get a file with DFU.\n" );
// save the info provided by our caller
image_buffer = buffer;
image_buffer_size = maxlen;
print( "Initializing USB...\n" );
#if WITH_PLATFORM_INIT_USB
if(platform_init_usb() != 0)
goto exit;
#else
if(usb_init() != 0)
goto exit;
#endif
// wait here till dfu download is finished
while(!dfu_done) event_wait(&dfu_event);
dprintf(DEBUG_INFO, "DFU complete, status=%d\n", completion_status);
exit:
print( "Exiting USB...\n" );
usb_quiesce();
return completion_status;
}
int usb_dfu_init()
{
if(usb_dfu_inited) return 0;
io_buffer = memalign(sizeof(*io_buffer), CPU_CACHELINE_SIZE);
bzero((void *)io_buffer, sizeof(*io_buffer));
set_status(errOK, STANDARD_DELAY_MS, dfuIDLE, 0);
completion_status = -1;
total_received = 0;
dfu_done = false;
event_init(&dfu_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
usb_dfu_interface_instance.total_interfaces = APPLE_USB_DFU_TOTAL_INTFS;
usb_dfu_interface_instance.interface_descs = (struct usb_interface_descriptor *)&usb_dfu_interface_descriptor;
usb_dfu_interface_instance.total_other_descs = 1;
usb_dfu_interface_instance.other_descs = (void *)&usb_dfu_run_time_desc;
usb_dfu_interface_instance.handle_request = handle_interface_request;
usb_dfu_interface_instance.non_setup_data_phase_finished_callback = data_received;
usb_dfu_interface_instance.handle_bus_reset = handle_bus_reset;
usb_core_register_interface(&usb_dfu_interface_instance);
usb_dfu_inited = true;
return 0;
}
void usb_dfu_exit()
{
if(!usb_dfu_inited) return;
bzero((void*)&usb_dfu_interface_instance, sizeof(struct usb_interface_instance));
if(io_buffer) {
free(io_buffer);
io_buffer = NULL;
}
usb_dfu_inited = false;
}
static void set_status(u_int8_t bStatus, int bwPollTimeout, u_int8_t bState, u_int8_t iString)
{
status_req.bStatus = bStatus;
status_req.bwPollTimeout[0]= bwPollTimeout & 0xff;
status_req.bwPollTimeout[1]= (bwPollTimeout >> 8) & 0xff;
status_req.bwPollTimeout[2]= (bwPollTimeout >> 16) & 0xff;
dfu_state = status_req.bState = bState;
status_req.iString = iString;
}
static int handle_interface_request(struct usb_device_request *request, uint8_t **out_buffer)
{
u_int8_t bRequest = request->bRequest;
u_int16_t wLength = request->wLength;
int ret;
print("type: %d\n", (request->bmRequestType & USB_REQ_DIRECTION_MASK));
print("request=%02x wValue=%04x index=%d length=%d\n", bRequest,
request->wValue, request->wIndex, wLength);
ret = -1;
// DFU_GETSTATE and DFU_GETSTATUS request are DEVICE2HOST
// request. Response for these requests are copied into
// io_buffer.
// DFU_DNLOAD request is HOST2DEVICE type request. We pass our
// io_buffer to the stack to copy the data from the host.
//
// io_buffer is gauranteed to be larger than any data needs to
// be copied into it.
if((request->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE)
{
if(out_buffer == NULL)
return -1;
switch(bRequest)
{
case DFU_DNLOAD:
{
if(wLength == 0) {
print("File transfer complete. Waiting for status sync.\n");
set_status(errOK, STANDARD_DELAY_MS, dfuMANIFEST_SYNC, 0);
}
else {
if(wLength > sizeof(*io_buffer)) {
// cleanest way to recover is to stall here
set_status(errSTALLEDPKT, STANDARD_DELAY_MS, dfuIDLE, 0);
return -1;
}
*out_buffer = (uint8_t *)io_buffer;
}
expecting = wLength;
ret = wLength;
break;
}
case DFU_CLR_STATUS :
case DFU_ABORT:
{
set_status(errOK, STANDARD_DELAY_MS, dfuIDLE, 0);
total_received = 0;
if(!dfu_done) {
completion_status = -1;
dfu_done = true;
event_signal(&dfu_event);
}
ret = 0;
break;
}
}
return ret;
}
else if((request->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_DEVICE2HOST)
{
switch(bRequest) {
case DFU_GETSTATE:
print("Returning state = %d\n", dfu_state);
*(u_int8_t *)io_buffer = dfu_state;
ret = 1;
break;
case DFU_GETSTATUS:
memcpy((u_int8_t *)io_buffer, (void *)&status_req, sizeof(struct usb_dfu_status_request));
if(dfu_state == dfuMANIFEST_SYNC) {
set_status(errOK, DL_DONE_DELAY_MS, dfuMANIFEST, 0);
}
else if(dfu_state == dfuMANIFEST) {
// XXX TODO: validate DFU File Suffix? For now erase them
RELEASE_ASSERT(total_received >= DFU_FILE_SUFFIX_LENGTH);
RELEASE_ASSERT(image_buffer != NULL);
completion_status = total_received - DFU_FILE_SUFFIX_LENGTH;
bzero((void *)&image_buffer[completion_status], DFU_FILE_SUFFIX_LENGTH);
total_received = 0;
// transitioning to this state will break us out of the file wait loop
set_status(errOK, STANDARD_DELAY_MS, dfuMANIFEST_WAIT_RESET, 0);
}
ret = sizeof(struct usb_dfu_status_request);
break;
}
if(ret < 0)
return -1;
usb_core_do_transfer(EP0_IN, (u_int8_t *)io_buffer, ret, NULL);
return 0;
}
return -1;
}
static void handle_bus_reset(void)
{
if(dfu_state == dfuMANIFEST_WAIT_RESET) {
dfu_done = true;
event_signal(&dfu_event);
}
}
static void data_received(u_int32_t received)
{
print("DFU received %d of %d\n", received, expecting);
if(received != expecting) {
set_status(errNOTDONE, STANDARD_DELAY_MS, dfuERROR, 0);
}
else if((total_received + received) > image_buffer_size) {
set_status(errADDRESS, STANDARD_DELAY_MS, dfuERROR, 0);
}
else {
if(!security_allow_memory(&image_buffer[total_received], received)) {
dprintf(DEBUG_INFO, "Permission Denied\n");
completion_status = -1;
dfu_done = true;
event_signal(&dfu_event);
return;
}
memcpy(&image_buffer[total_received], (void *)io_buffer, received);
total_received += received;
expecting = 0;
set_status(errOK, STANDARD_DELAY_MS, dfuDNLOAD_IDLE, 0);
}
}
+904
View File
@@ -0,0 +1,904 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <drivers/usb/usb_core.h>
#include <drivers/dockfifo/dockfifo.h>
#include <drivers/usb/usb_controller.h>
#include <sys/task.h>
#include <endian_tools.h>
#include <platform.h>
// #undef DEBUG_LEVEL
// #define DEBUG_LEVEL DEBUG_SPEW
/*
* 3 bytes header:
* 1byte: endpoint and flags
* bit 7 is direction:
* 0: Host to Device (OUT in USB terms)
* 1: Device to Host (IN in USB terms)
* bit 6 is control packet phase:
* 0: data or N/A
* 1: setup
* bit 5 is fragment continuation:
* 0: last or only packet in fragment
* 1: more packets follow, continuing data
* ep 31: reserved for link control management
* ep 0-30: available
*
* Controller management requests: 1 byte + data
* 1byte: command
* nbytes: data
*/
#define EP_DIR_OUT (0 << 7)
#define EP_DIR_IN (1 << 7)
#define EP_DIR_MASK (1 << 7)
#define EP_PHASE_DATA (0 << 6)
#define EP_PHASE_SETUP (1 << 6)
#define EP_PHASE_MASK (1 << 6)
#define EP_FRAG_LAST (0 << 5)
#define EP_FRAG_MORE (1 << 5)
#define EP_FRAG_MASK (1 << 5)
#define EP_NUM_MASK 0x1f
#define EP_LINK_CONTROL 0x1f
#define MAX_EP_NUMBER 5
#define MAX_EP_NEEDED (MAX_EP_NUMBER * 2 + 2) // 2*EP and EP0 IN/OUT
#define ep_to_epnum(ep) ((ep) & EP_NUM_MASK)
#define ep_to_epdir(ep) ((ep) & EP_DIR_MASK)
#define ep_to_epindex(ep) ((2 * ep_to_epnum((ep))) + (ep_to_epdir((ep)) ? 0 : 1))
enum {
// Host to Device
kCommand_LinkReady = 0x01, // 4 bytes: nonce
kCommand_HostConnect = 0x02, // no data
kCommand_HostDisconnect = 0x03, // no data
kCommand_DeviceBusReset = 0x04, // no data
kCommand_DeviceConnectionSpeed = 0x05, // 1 byte: FS or HS
// Device to Host
kCommand_LinkReadyAck = 0x81, // 4 bytes: repeat nonce from LinkReady command
kCommand_DeviceConnect = 0x82, // no data
kCommand_DeviceDisconnect = 0x83, // no data
kCommand_ConfigureEndpoint = 0x84, // 2 bytes: ep# (msb is direction), XXX config data to be defined
kCommand_EnableEndpoint = 0x85, // 2 byte: ep#, enable (1) or disable (0)
kCommand_StallEndpoint = 0x86, // 2 byte: ep#, set (1) or clear (0) stall
kCommand_Error = 0xff // 1+ bytes: code, data
};
enum {
kError_OK = 0x00, // No error
kError_LinkNotReady = 0x01, // Need LinkReady first
};
#define MAX_PAYLOAD_SIZE (512)
enum {
kEndpointState_Free = 0,
kEndpointState_Allocated_Idle = (1 << 0),
kEndpointState_Allocated_Busy = (1 << 1),
kEndpointState_Allocated_AbortRequested = (1 << 2),
kEndpointState_Allocated_Stalled = (1 << 3),
};
struct usb_endpoint_instance
{
uint32_t endpoint_address;
uint32_t max_packet_size;
uint32_t attributes;
uint32_t bInterval;
uint32_t state;
struct task_event idle_state_event;
uint32_t remote_available;
struct usb_device_io_request *io_request;
};
static void usb_dockfifo_stall_endpoint(uint32_t endpoint, bool stall);
static bool usb_dockfifo_link_ready;
static uint8_t usb_connection_speed;
static bool usb_ep0_data_phase_expected;
static struct usb_endpoint_instance usb_dockfifo_endpoints[MAX_EP_NEEDED];
static struct task *usb_dockfifo_main_task_handle;
static struct task *usb_dockfifo_writer_task_handle;
static struct task_event usb_dockfifo_writer_task_event;
static uint8_t usb_dockfifo_read_buffer_data[MAX_PAYLOAD_SIZE + 1];
static size_t usb_dockfifo_read_buffer_bytes;
//=======================
// Local funtions
//=======================
static void dump_bytes(uint8_t *buffer, size_t size)
{
int32_t i;
dprintf(DEBUG_INFO, "===\n");
for(i = 0; i < (int32_t)size; i++) {
dprintf(DEBUG_INFO, "%02x ", buffer[i]);
}
dprintf(DEBUG_INFO, "\n===\n");
}
static int32_t usb_dockfifo_read_data()
{
static int frame_count = 0;
int32_t ret = dockfifo_bulk_read_frame(
usb_dockfifo_read_buffer_data,
sizeof(usb_dockfifo_read_buffer_data),
&usb_dockfifo_read_buffer_bytes);
if ((ret != 0) || (usb_dockfifo_read_buffer_bytes < 1)) {
dprintf(DEBUG_INFO, "failed to read frame: %d\n", ret);
return ret;
}
dprintf(DEBUG_SPEW, "Receive frame %d\n", ++frame_count);
return 0;
}
static int32_t usb_dockfifo_send_bytes(const uint8_t *data, size_t size)
{
static int frame_count = 0;
dprintf(DEBUG_SPEW, "Send frame %d\n", ++frame_count);
int32_t ret = dockfifo_bulk_write_frame(data, size);
if (ret != 0) {
dprintf(DEBUG_INFO, "failed to write frame: %d\n", ret);
return ret;
}
return 0;
}
static void usb_dockfifo_go_on_bus(bool on)
{
uint8_t data[2];
data[0] = EP_LINK_CONTROL | EP_DIR_IN;
if (on)
data[1] = kCommand_DeviceConnect;
else
data[1] = kCommand_DeviceDisconnect;
usb_dockfifo_send_bytes(data, sizeof(data));
}
static void usb_dockfifo_send_error(uint8_t error_code)
{
dprintf(DEBUG_INFO, "Responding with error 0x%02x\n", error_code);
uint8_t data[3] = {
EP_LINK_CONTROL | EP_DIR_IN,
kCommand_Error,
error_code
};
usb_dockfifo_send_bytes(data, sizeof(data));
}
static void usb_dockfifo_send_available(uint8_t epnum)
{
dprintf(DEBUG_SPEW, "ep%02xOUT available\n", epnum);
uint8_t data[3] = {
epnum | EP_DIR_OUT,
MAX_PAYLOAD_SIZE & 0xff,
(MAX_PAYLOAD_SIZE >> 8) & 0xff
};
usb_dockfifo_send_bytes(data, sizeof(data));
}
static void usb_dockfifo_handle_ready(void)
{
dprintf(DEBUG_SPEW, "Got READY packet. Replying.\n");
// Send ReadyAck.
uint8_t data[8];
data[0] = EP_LINK_CONTROL | EP_DIR_IN;
data[1] = kCommand_LinkReadyAck;
// Ping back with the same nonce value we received.
memcpy(data + 2, usb_dockfifo_read_buffer_data + 2, 4);
// Inform the host about the max packet size (not including
// endpoint byte) we can receive.
ASSERT(DOCKFIFO_BULK_MRU >= MAX_PAYLOAD_SIZE + 1);
write_le_16(data, 6, MAX_PAYLOAD_SIZE);
usb_dockfifo_send_bytes(data, sizeof(data));
// Accept other packets.
usb_dockfifo_link_ready = true;
}
static void usb_dockfifo_handle_link_control(void)
{
// Handle commands from the host.
if (usb_dockfifo_read_buffer_bytes < 2) {
dprintf(DEBUG_INFO,
"Expected LinkControl bytes >= 2, got %d\n",
(int) usb_dockfifo_read_buffer_bytes);
return;
}
uint8_t command = usb_dockfifo_read_buffer_data[1];
if ((!usb_dockfifo_link_ready) && (command != kCommand_LinkReady)) {
dprintf(DEBUG_INFO, "Require Ready command first, got 0x%02x\n",
command);
// Tell host it needs to reset its session.
usb_dockfifo_send_error(kError_LinkNotReady);
return;
}
switch (command) {
case kCommand_LinkReady:
dprintf(DEBUG_INFO, "Got Ready command\n");
usb_dockfifo_handle_ready();
break;
case kCommand_HostConnect:
{
dprintf(DEBUG_INFO, "Got HostConnected command\n");
usb_core_event_handler(CABLE_CONNECTED);
usb_dockfifo_go_on_bus(true);
break;
}
case kCommand_DeviceBusReset:
dprintf(DEBUG_INFO, "Got DeviceBusReset command\n");
usb_core_event_handler(USB_RESET);
break;
case kCommand_DeviceConnectionSpeed:
dprintf(DEBUG_INFO, "Got DeviceConnectionSpeed command\n");
if (usb_dockfifo_read_buffer_bytes < 3) {
dprintf(DEBUG_INFO,
"Expected 3 bytes for DeviceConnectionSpeed\n");
break;
}
usb_connection_speed = usb_dockfifo_read_buffer_data[2] ?
CONNECTION_SPEED_HIGH : CONNECTION_SPEED_FULL;
usb_core_event_handler(USB_ENUM_DONE);
break;
case kCommand_HostDisconnect:
dprintf(DEBUG_INFO, "Got HostDisconnected command\n");
usb_core_event_handler(CABLE_DISCONNECTED);
usb_dockfifo_go_on_bus(false);
break;
default:
dprintf(DEBUG_INFO, "Unknown command 0x%02x\n", command);
}
}
static void usb_dockfifo_handle_endpoint_out(uint32_t endpoint, const uint8_t *buffer, size_t bytes)
{
dprintf(DEBUG_SPEW, "handle epout %02x %d\n", endpoint, (int) bytes);
// Get endpoint.
size_t epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
uint32_t ep_num = ep_to_epnum(endpoint);
ASSERT((ep_num <= EP_NUM_MASK) && (ep_num != EP_LINK_CONTROL));
struct usb_endpoint_instance *ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
if ((ep->io_request == NULL) || (ep->state & kEndpointState_Allocated_AbortRequested)) {
dprintf(DEBUG_INFO, "Dropping unexpected data received for endpoint %x, state:%d io_request:%p\n", endpoint, ep->state, ep->io_request);
return;
}
// Get IO request, transfer size.
struct usb_device_io_request *req = ep->io_request;
ASSERT(req != NULL);
uint32_t xfer_size = req->io_length - req->return_count;
// Make sure we have space left to copy this data
RELEASE_ASSERT(bytes <= xfer_size);
// Save data received
memcpy((void *) req->io_buffer + req->return_count, buffer, bytes);
// Update IO request.
req->return_count += bytes;
dprintf(DEBUG_SPEW, "ep%02xout now %d/%d\n",
ep_num, (int) req->return_count, (int) req->io_length);
if ((bytes == ep->max_packet_size) &&
(req->return_count < req->io_length) &&
((ep->state & kEndpointState_Allocated_AbortRequested) == 0)) {
// More data to be received
dprintf(DEBUG_SPEW, "More to be received\n");
usb_dockfifo_send_available(ep_to_epnum(req->endpoint));
return;
} else {
// Completed transaction, update status and return
dprintf(DEBUG_SPEW, "Completed a transaction\n");
ep->io_request = NULL;
uint32_t old_state = ep->state;
ep->state = kEndpointState_Allocated_Idle;
event_signal(&ep->idle_state_event);
if (!(old_state & kEndpointState_Allocated_AbortRequested)) {
req->status = USB_IO_SUCCESS;
usb_core_complete_endpoint_io(req);
}
}
}
static void usb_dockfifo_start_endpoint_in(uint32_t endpoint)
{
static uint8_t buf[MAX_PAYLOAD_SIZE + 1];
// Get endpoint.
size_t epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
uint32_t ep_num = ep_to_epnum(endpoint);
ASSERT((ep_num <= EP_NUM_MASK) && (ep_num != EP_LINK_CONTROL));
struct usb_endpoint_instance *ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
// Get IO request, transfer size.
struct usb_device_io_request *req = ep->io_request;
ASSERT(req != NULL);
uint32_t xfer_size = req->io_length - req->return_count;
// Fragment the request if it exceeds max buffer size.
bool fragment = false;
if (xfer_size > MAX_PAYLOAD_SIZE) {
xfer_size = MAX_PAYLOAD_SIZE;
fragment = true;
}
// Should be some remote buffer space available before this function
// was invoked.
ASSERT(ep->remote_available > 0);
if (xfer_size > ep->remote_available) {
xfer_size = ep->remote_available;
fragment = true;
}
ep->remote_available = 0;
// Encode the endpoint and transfer flags.
uint8_t encoded_ep = ep_num | EP_DIR_IN;
if (fragment) {
encoded_ep |= EP_FRAG_MORE;
}
dprintf(DEBUG_SPEW, "ep_num:0x%02x sent:%d io_len:%d xfer:%d frag:%d\n",
ep_num,
(int) req->return_count,
(int) req->io_length,
(int) xfer_size,
(int) fragment);
// Send encoded endpoint|flags, followed by payload.
buf[0] = encoded_ep;
memcpy(buf + 1, (void *) req->io_buffer + req->return_count, xfer_size);
usb_dockfifo_send_bytes(buf, xfer_size + 1);
dprintf(DEBUG_SPEW, "Sent\n");
// Update IO request.
req->return_count += xfer_size;
if (fragment && ((ep->state & kEndpointState_Allocated_AbortRequested) == 0)) {
// More data needs transmitting for this packet.
event_signal(&usb_dockfifo_writer_task_event);
} else {
// Completed this packet, update status and return
uint32_t old_state = ep->state;
ep->state = kEndpointState_Allocated_Idle;
event_signal(&ep->idle_state_event);
if (!(old_state & kEndpointState_Allocated_AbortRequested)) {
req->status = USB_IO_SUCCESS;
ep->io_request = NULL;
usb_core_complete_endpoint_io(req);
}
}
}
static bool usb_dockfifo_handle_ep0_data(uint8_t *buf, size_t bytes,
bool *data_phase)
{
// Fragment into EP0_MAX_PACKET_SIZE chunks.
while (bytes > 0) {
size_t to_receive = EP0_MAX_PACKET_SIZE;
if (to_receive > bytes) {
to_receive = bytes;
}
usb_core_handle_usb_control_receive(buf, false, to_receive,
data_phase);
buf += to_receive;
bytes -= to_receive;
if (bytes > 0 && !*data_phase) {
dprintf(DEBUG_INFO, "Began setup phase in fragment\n");
return false;
}
}
return true;
}
static bool usb_dockfifo_dispatch_ep_out(void)
{
ASSERT(usb_dockfifo_read_buffer_bytes >= 1);
uint8_t endpoint = usb_dockfifo_read_buffer_data[0];
ASSERT((endpoint & EP_DIR_MASK) == EP_DIR_OUT);
switch (endpoint & ~EP_FRAG_MASK) {
case EP_LINK_CONTROL | EP_DIR_OUT:
usb_dockfifo_handle_link_control();
return true;
case 0 | EP_PHASE_SETUP | EP_DIR_OUT:
dprintf(DEBUG_SPEW, "Setup packet received\n");
if (usb_dockfifo_read_buffer_bytes < 1 + SETUP_PACKET_LEN) {
dprintf(DEBUG_INFO,
"Setup packet too small: %d\n",
(int) usb_dockfifo_read_buffer_bytes);
return false;
}
if (usb_dockfifo_read_buffer_bytes > 1 + EP0_MAX_PACKET_SIZE) {
dprintf(DEBUG_INFO,
"Setup packet too big: %d\n",
(int) usb_dockfifo_read_buffer_bytes);
return false;
}
// auto-clear stall if endpoint was previously stalled
usb_dockfifo_stall_endpoint(0x80, false);
usb_ep0_data_phase_expected = false;
usb_core_handle_usb_control_receive(
usb_dockfifo_read_buffer_data + 1, true,
SETUP_PACKET_LEN,
&usb_ep0_data_phase_expected);
return true;
case 0 | EP_PHASE_DATA | EP_DIR_OUT:
dprintf(DEBUG_SPEW, "Data phase for setup packet\n");
usb_ep0_data_phase_expected = false;
if (!usb_dockfifo_handle_ep0_data(
usb_dockfifo_read_buffer_data + 1,
usb_dockfifo_read_buffer_bytes - 1,
&usb_ep0_data_phase_expected)) {
return false;
}
return true;
default:
usb_dockfifo_handle_endpoint_out(
(endpoint & ~EP_FRAG_MASK),
(usb_dockfifo_read_buffer_data + 1),
(usb_dockfifo_read_buffer_bytes - 1));
return true;
}
}
static bool usb_dockfifo_dispatch_ep_in(void)
{
// Update remote_available for this endpoint.
ASSERT(usb_dockfifo_read_buffer_bytes >= 1);
uint8_t endpoint = usb_dockfifo_read_buffer_data[0];
ASSERT((endpoint & EP_DIR_MASK) == EP_DIR_IN);
uint32_t ep_num = ep_to_epnum(endpoint);
ASSERT((ep_num <= EP_NUM_MASK) && (ep_num != EP_LINK_CONTROL));
size_t epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
struct usb_endpoint_instance *ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
if (usb_dockfifo_read_buffer_bytes < 3) {
dprintf(DEBUG_INFO, "Runt EPIN packet\n");
return false;
}
uint16_t available = 0;
memcpy(&available, &usb_dockfifo_read_buffer_data[1],
sizeof(available));
ep->remote_available = available;
dprintf(DEBUG_SPEW, "ep%02x remote_available %d\n",
(int) ep_num, (int) available);
if (available > 0) {
// Writer task may have been waiting to send data.
event_signal(&usb_dockfifo_writer_task_event);
}
return true;
}
static void usb_dockfifo_main_task_session(void)
{
dprintf(DEBUG_INFO, "DockFifo USB session started\n");
// Reset USB state.
usb_core_event_handler(USB_RESET);
// Require a Ready packet first.
usb_dockfifo_link_ready = false;
// Wait for DOCK_CONNECT.
while (platform_get_dock_connect() == false) {
dprintf(DEBUG_INFO, "Waiting for dock connect\n");
task_sleep(100*1000);
}
// Loop while in a good state. Breaking out of the loop breaks
// the link until a new Ready packet is received.
for (;;) {
dprintf(DEBUG_SPEW, "main loop\n");
// Read a packet.
usb_dockfifo_read_data();
if (usb_dockfifo_read_buffer_bytes < 1) {
dprintf(DEBUG_INFO, "Runt packet\n");
break;
}
// Get endpoint number.
uint8_t endpoint = usb_dockfifo_read_buffer_data[0];
dprintf(DEBUG_SPEW, "Got EP%s%02x %s %s %d\n",
(endpoint & EP_DIR_MASK) == EP_DIR_OUT ? "OUT" : "IN",
endpoint & EP_NUM_MASK,
(endpoint & EP_PHASE_MASK) == EP_PHASE_DATA ?
"data" : "setup",
(endpoint & EP_FRAG_MASK) == EP_FRAG_MORE ?
"frag" : "no frag",
(int) (usb_dockfifo_read_buffer_bytes - 1));
// If we're not Link-Ready yet, any packet other than
// LinkReady will be responded with an error, but we
// don't need to exit the loop.
if (!usb_dockfifo_link_ready &&
endpoint != (EP_LINK_CONTROL | EP_DIR_OUT)) {
dprintf(DEBUG_INFO, "Non-link packet before Ready\n");
// Tell host it needs to reset its session.
usb_dockfifo_send_error(kError_LinkNotReady);
continue;
}
// Dispatch based on endpoint.
bool ok;
if ((endpoint & EP_DIR_MASK) == EP_DIR_OUT) {
ok = usb_dockfifo_dispatch_ep_out();
} else {
ok = usb_dockfifo_dispatch_ep_in();
}
if (!ok) {
break;
}
}
dprintf(DEBUG_INFO, "dockfifo USB session ended\n");
}
static int usb_dockfifo_main_task(void *args)
{
for (;;) {
// Keep re-trying sessions. If there are protocol
// errors, restart from scratch.
usb_dockfifo_main_task_session();
}
}
static int usb_dockfifo_writer_task(void *args)
{
for (;;) {
static int32_t current_ep_in;
event_wait(&usb_dockfifo_writer_task_event);
// walk through IN endpoints for any pending io's, if nothing pending wait for more work
for (current_ep_in = 0; current_ep_in < MAX_EP_NEEDED; current_ep_in += 2) {
if ((usb_dockfifo_endpoints[current_ep_in].state == kEndpointState_Allocated_Busy) &&
(usb_dockfifo_endpoints[current_ep_in].io_request != NULL) &&
(usb_dockfifo_endpoints[current_ep_in].remote_available > 0))
usb_dockfifo_start_endpoint_in(usb_dockfifo_endpoints[current_ep_in].endpoint_address);
}
}
return 0;
}
static int usb_dockfifo_init()
{
bzero(usb_dockfifo_endpoints, sizeof(struct usb_endpoint_instance) * MAX_EP_NEEDED);
// main task to do initial handshake and enumeration
usb_dockfifo_main_task_handle = task_create("usb_dockfifo main", usb_dockfifo_main_task, NULL, 0x1000);
// writer task
usb_dockfifo_writer_task_handle = task_create("usb_dockfifo writer", usb_dockfifo_writer_task, NULL, 0x1000);
event_init(&usb_dockfifo_writer_task_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
return 0;
}
static void usb_dockfifo_free()
{
// dockfifo_bulk_quiesce();
}
static int usb_dockfifo_start()
{
event_init(&usb_dockfifo_endpoints[ep_to_epindex(EP0_IN)].idle_state_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
usb_dockfifo_endpoints[ep_to_epindex(EP0_IN)].endpoint_address = 0x80;
usb_dockfifo_endpoints[ep_to_epindex(EP0_IN)].max_packet_size = EP0_MAX_PACKET_SIZE;
usb_dockfifo_endpoints[ep_to_epindex(EP0_IN)].state = kEndpointState_Allocated_Idle;
event_init(&usb_dockfifo_endpoints[ep_to_epindex(EP0_OUT)].idle_state_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
usb_dockfifo_endpoints[ep_to_epindex(EP0_OUT)].endpoint_address = 0;
usb_dockfifo_endpoints[ep_to_epindex(EP0_OUT)].max_packet_size = EP0_MAX_PACKET_SIZE;
usb_dockfifo_endpoints[ep_to_epindex(EP0_OUT)].state = kEndpointState_Allocated_Idle;
dockfifo_bulk_init();
task_start(usb_dockfifo_main_task_handle);
task_start(usb_dockfifo_writer_task_handle);
return 0;
}
static void usb_dockfifo_stop()
{
usb_dockfifo_go_on_bus(false);
}
static void usb_dockfifo_set_address(uint32_t new_address)
{
}
static int usb_dockfifo_get_connection_speed()
{
return usb_connection_speed;
}
static void usb_dockfifo_activate_endpoint(uint32_t endpoint, int type, int max_packet_size, int interval)
{
uint32_t epindex;
struct usb_endpoint_instance *ep;
enter_critical_section();
ASSERT(ep_to_epnum(endpoint) <= MAX_EP_NUMBER);
epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
if(ep->state != kEndpointState_Free)
goto exit;
ep->endpoint_address = endpoint;
ep->attributes = type;
ep->max_packet_size = max_packet_size;
ep->bInterval = interval;
event_init(&ep->idle_state_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
ep->state = kEndpointState_Allocated_Idle;
exit:
exit_critical_section();
}
static void usb_dockfifo_do_endpoint_io(struct usb_device_io_request *req)
{
struct usb_endpoint_instance *ep;
uint32_t epindex;
dprintf(DEBUG_SPEW, "endpoint %02x len %d\n", req->endpoint,
(int) req->io_length);
enter_critical_section();
ASSERT(ep_to_epnum(req->endpoint) <= MAX_EP_NUMBER);
epindex = ep_to_epindex(req->endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
req->return_count = 0;
req->status = USB_IO_ERROR;
req->next = NULL;
// make sure endpoint is idle
if(ep->state != kEndpointState_Allocated_Idle) {
dprintf(DEBUG_INFO, "endpoint %x is not idle, state:%x\n", req->endpoint, ep->state);
event_wait(&ep->idle_state_event);
dprintf(DEBUG_INFO, "endpoint %x got idle state\n",
req->endpoint);
}
// save IO
RELEASE_ASSERT(ep->io_request == NULL);
ep->io_request = req;
// mark endpoint busy
ep->state = kEndpointState_Allocated_Busy;
event_unsignal(&ep->idle_state_event);
// start transmitting/receiving the data
if (ep_to_epdir(req->endpoint)) {
dprintf(DEBUG_SPEW, "EP%02x start write len %d\n",
ep_to_epnum(req->endpoint), (int) req->io_length);
event_signal(&usb_dockfifo_writer_task_event);
} else {
dprintf(DEBUG_SPEW, "EP%02x advertise available\n",
ep_to_epnum(req->endpoint));
usb_dockfifo_send_available(ep_to_epnum(req->endpoint));
}
exit_critical_section();
}
static void usb_dockfifo_stall_endpoint(uint32_t endpoint, bool stall)
{
struct usb_endpoint_instance *ep;
uint32_t epindex;
// Nothing to do for EP0_OUT
if(endpoint == 0)
return;
enter_critical_section();
ASSERT(ep_to_epnum(endpoint) <= MAX_EP_NUMBER);
epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
dprintf(DEBUG_SPEW, "stall endpoint %x, state:%x, stall:%d\n", endpoint, ep->state, stall);
if (stall) {
// if already stalled, nothing to do
if ((ep->state & kEndpointState_Allocated_Stalled) != 0)
return;
// wait for endpoint to be idle
if (ep->state != kEndpointState_Allocated_Idle)
event_wait(&ep->idle_state_event);
ep->state |= kEndpointState_Allocated_Stalled;
}
else {
// if not stalled, nothing to do
if ((ep->state & kEndpointState_Allocated_Stalled) == 0)
return;
}
// Notify Dock
uint8_t data[] = {
EP_LINK_CONTROL | EP_DIR_IN,
kCommand_StallEndpoint,
endpoint,
stall
};
usb_dockfifo_send_bytes(data, sizeof(data));
if (!stall) {
ep->state = kEndpointState_Allocated_Idle;
event_signal(&ep->idle_state_event);
}
exit_critical_section();
}
static void usb_dockfifo_reset_endpoint_data_toggle(uint32_t endpoint)
{
}
static bool usb_dockfifo_is_endpoint_stalled(uint32_t endpoint)
{
struct usb_endpoint_instance *ep;
uint32_t epindex;
enter_critical_section();
ASSERT(ep_to_epnum(endpoint) <= MAX_EP_NUMBER);
epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
dprintf(DEBUG_SPEW, "endpoint %x, state:%x\n", endpoint, ep->state);
exit_critical_section();
return ((ep->state & kEndpointState_Allocated_Stalled) != 0);
}
static void usb_dockfifo_do_test_mode(uint32_t selector)
{
}
static void usb_dockfifo_abort_endpoint(uint32_t endpoint)
{
uint32_t epindex;
struct usb_endpoint_instance *ep;
enter_critical_section();
ASSERT(ep_to_epnum(endpoint) <= MAX_EP_NUMBER);
epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
dprintf(DEBUG_SPEW, "abort endpoint %x, state:%x\n", endpoint, ep->state);
if (ep->state != kEndpointState_Allocated_Busy)
goto exit;
ep->state |= kEndpointState_Allocated_AbortRequested;
// wait for endpoint to be idle
if (ep->state != kEndpointState_Allocated_Idle)
event_wait(&ep->idle_state_event);
ep->io_request->status = USB_IO_ABORTED;
usb_core_complete_endpoint_io(ep->io_request);
ep->io_request = NULL;
dprintf(DEBUG_SPEW, "abort endpoint %x finished, state:%x\n", endpoint, ep->state);
exit:
exit_critical_section();
}
static void usb_dockfifo_deactivate_endpoint(uint32_t endpoint)
{
uint32_t epindex;
struct usb_endpoint_instance *ep;
enter_critical_section();
ASSERT(ep_to_epnum(endpoint) <= MAX_EP_NUMBER);
epindex = ep_to_epindex(endpoint);
ASSERT(epindex < MAX_EP_NEEDED);
ep = &usb_dockfifo_endpoints[epindex];
ASSERT(ep != NULL);
if(ep->state == kEndpointState_Free)
goto exit;
usb_dockfifo_abort_endpoint(endpoint);
bzero(&usb_dockfifo_endpoints[ep_to_epindex(endpoint)], sizeof(struct usb_endpoint_instance));
exit:
exit_critical_section();
}
static const struct usb_controller_functions usb_dockfifo_controller_functions = {
.init = usb_dockfifo_init,
.free = usb_dockfifo_free,
.start = usb_dockfifo_start,
.stop = usb_dockfifo_stop,
.set_address = usb_dockfifo_set_address,
.get_connection_speed = usb_dockfifo_get_connection_speed,
.activate_endpoint = usb_dockfifo_activate_endpoint,
.do_endpoint_io = usb_dockfifo_do_endpoint_io,
.stall_endpoint = usb_dockfifo_stall_endpoint,
.reset_endpoint_data_toggle = usb_dockfifo_reset_endpoint_data_toggle,
.is_endpoint_stalled = usb_dockfifo_is_endpoint_stalled,
.do_test_mode = usb_dockfifo_do_test_mode,
.abort_endpoint = usb_dockfifo_abort_endpoint,
.deactivate_endpoint = usb_dockfifo_deactivate_endpoint,
};
//=======================
// Global funtions
//=======================
const struct usb_controller_functions *usb_dockfifo_controller_init()
{
return &usb_dockfifo_controller_functions;
}
+389
View File
@@ -0,0 +1,389 @@
/*
* Copyright (C) 2007-2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
////////////////////////////////////////////////////////////////////
// USB Serial
// This file implements usb serial emulation protocol. We have 'usbterm'
// tool on the Mac to enable this.
////////////////////////////////////////////////////////////////////
#include <debug.h>
#include <sys/types.h>
#include <stdlib.h>
#include <drivers/usb/usb_chap9.h>
#include <drivers/usb/usb_public.h>
#include <drivers/usb/usb_core.h>
#include <platform/memmap.h>
#include <sys.h>
#include <sys/task.h>
#include <lib/cbuf.h>
#include <sys/callout.h>
//==============================================================================================
// Local conts, macors, structs, typedefs
//==============================================================================================
#define WRITE_CBUF_MAX_CAPACITY (4096)
#define DEBUG 0
#if DEBUG
#define print(fmt, args...) printf("%s --- " fmt, __FUNCTION__, ##args)
#else
#define print(fmt, args...) (void)0
#endif
struct usb_serial_buffer {
u_int8_t bytes[HS_BULK_EP_MAX_PACKET_SIZE];
};
//==============================================================================================
// Global and Local variables
//==============================================================================================
static const struct usb_interface_descriptor usb_serial_interface_descriptors[APPLE_USB_SERIAL_TOTAL_INTFS] =
{
{
USB_DT_INTERFACE_SIZE,
USB_DT_INTERFACE,
APPLE_USB_SERIAL_INTF,
0,
0,
APPLE_USB_SERIAL_CLASS,
APPLE_USB_SERIAL_SUBCLASS,
APPLE_USB_SERIAL_PROTOCOL,
0
},
{
USB_DT_INTERFACE_SIZE,
USB_DT_INTERFACE,
APPLE_USB_SERIAL_INTF,
1,
APPLE_USB_SERIAL_TOTAL_EPS,
APPLE_USB_SERIAL_CLASS,
APPLE_USB_SERIAL_SUBCLASS,
APPLE_USB_SERIAL_PROTOCOL,
0
}
};
static const struct usb_endpoint_descriptor usb_serial_endpoint_descriptors[APPLE_USB_SERIAL_TOTAL_EPS] = {
{
USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT,
APPLE_USB_SERIAL_EP_BULK_IN,
USB_ENDPOINT_BULK,
HS_BULK_EP_MAX_PACKET_SIZE,
0
},
{
USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT,
APPLE_USB_SERIAL_EP_BULK_OUT,
USB_ENDPOINT_BULK,
HS_BULK_EP_MAX_PACKET_SIZE,
0
}
};
static const char *usb_serial_string_descriptors[APPLE_USB_SERIAL_TOTAL_INTFS] =
{
NULL,
"Apple USB Serial Interface"
};
static struct usb_interface_instance usb_serial_interface_instance;
static struct usb_serial_buffer *out_buffer;
static struct usb_serial_buffer *in_buffer;
static struct task_event in_buffer_event;
static struct cbuf *usb_serial_output_cbuf;
static bool usb_serial_inited;
static volatile bool usb_serial_activated;
static int current_alt_setting;
//==============================================================================================
// Functions Prototypes
//==============================================================================================
static int usb_serial_flush_write_cbuf (bool start_transfer, u_int32_t length);
static void usb_serial_transfer_finished_cb (struct usb_device_io_request *io_request);
static void usb_serial_activate_endpoints (void);
static void usb_serial_deactivate_endpoints (void);
static int usb_serial_get_max_packet_size(void);
static int usb_serial_task_entry(void *arg);
//==============================================================================================
// Local functions
//==============================================================================================
static void usb_serial_activate_interface (void)
{
usb_serial_activate_endpoints();
usb_core_do_transfer(APPLE_USB_SERIAL_EP_BULK_OUT, (u_int8_t *)out_buffer, sizeof(*out_buffer), usb_serial_transfer_finished_cb);
usb_serial_activated = true;
task_start(task_create("usb_serial", usb_serial_task_entry, NULL, 0x400));
}
static void usb_serial_deactivate_interface (void)
{
usb_serial_activated = false;
usb_serial_deactivate_endpoints();
}
static void usb_serial_activate_endpoints (void)
{
int i;
for(i = 0; i < APPLE_USB_SERIAL_TOTAL_EPS; i++) {
usb_core_activate_endpoint(usb_serial_endpoint_descriptors[i].bEndpointAddress,
usb_serial_endpoint_descriptors[i].bmAttributes,
usb_serial_get_max_packet_size(),
usb_serial_endpoint_descriptors[i].bInterval);
}
}
static void usb_serial_deactivate_endpoints (void)
{
int i;
for(i = 0; i < APPLE_USB_SERIAL_TOTAL_EPS; i++) {
usb_core_deactivate_endpoint(usb_serial_endpoint_descriptors[i].bEndpointAddress);
}
}
static void usb_serial_transfer_finished_cb (struct usb_device_io_request *io_request)
{
print("callback %x\n", io_request->endpoint);
if(io_request->endpoint == APPLE_USB_SERIAL_EP_BULK_OUT) {
if (io_request->status == USB_IO_SUCCESS) {
u_int32_t i = 0;
u_int32_t count;
count = __min(io_request->return_count, sizeof(*out_buffer));
while(i < count) {
debug_pushchar(out_buffer->bytes[i++]);
}
}
else {
dprintf(DEBUG_INFO, "failed to read\n");
}
usb_core_do_transfer(APPLE_USB_SERIAL_EP_BULK_OUT, (u_int8_t *)out_buffer, sizeof(*out_buffer), usb_serial_transfer_finished_cb);
}
else if (io_request->endpoint == APPLE_USB_SERIAL_EP_BULK_IN) {
event_signal(&in_buffer_event);
if (io_request->status != USB_IO_SUCCESS) {
dprintf(DEBUG_INFO, "failed to write\n");
}
}
}
static int usb_serial_handle_set_interface (int value)
{
switch(value) {
case 0 :
usb_serial_deactivate_interface();
current_alt_setting = 0;
break;
case 1 :
usb_serial_activate_interface();
current_alt_setting = 1;
break;
default :
return -1;
}
return 0;
}
static int usb_serial_handle_get_interface (void)
{
return (current_alt_setting);
}
static int usb_serial_task_entry(void *arg __unused)
{
while (usb_serial_activated) {
if(usb_serial_flush_write_cbuf(true, sizeof(*in_buffer)) == 0)
{
task_sleep(15 * 1000);
}
}
return 0;
}
static int usb_serial_flush_write_cbuf (bool start_transfer, u_int32_t length)
{
u_int32_t i = 0;
char c = 0;
u_int32_t max_len = __min(length, sizeof(*in_buffer));
while(false == event_wait_timeout(&in_buffer_event, 5000 * 1000)) {
if(usb_serial_activated) {
usb_core_abort_endpoint(APPLE_USB_SERIAL_EP_BULK_IN);
}
}
while(i < max_len) {
if(cbuf_read_char(usb_serial_output_cbuf, &c) == 0) {
break;
}
in_buffer->bytes[i++] = c;
}
if(i && start_transfer) {
usb_core_do_transfer(APPLE_USB_SERIAL_EP_BULK_IN, (u_int8_t *)in_buffer, i, usb_serial_transfer_finished_cb);
}
else {
event_signal(&in_buffer_event);
}
return i; // Number of characters written to USB Buffer
}
static int usb_serial_get_max_packet_size(void)
{
int mps;
if(usb_core_get_connection_speed() == CONNECTION_SPEED_HIGH) {
mps = HS_BULK_EP_MAX_PACKET_SIZE;
}
else {
mps = FS_EP_MAX_PACKET_SIZE;
}
return mps;
}
//==============================================================================================
// Global functions
//==============================================================================================
int usb_serial_early_init (void)
{
in_buffer = memalign(sizeof(*in_buffer), CPU_CACHELINE_SIZE);
bzero(in_buffer, sizeof(*in_buffer));
usb_serial_output_cbuf = cbuf_create(WRITE_CBUF_MAX_CAPACITY, NULL);
if(usb_serial_output_cbuf == NULL) {
usb_serial_inited = false;
dprintf(DEBUG_INFO, "usb_serial_output_cbuf create failed \n");
return -1;
}
event_init(&in_buffer_event, EVENT_FLAG_AUTO_UNSIGNAL, true);
usb_serial_inited = true;
return 0;
}
int usb_serial_init (void)
{
if(!usb_serial_inited) {
dprintf(DEBUG_INFO, "usb_serial_early_init failed \n");
return -1;
}
usb_serial_activated = false;
current_alt_setting = 0;
out_buffer = memalign(sizeof(*out_buffer), CPU_CACHELINE_SIZE);
if(out_buffer == NULL) {
dprintf(DEBUG_INFO, "usb_serial:usb_serial_init --- out_buffer memalign failed \n");
return -1;
}
bzero(out_buffer, sizeof(*out_buffer));
usb_serial_interface_instance.total_interfaces = APPLE_USB_SERIAL_TOTAL_INTFS;
usb_serial_interface_instance.interface_descs = (struct usb_interface_descriptor *)&usb_serial_interface_descriptors;
usb_serial_interface_instance.total_endpoints = APPLE_USB_SERIAL_TOTAL_EPS;
usb_serial_interface_instance.endpoint_descs = (struct usb_endpoint_descriptor *)&usb_serial_endpoint_descriptors;
usb_serial_interface_instance.total_string_descs = APPLE_USB_SERIAL_TOTAL_INTFS;
usb_serial_interface_instance.string_descs = (char **)usb_serial_string_descriptors;
usb_serial_interface_instance.deactivate_interface = usb_serial_deactivate_interface;
usb_serial_interface_instance.handle_set_interface = usb_serial_handle_set_interface;
usb_serial_interface_instance.handle_get_interface = usb_serial_handle_get_interface;
usb_core_register_interface(&usb_serial_interface_instance);
return 0;
}
void usb_serial_putchar(int c)
{
int ret = 0;
if((ret = cbuf_write_char(usb_serial_output_cbuf, c)) == 0) {
bool start_transfer = false;
u_int32_t len = 1;
if(usb_serial_activated) {
len = usb_serial_get_max_packet_size();
start_transfer = true;
}
usb_serial_flush_write_cbuf(start_transfer, len);
cbuf_write_char(usb_serial_output_cbuf, c);
}
}
void usb_serial_exit (void)
{
if(usb_serial_output_cbuf) {
cbuf_destroy(usb_serial_output_cbuf);
usb_serial_output_cbuf = NULL;
}
if(in_buffer) {
free(in_buffer);
in_buffer = NULL;
}
if(out_buffer) {
free(out_buffer);
out_buffer = NULL;
}
usb_serial_inited = false;
}
int usb_serial_send_cmd_string(u_int8_t *buffer, u_int32_t len)
{
if(!usb_serial_activated) {
return -1;
}
usb_core_do_transfer(APPLE_USB_SERIAL_EP_BULK_IN, buffer, len, NULL);
return 0;
}
bool usb_serial_is_active()
{
return ((current_alt_setting == 1) ? true : false);
}
+416
View File
@@ -0,0 +1,416 @@
/*
* Copyright (C) 2010-2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
////////////////////////////////////////////////////////////////////
// USB Bulk Upload + File transfer
//
// This file implements USB Bulk protocol for file uploads;
// and it also implements vendor specific file transfer
// protocol using a bulk pipe.
///////////////////////////////////////////////////////////////////
#include <debug.h>
#include <sys/task.h>
#include <lib/profile.h>
#include <lib/env.h>
#include <sys/security.h>
#include <platform/memmap.h>
#include <drivers/usb/usb_chap9.h>
#include <drivers/usb/usb_public.h>
#include <drivers/usb/usb_core.h>
#define DEBUG 0
#if DEBUG
#define print(fmt, args...) printf("%s - " fmt, __FUNCTION__, ##args)
#else
#define print(fmt, args...) (void)0
#endif
#ifdef SUPPORT_FPGA
#define TIMEOUT_SCALER (10)
#else
#define TIMEOUT_SCALER (1)
#endif
#define BULK_HS_TRNSFR_TIMEOUT (15 * 1000 * 1000 * TIMEOUT_SCALER)
#define BULK_FS_TRNSFR_TIMEOUT (30 * 1000 * 1000 * TIMEOUT_SCALER)
#define ERR_PACKET_LEN (4)
#define ERR_PKT_START (0xfb)
#define ERR_PKT_END (0xfa)
// File transfer error codes
#define ERR_FILE_SUCCESS 0
#define ERR_FILE_UNKNOWN_ERROR 1
#define ERR_FILE_UNEXPECTED_ERROR 2
#define ERR_FILE_NOT_FOUND 3
#define ERR_FILE_READ_ERROR 4
#define ERR_FILE_WRITE_ERROR 5
// Personalization related file transfer error codes
#define ERR_PFILE_NOT_IM4P 11
#define ERR_PFILE_CREATE_FAILED 12
#define ERR_PFILE_READ_ERROR 13
static const struct usb_interface_descriptor usb_trnsfr_interface_descriptor = {
USB_DT_INTERFACE_SIZE,
USB_DT_INTERFACE,
APPLE_USB_TRNSFR_INTF,
0,
APPLE_USB_TRNSFR_TOTAL_EPS,
APPLE_USB_TRNSFR_CLASS,
APPLE_USB_TRNSFR_SUBCLASS,
APPLE_USB_TRNSFR_PROTOCOL,
0
};
static const struct usb_endpoint_descriptor usb_trnsfr_endpoint_descriptors [] = {
{
USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT,
APPLE_USB_TRNSFR_EP_BULK_OUT,
USB_ENDPOINT_BULK,
HS_BULK_EP_MAX_PACKET_SIZE,
0
}
#if WITH_BULK_UPLOAD
,
{
USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT,
APPLE_USB_TRNSFR_EP_BULK_IN,
USB_ENDPOINT_BULK,
HS_BULK_EP_MAX_PACKET_SIZE,
0
}
#endif
};
static struct usb_interface_instance usb_trnsfr_interface_instance;
static struct task_event trnsfr_event;
static volatile bool trnsfr_done;
static int completion_status;
static u_int8_t *image_buffer;
static u_int32_t image_buffer_size;
static struct callout trnsfr_callout;
static u_int32_t max_transfer_len;
#if WITH_BULK_UPLOAD
static u_int8_t __aligned(CPU_CACHELINE_SIZE) bulk_in_zlp_buffer[sizeof(u_int32_t)];
static u_int8_t __aligned(CPU_CACHELINE_SIZE) bulk_upload_status_buffer[ERR_PACKET_LEN];
static void bulk_in_callback(struct usb_device_io_request *io_request);
static void bulk_upload_status_callback(struct usb_device_io_request *io_request);
#endif // WITH_BULK_UPLOAD
static void activate_interface(void);
static void deactivate_interface(void);
static void bulk_transfer_callback(struct usb_device_io_request *io_request);
static void handle_trnsfr_callout(struct callout *co, void *args);
static int handle_vendor_request(struct usb_device_request *request);
static void transfer_failed();
int usb_transfer_init()
{
completion_status = -1;
image_buffer = NULL;
image_buffer_size = 0;
trnsfr_done = false;
event_init(&trnsfr_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
usb_trnsfr_interface_instance.total_interfaces = APPLE_USB_TRNSFR_TOTAL_INTFS;
usb_trnsfr_interface_instance.interface_descs = (struct usb_interface_descriptor *)&usb_trnsfr_interface_descriptor;
usb_trnsfr_interface_instance.total_endpoints = APPLE_USB_TRNSFR_TOTAL_EPS;
usb_trnsfr_interface_instance.endpoint_descs = (struct usb_endpoint_descriptor *)&usb_trnsfr_endpoint_descriptors;
usb_trnsfr_interface_instance.deactivate_interface = deactivate_interface;
usb_trnsfr_interface_instance.activate_interface = activate_interface;
#if WITH_RECOVERY_MODE
usb_trnsfr_interface_instance.handle_vendor_request = handle_vendor_request;
#endif // WITH_RECOVERY_MODE
usb_core_register_interface(&usb_trnsfr_interface_instance);
return 0;
}
void usb_transfer_exit()
{
}
void usb_transfer_prepare(int type, void *address, u_int32_t length)
{
u_int32_t timeout;
print("\n");
timeout = 0;
completion_status = -1;
image_buffer = address;
image_buffer_size = length;
trnsfr_done = false;
#if WITH_ENV
env_set_uint("filesize", 0, 0);
#endif // WITH_ENV
if(type == USB_TRANSFER_TYPE_BULK_GET) {
max_transfer_len = DEFAULT_RAMDISK_SIZE;
if(!security_allow_memory((u_int8_t *)image_buffer, max_transfer_len)) {
dprintf(DEBUG_INFO, "Permission denied\n");
return;
}
if(usb_core_get_connection_speed() == CONNECTION_SPEED_HIGH)
timeout = BULK_HS_TRNSFR_TIMEOUT;
else
timeout = BULK_FS_TRNSFR_TIMEOUT;
usb_core_abort_endpoint(APPLE_USB_TRNSFR_EP_BULK_OUT);
usb_core_do_transfer(APPLE_USB_TRNSFR_EP_BULK_OUT, image_buffer, max_transfer_len,
bulk_transfer_callback);
}
#if WITH_BULK_UPLOAD
else if(type == USB_TRANSFER_TYPE_BULK_PUT) {
if(!security_allow_memory((u_int8_t *)image_buffer, image_buffer_size)) {
dprintf(DEBUG_INFO, "Permission denied\n");
return;
}
timeout = (usb_core_get_connection_speed() == CONNECTION_SPEED_HIGH) ? BULK_HS_TRNSFR_TIMEOUT : BULK_FS_TRNSFR_TIMEOUT;
usb_core_abort_endpoint(APPLE_USB_TRNSFR_EP_BULK_OUT);
usb_core_abort_endpoint(APPLE_USB_TRNSFR_EP_BULK_IN);
// Queue BULK IN request to upload data to host
usb_core_do_transfer(APPLE_USB_TRNSFR_EP_BULK_IN, image_buffer, image_buffer_size, bulk_in_callback);
// Keep an active BULK OUT request so that host can communcate failure at any time or communicate success at the end.
// There is no timeout for this request
usb_core_do_transfer(APPLE_USB_TRNSFR_EP_BULK_OUT, bulk_upload_status_buffer, ERR_PACKET_LEN, bulk_upload_status_callback);
}
#endif // WITH_BULK_UPLOAD
callout_enqueue(&trnsfr_callout, timeout, handle_trnsfr_callout, NULL);
}
u_int32_t usb_transfer_start()
{
print("starting\n");
while(!trnsfr_done) event_wait(&trnsfr_event);
#if DEBUG_BUILD
dprintf(DEBUG_SPEW, "transfer complete, status=%d\n", completion_status);
#else
dprintf(DEBUG_INFO, "transfer complete, status=%d\n", completion_status);
#endif
return completion_status;
}
static void deactivate_interface(void)
{
usb_core_deactivate_endpoint(APPLE_USB_TRNSFR_EP_BULK_OUT);
#if WITH_BULK_UPLOAD
usb_core_deactivate_endpoint(APPLE_USB_TRNSFR_EP_BULK_IN);
#endif
}
static void activate_interface(void)
{
int mps;
mps = (usb_core_get_connection_speed() == CONNECTION_SPEED_HIGH) ? HS_BULK_EP_MAX_PACKET_SIZE : FS_EP_MAX_PACKET_SIZE;
usb_core_activate_endpoint(APPLE_USB_TRNSFR_EP_BULK_OUT, USB_ENDPOINT_BULK, mps, 0);
#if WITH_BULK_UPLOAD
usb_core_activate_endpoint(APPLE_USB_TRNSFR_EP_BULK_IN, USB_ENDPOINT_BULK, mps, 0);
#endif
}
static void handle_trnsfr_callout(struct callout *co, void *args)
{
print("\n");
transfer_failed();
}
#if WITH_RECOVERY_MODE
static int handle_vendor_request(struct usb_device_request *request)
{
int ret;
ret = -1;
print("req: %d\n", request->wValue);
if(request->wValue == PR_RESET_REQUEST) {
PROFILE_1('UHVR');
usb_transfer_prepare(USB_TRANSFER_TYPE_BULK_GET, (void *)DEFAULT_LOAD_ADDRESS, DEFAULT_RAMDISK_SIZE);
ret = 0;
}
return ret;
}
#endif // WITH_RECOVERY_MODE
static void transfer_failed()
{
print("\n");
callout_dequeue(&trnsfr_callout);
completion_status = -1;
#if WITH_ENV
env_set_uint("filesize", 0, 0);
#endif // WITH_ENV
trnsfr_done = true;
event_signal(&trnsfr_event);
}
static void bulk_transfer_callback(struct usb_device_io_request *io_request)
{
print("status: %d, count: %d\n", io_request->status, io_request->return_count);
if(io_request->status != USB_IO_SUCCESS) {
transfer_failed();
return;
}
// special case, Error packet handling.
// this length and pattern should not appear in
// normal case, if someone will hit this often
// will make a change.
if(io_request->return_count == ERR_PACKET_LEN) {
u_int8_t *buf = (u_int8_t *)image_buffer;
if((buf[0] == ERR_PKT_START) && (buf[3] == ERR_PKT_END)) {
switch(buf[2])
{
case ERR_FILE_UNEXPECTED_ERROR:
dprintf(DEBUG_CRITICAL, "Unexpected error, exiting\n");
break;
case ERR_FILE_NOT_FOUND:
dprintf(DEBUG_CRITICAL, "File not found or could not be accessed, exiting\n");
break;
case ERR_FILE_READ_ERROR:
dprintf(DEBUG_CRITICAL, "File read error, exiting\n");
break;
case ERR_PFILE_NOT_IM4P:
dprintf(DEBUG_CRITICAL, "Not an im4p file, exiting\n");
break;
case ERR_PFILE_CREATE_FAILED:
dprintf(DEBUG_CRITICAL, "Could not personalize file, exiting\n");
break;
case ERR_PFILE_READ_ERROR:
dprintf(DEBUG_CRITICAL, "Error reading personalized file, exiting\n");
break;
case ERR_FILE_UNKNOWN_ERROR:
default:
dprintf(DEBUG_CRITICAL, "Unknown error - %d, exiting\n", buf[2]);
break;
}
transfer_failed();
return;
}
}
#if WITH_ENV
env_set_uint("filesize", io_request->return_count, 0);
#endif // WITH_ENV
completion_status = io_request->return_count;
callout_dequeue(&trnsfr_callout);
trnsfr_done = true;
event_signal(&trnsfr_event);
}
#ifdef WITH_BULK_UPLOAD
static void bulk_in_callback(struct usb_device_io_request *io_request)
{
int mps;
int amount;
amount = io_request->return_count;
print("status: %d, count: %d\n", io_request->status, amount);
if(io_request->status == USB_IO_SUCCESS) {
completion_status = amount;
mps = (usb_core_get_connection_speed() == CONNECTION_SPEED_HIGH) ? HS_BULK_EP_MAX_PACKET_SIZE : FS_EP_MAX_PACKET_SIZE;
if((amount > 0) && ((amount & (mps - 1)) == 0))
{
// Send an empty packet to indicate end of transfer
usb_core_do_transfer(APPLE_USB_TRNSFR_EP_BULK_IN, bulk_in_zlp_buffer, 0, NULL);
}
// Restart the timer waiting for the status packet
callout_reset(&trnsfr_callout, 0);
}
else {
completion_status = -1;
}
}
#endif // WITH_BULK_UPLOAD
#ifdef WITH_BULK_UPLOAD
static void bulk_upload_status_callback(struct usb_device_io_request *io_request)
{
bool upload_success = false;
print("status: %d, count: %d\n", io_request->status, io_request->return_count);
if(io_request->status == USB_IO_SUCCESS) {
if(io_request->return_count == ERR_PACKET_LEN) {
if((bulk_upload_status_buffer[0] == ERR_PKT_START) && (bulk_upload_status_buffer[3] == ERR_PKT_END)) {
switch(bulk_upload_status_buffer[2]) {
case ERR_FILE_SUCCESS:
upload_success = true;
break;
case ERR_FILE_UNEXPECTED_ERROR:
printf("Unexpected error, exiting\n");
break;
case ERR_FILE_NOT_FOUND:
printf("File could not be opened, exiting\n");
break;
case ERR_FILE_WRITE_ERROR:
printf("File write error, exiting\n");
break;
case ERR_FILE_UNKNOWN_ERROR:
default:
printf("Unknown error - %d, exiting\n", bulk_upload_status_buffer[2]);
break;
}
}
else {
dprintf(DEBUG_INFO, "Invalid format for status packet\n");
}
}
else {
dprintf(DEBUG_INFO, "Invalid status packet length - %d\n", io_request->return_count);
}
}
else {
dprintf(DEBUG_INFO, "Status packet failed %x\n", io_request->status);
}
if(!upload_success) {
usb_core_abort_endpoint(APPLE_USB_TRNSFR_EP_BULK_IN);
}
trnsfr_done = true;
callout_dequeue(&trnsfr_callout);
event_signal(&trnsfr_event);
}
#endif // WITH_BULK_UPLOAD