diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..192befb --- /dev/null +++ b/.clang-format @@ -0,0 +1,105 @@ +--- +Language: Cpp +# Cpp, C, ObjC, Java, JavaScript, TypeScript, Proto, TableGen, TextProto +BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +TabWidth: 4 +UseTab: Never +... \ No newline at end of file diff --git a/dwc2-overlay.dts b/dwc2-overlay.dts index e56871f..9b32178 100644 --- a/dwc2-overlay.dts +++ b/dwc2-overlay.dts @@ -13,7 +13,7 @@ dr_mode = "otg"; g-np-tx-fifo-size = <32>; g-rx-fifo-size = <558>; - g-tx-fifo-size = <3072 512 256>; + g-tx-fifo-size = <128 128 256 256 512 768 768>; status = "okay"; }; }; diff --git a/hvperf.c b/hvperf.c index e9c9330..bb38ecf 100644 --- a/hvperf.c +++ b/hvperf.c @@ -5,7 +5,7 @@ /* * this is an example pthreaded USER MODE driver implementing a - * USB Gadget/Device with simple bulk in/out functionality. + * USB Gadget/Device with simple bulk source/sink functionality. * you could implement pda sync software this way, or some usb class * protocols (printers, test-and-measurement equipment, and so on). * @@ -19,7 +19,7 @@ /*!********************************************************************* * hvperf.c - * Version : V1.0.1 + * Version : V1.0.2 * Author : usiop-vault * *********************************************************************!*/ @@ -59,9 +59,9 @@ static int pattern; * DO NOT REUSE THESE IDs with any protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ -#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ -#define DRIVER_ISO_PRODUCT_NUM 0xa4a3 /* user mode iso out/src */ -#define DRIVER_PRODUCT_NUM 0xa4a4 /* user mode out/src */ +#define DRIVER_VENDOR_NUM 0x1004 /* NetChip */ +#define DRIVER_ISO_PRODUCT_NUM 0x61a1 /* user mode iso out/src */ +#define DRIVER_PRODUCT_NUM 0x61a0 /* user mode out/src */ /* NOTE: these IDs don't imply endpoint numbering; host side drivers * should use endpoint descriptors, or perhaps bcdDevice, to configure @@ -76,7 +76,9 @@ static int pattern; #define STRINGID_PRODUCT 2 #define STRINGID_SERIAL 3 #define STRINGID_CONFIG 4 -#define STRINGID_INTERFACE 5 +#define STRINGID_INTERFACE0 5 +#define STRINGID_INTERFACE1_ALTERNATE_SETTING_0 6 +#define STRINGID_INTERFACE1_ALTERNATE_SETTING_1 7 static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, @@ -95,62 +97,48 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -#define MAX_USB_POWER 1 +#define MAX_USB_POWER 50 -#define CONFIG_VALUE 3 +#define CONFIG_VALUE 1 -static const struct usb_config_descriptor config = { - .bLength = sizeof config, - .bDescriptorType = USB_DT_CONFIG, - - /* must compute wTotalLength ... */ - .bNumInterfaces = 1, - .bConfigurationValue = CONFIG_VALUE, - .iConfiguration = STRINGID_CONFIG, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = (MAX_USB_POWER + 1) / 2, -}; - -static struct usb_interface_descriptor in_out_intf = { - .bLength = sizeof in_out_intf, +static struct usb_interface_descriptor in_out_intf0 = { + .bLength = sizeof in_out_intf0, .bDescriptorType = USB_DT_INTERFACE, - + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .iInterface = STRINGID_INTERFACE, + .iInterface = STRINGID_INTERFACE0, }; -// Alternate Setting 0 -static struct usb_interface_descriptor in_out_intf_alt0 = { - .bLength = sizeof in_out_intf_alt0, +// Alternate Setting 0 for wMaxPacketSize : 1024 +static struct usb_interface_descriptor in_out_intf1_alt0 = { + .bLength = sizeof in_out_intf1_alt0, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, + .bInterfaceNumber = 1, .bAlternateSetting = 0, - .bNumEndpoints = 2, + .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .iInterface = STRINGID_INTERFACE, + .iInterface = STRINGID_INTERFACE1_ALTERNATE_SETTING_0, }; -// Alternate Setting 1 -static struct usb_interface_descriptor in_out_intf_alt1 = { - .bLength = sizeof in_out_intf_alt1, +// Alternate Setting 1 for wMaxPacketSize : 5120 +static struct usb_interface_descriptor in_out_intf1_alt1 = { + .bLength = sizeof in_out_intf1_alt1, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, + .bInterfaceNumber = 1, .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .iInterface = STRINGID_INTERFACE, + .iInterface = STRINGID_INTERFACE1_ALTERNATE_SETTING_0, }; -/* some devices can handle other status packet sizes */ -#define STATUS_MAXPACKET 8 -#define LOG2_STATUS_POLL_MSEC 3 - /* High speed configurations are used only in addition to a full-speed * ones ... since all high speed devices support full speed configs. * Of course, not all hardware supports high speed configurations. */ -static struct usb_endpoint_descriptor hs_in_desc = { +static struct usb_endpoint_descriptor hs_in0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -158,7 +146,7 @@ static struct usb_endpoint_descriptor hs_in_desc = { .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_endpoint_descriptor hs_out_desc = { +static struct usb_endpoint_descriptor hs_out0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -167,21 +155,75 @@ static struct usb_endpoint_descriptor hs_out_desc = { .bInterval = 1, }; -static struct usb_endpoint_descriptor hs_status_desc = { +static struct usb_endpoint_descriptor hs_in1_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET), - .bInterval = LOG2_STATUS_POLL_MSEC + 3, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static const struct usb_interface_descriptor *hs_intfs[] = { + &in_out_intf0, + &in_out_intf1_alt0, }; static const struct usb_endpoint_descriptor *hs_eps[] = { - &hs_in_desc, - //&hs_out_desc, - //&hs_status_desc, + &hs_in0_desc, + &hs_out0_desc, + &hs_in1_desc, +}; + +static const struct usb_endpoint_descriptor *hs_in_eps[] = { + &hs_in0_desc, + &hs_in1_desc, +}; + +static const struct usb_endpoint_descriptor *hs_out_eps[] = { + &hs_out0_desc, +}; + +static const struct usb_config_descriptor config = { + .bLength = sizeof config, + .bDescriptorType = USB_DT_CONFIG, + + /* must compute wTotalLength ... */ + .bNumInterfaces = 2, + .wTotalLength = sizeof(config) + sizeof(in_out_intf0) + sizeof(in_out_intf1_alt0) + + sizeof(hs_in0_desc) + sizeof(hs_out0_desc) + sizeof(hs_in1_desc), + .bConfigurationValue = CONFIG_VALUE, + .iConfiguration = STRINGID_CONFIG, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = (MAX_USB_POWER + 1) / 2, }; +// struct usb_descriptor_header { +// unsigned char bLength; +// unsigned char bDescriptorType; +// }; + +// static const struct usb_descriptor_header *descriptors[] = { +// (struct usb_descriptor_header *)&config, +// (struct usb_descriptor_header *)&in_out_intf0, +// (struct usb_descriptor_header *)&in_out_intf1_alt1, +// (struct usb_descriptor_header *)&hs_in0_desc, +// (struct usb_descriptor_header *)&hs_out0_desc, +// (struct usb_descriptor_header *)&hs_in1_desc, +// NULL, +// }; + +// void calculate_config_descriptor_length() { +// unsigned char total_length = 0; +// struct usb_descriptor_header **desc = descriptors; + +// while (*desc) { +// total_length += (*desc)->bLength; +// desc++; +// } + +// config.wTotalLength = total_length; +// } + /*-------------------------------------------------------------------------*/ static char serial[64]; @@ -189,11 +231,11 @@ static char serial[64]; static struct usb_string stringtab[] = { { STRINGID_MFGR, - "Licensed to VaultMicro", + "Licensed to Code, LLC", }, { STRINGID_PRODUCT, - "hvperf", + "My Source/Sink Product", }, { STRINGID_SERIAL, @@ -204,8 +246,16 @@ static struct usb_string stringtab[] = { "The Configuration", }, { - STRINGID_INTERFACE, - "hvperf", + STRINGID_INTERFACE0, + "intf0", + }, + { + STRINGID_INTERFACE1_ALTERNATE_SETTING_0, + "intf1altf0", + }, + { + STRINGID_INTERFACE1_ALTERNATE_SETTING_1, + "intf1altf1", }, }; @@ -222,7 +272,7 @@ static struct usb_gadget_strings strings = { static int HIGHSPEED; static char *DEVNAME; -static char *EP_IN_NAME, *EP_OUT_NAME, *EP_STATUS_NAME; +static char *EP_IN0_NAME, *EP_IN1_NAME, *EP_OUT0_NAME; /* gadgetfs currently has no chunking (or O_DIRECT/zerocopy) support * to turn big requests into lots of smaller ones; so this is "small". @@ -233,31 +283,6 @@ static enum usb_device_speed current_speed; static inline int min(unsigned a, unsigned b) { return (a < b) ? a : b; } -static int autoconfig() { - struct stat statb; - if (stat(DEVNAME = "fe980000.usb", &statb) == 0) { - HIGHSPEED = 1; - device_desc.bcdDevice = __constant_cpu_to_le16(0x0107), - - hs_in_desc.bEndpointAddress = USB_DIR_IN | 1; - EP_IN_NAME = "ep1in"; - hs_out_desc.bEndpointAddress = USB_DIR_OUT | 1; - EP_OUT_NAME = "ep1out"; - - in_out_intf.bNumEndpoints = 3; - hs_status_desc.bEndpointAddress = USB_DIR_IN | 3; - EP_STATUS_NAME = "ep3"; - - /* Atmel AT91 processors, full speed only */ - } else { - DEVNAME = 0; - return -ENODEV; - } - return 0; -} - -#ifdef AIO - static int iso; static int interval; static unsigned iosize; @@ -266,7 +291,7 @@ static unsigned bufsize = USB_BUFSIZE; /* This is almost the only place where usb needs to know whether we're * driving an isochronous stream or a bulk one. */ -static int iso_autoconfig() { +static int autoconfig() { struct stat statb; /* ISO endpoints "must not be part of a default interface setting". @@ -277,25 +302,34 @@ static int iso_autoconfig() { */ device_desc.idProduct = __constant_cpu_to_le16(DRIVER_ISO_PRODUCT_NUM); + /* NetChip 2280 PCI device or dummy_hcd, high/full speed */ if (stat(DEVNAME = "fe980000.usb", &statb) == 0) { - unsigned bInterval; - - bInterval = interval; + unsigned bInterval, wMaxPacketSize; HIGHSPEED = 1; device_desc.bcdDevice = __constant_cpu_to_le16(0x0103); unsigned short wMaxPacketSize = (unsigned short)bufsize; - fprintf(stderr, "\n\n%04x\n\n", wMaxPacketSize); + hs_in0_desc.bEndpointAddress = USB_DIR_IN | 1; + hs_out0_desc.bEndpointAddress = USB_DIR_OUT | 1; + hs_in1_desc.bEndpointAddress = USB_DIR_IN | 2; + + EP_IN0_NAME = "ep1in"; + EP_OUT0_NAME = "ep1out"; + EP_IN1_NAME = "ep2in"; + + hs_in0_desc.bmAttributes = USB_ENDPOINT_XFER_BULK; + hs_out0_desc.bmAttributes = USB_ENDPOINT_XFER_BULK; + hs_in1_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; - hs_in_desc.bEndpointAddress = USB_DIR_IN | 1; - hs_in_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; - hs_in_desc.wMaxPacketSize = wMaxPacketSize; - hs_in_desc.bInterval = bInterval; - EP_IN_NAME = "ep1in"; + hs_in1_desc.wMaxPacketSize = 5120; - in_out_intf.bNumEndpoints = 1; + hs_in0_desc.bInterval = hs_in1_desc.bInterval = bInterval; + + in_out_intf0.bNumEndpoints = 2; + in_out_intf1_alt0.bNumEndpoints = 1; + in_out_intf1_alt1.bNumEndpoints = 1; /* Atmel AT91 processors, full speed only */ } else { @@ -304,27 +338,23 @@ static int iso_autoconfig() { } if (verbose) { if (HIGHSPEED) - fprintf(stderr, "iso hs wMaxPacket %04x bInterval %02x\n", - __le16_to_cpu(hs_in_desc.wMaxPacketSize), hs_in_desc.bInterval); + fprintf(stderr, "iso hs wMaxPacket 0x%04x bInterval 0x%02x\n", + __le16_to_cpu(hs_in1_desc.wMaxPacketSize), hs_in1_desc.bInterval); } return 0; } -#else -#define iso 0 -#endif /* AIO */ - /*-------------------------------------------------------------------------*/ -/* full duplex data, with at least three threads: ep0, out, and in */ +/* full duplex data, with at least three threads: ep0, sink, and source */ static pthread_t ep0; -static pthread_t in; -static int in_fd = -1; +static pthread_t source; +static int source_fd = -1; -static pthread_t out; -static int out_fd = -1; +static pthread_t sink; +static int sink_fd = -1; // FIXME no status i/o yet @@ -358,9 +388,10 @@ static void close_fd(void *fd_ptr) { /* you should be able to open and configure endpoints * whether or not the host is connected */ -static int ep_config(char *name, const char *label, struct usb_endpoint_descriptor *hs) { + +static int ep_config(char *name, const char *label, const struct usb_endpoint_descriptor **hs) { int fd, status; - char buf[USB_BUFSIZE]; + char buf[USB_BUFSIZE], *cp = &buf[0]; /* open and initialize with endpoint descriptor(s) */ fd = open(name, O_RDWR); @@ -371,10 +402,25 @@ static int ep_config(char *name, const char *label, struct usb_endpoint_descript } /* one (fs or ls) or two (fs + hs) sets of config descriptors */ - *(__u32 *)buf = 1; /* tag for this format */ - if (HIGHSPEED) - memcpy(buf + 4 + USB_DT_ENDPOINT_SIZE, hs, USB_DT_ENDPOINT_SIZE); - status = write(fd, buf, 4 + USB_DT_ENDPOINT_SIZE + (HIGHSPEED ? USB_DT_ENDPOINT_SIZE : 0)); + + *(__u32 *)cp = 1; /* tag for this format */ + cp += 4; + + memcpy(cp, hs[0], USB_DT_ENDPOINT_SIZE); // compensate full speed + cp += USB_DT_ENDPOINT_SIZE; + + int i; + int num_endpoints = sizeof(hs_eps) / sizeof(hs_eps[0]); + + memcpy(cp, hs[1], USB_DT_ENDPOINT_SIZE); + cp += USB_DT_ENDPOINT_SIZE; + + // for (i = 0; i < num_endpoints; i++) { + // memcpy(cp, hs[i], USB_DT_ENDPOINT_SIZE); + // cp += USB_DT_ENDPOINT_SIZE; + // } + + status = write(fd, buf, cp - buf); if (status < 0) { status = -errno; fprintf(stderr, "%s config %s error %d (%s)\n", label, name, errno, strerror(errno)); @@ -389,8 +435,9 @@ static int ep_config(char *name, const char *label, struct usb_endpoint_descript return fd; } -#define in_open(name) ep_config(name, __FUNCTION__, &hs_in_desc) -#define out_open(name) ep_config(name, __FUNCTION__, &hs_out_desc) + +#define in_open(name) ep_config(name, __FUNCTION__, hs_in_eps) +#define out_open(name) ep_config(name, __FUNCTION__, hs_out_eps) static unsigned long fill_in_buf(void *buf, unsigned long nbytes) { #ifdef DO_PIPE @@ -464,17 +511,17 @@ static int empty_out_buf(void *buf, unsigned long nbytes) { return len; } -static void *simple_in_thread(void *param) { +static void *simple_source_thread(void *param) { char *name = (char *)param; int status; char buf[USB_BUFSIZE]; - status = in_open(name); + status = source_open(name); if (status < 0) return 0; - in_fd = status; + source_fd = status; - pthread_cleanup_push(close_fd, &in_fd); + pthread_cleanup_push(close_fd, &source_fd); do { unsigned long len; @@ -485,7 +532,7 @@ static void *simple_in_thread(void *param) { len = fill_in_buf(buf, sizeof buf); if (len > 0) - status = write(in_fd, buf, len); + status = write(source_fd, buf, len); else status = 0; @@ -502,25 +549,25 @@ static void *simple_in_thread(void *param) { return 0; } -static void *simple_out_thread(void *param) { +static void *simple_sink_thread(void *param) { char *name = (char *)param; int status; char buf[USB_BUFSIZE]; - status = out_open(name); + status = sink_open(name); if (status < 0) return 0; - out_fd = status; + sink_fd = status; /* synchronous reads of endless streams of data */ - pthread_cleanup_push(close_fd, &out_fd); + pthread_cleanup_push(close_fd, &sink_fd); do { /* original LinuxThreads cancelation didn't work right * so test for it explicitly. */ pthread_testcancel(); errno = 0; - status = read(out_fd, buf, sizeof buf); + status = read(sink_fd, buf, sizeof buf); if (status < 0) break; @@ -538,8 +585,8 @@ static void *simple_out_thread(void *param) { return 0; } -static void *(*in_thread)(void *); -static void *(*out_thread)(void *); +static void *(*source_thread)(void *); +static void *(*sink_thread)(void *); #ifdef AIO @@ -626,11 +673,11 @@ static void *aio_in_thread(void *param) { struct iocb *queue, *iocb; unsigned i; - status = in_open(name); + status = source_open(name); if (status < 0) return 0; - in_fd = status; - pthread_cleanup_push(close_fd, &in_fd); + source_fd = status; + pthread_cleanup_push(close_fd, &source_fd); /* initialize i/o queue */ status = io_setup(aio_in, &ctx); @@ -654,7 +701,7 @@ static void *aio_in_thread(void *param) { } /* host receives the data we're writing */ - io_prep_pwrite(iocb, in_fd, buf, fill_in_buf(buf, iosize), 0); + io_prep_pwrite(iocb, source_fd, buf, fill_in_buf(buf, iosize), 0); io_set_callback(iocb, in_complete); iocb->key = USB_DIR_IN; @@ -717,11 +764,11 @@ static void *aio_out_thread(void *param) { struct iocb *queue, *iocb; unsigned i; - status = out_open(name); + status = sink_open(name); if (status < 0) return 0; - out_fd = status; - pthread_cleanup_push(close_fd, &out_fd); + sink_fd = status; + pthread_cleanup_push(close_fd, &sink_fd); /* initialize i/o queue */ status = io_setup(aio_out, &ctx); @@ -745,7 +792,7 @@ static void *aio_out_thread(void *param) { } /* data can be processed in out_complete() */ - io_prep_pread(iocb, out_fd, buf, iosize, 0); + io_prep_pread(iocb, sink_fd, buf, iosize, 0); io_set_callback(iocb, out_complete); iocb->key = USB_DIR_OUT; @@ -790,12 +837,11 @@ static void start_io() { break; case USB_SPEED_HIGH: /* for iso, we updated bufsize earlier */ - if (hs_in_desc.wMaxPacketSize > 1024) { + if (hs_in1_desc.wMaxPacketSize > 1024) { iosize = 3072; } else { - iosize = hs_in_desc.wMaxPacketSize; + iosize = hs_in1_desc.wMaxPacketSize; } - iosize = 3072; break; default: fprintf(stderr, "bogus link speed %d\n", current_speed); @@ -815,7 +861,7 @@ static void start_io() { * why? this clearly doesn't ... */ - if (pthread_create(&in, 0, in_thread, (void *)EP_IN_NAME) != 0) { + if (pthread_create(&in, 0, in_thread, (void *)EP_IN1_NAME) != 0) { perror("can't create in thread"); goto cleanup; } @@ -836,18 +882,18 @@ static void start_io() { } static void stop_io() { - if (!pthread_equal(in, ep0)) { - pthread_cancel(in); - if (pthread_join(in, 0) != 0) - perror("can't join in thread"); - in = ep0; + if (!pthread_equal(source, ep0)) { + pthread_cancel(source); + if (pthread_join(source, 0) != 0) + perror("can't join source thread"); + source = ep0; } - if (!pthread_equal(out, ep0)) { - pthread_cancel(out); - if (pthread_join(out, 0) != 0) - perror("can't join out thread"); - out = ep0; + if (!pthread_equal(sink, ep0)) { + pthread_cancel(sink); + if (pthread_join(sink, 0) != 0) + perror("can't join sink thread"); + sink = ep0; } } @@ -855,34 +901,35 @@ static void stop_io() { static char *build_config(char *cp, const struct usb_endpoint_descriptor **ep) { struct usb_config_descriptor *c; - int i; + int i, j = 0, k; + int num_intf = sizeof(hs_intfs) / sizeof(hs_intfs[0]); c = (struct usb_config_descriptor *)cp; - memcpy(cp, &config, config.bLength); - cp += config.bLength; - memcpy(cp, &in_out_intf, in_out_intf.bLength); - cp += in_out_intf.bLength; + memcpy(cp, &config, sizeof config); + cp += sizeof config; - for (i = 0; i < in_out_intf.bNumEndpoints; i++) { - memcpy(cp, ep[i], USB_DT_ENDPOINT_SIZE); - cp += USB_DT_ENDPOINT_SIZE; + for (i = 0; i < num_intf; i++) { + memcpy(cp, hs_intfs[i], hs_intfs[i]->bLength); + cp += hs_intfs[i]->bLength; + + for (k = 0; k < hs_intfs[i]->bNumEndpoints; k++, j++) { + memcpy(cp, ep[j], USB_DT_ENDPOINT_SIZE); + cp += USB_DT_ENDPOINT_SIZE; + } } + c->wTotalLength = __cpu_to_le16(cp - (char *)c); return cp; } static int init_device(void) { + // todo : adjust buf size, bc the camera descriptor is more than 5k char buf[4096], *cp = &buf[0]; int fd; int status; -#ifdef AIO - if (iso) - status = iso_autoconfig(); - else -#endif - status = autoconfig(); + status = autoconfig(); if (status < 0) { fprintf(stderr, "?? don't recognize /dev/gadget %s device\n", iso ? "iso" : "bulk"); return status; @@ -897,14 +944,15 @@ static int init_device(void) { *(__u32 *)cp = 0; /* tag for this format */ cp += 4; - /* write full then high speed configs */ - if (HIGHSPEED) - cp = build_config(cp, hs_eps); + cp = build_config(cp, hs_eps); // compensate full_speed + cp = build_config(cp, hs_eps); /* and device descriptor at the end */ memcpy(cp, &device_desc, sizeof device_desc); cp += sizeof device_desc; + fprintf(stderr, "Buffer size: %ld\n", cp - buf); + status = write(fd, &buf[0], cp - &buf[0]); if (status < 0) { perror("write dev descriptors"); @@ -1014,7 +1062,7 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { status = write(fd, buf, length); if (status < 0) { if (errno == EIDRM) - fprintf(stderr, "GET_INTERFACE timeout %s\n", strerror(errno)); + fprintf(stderr, "GET_INTERFACE timeout\n"); else perror("write GET_INTERFACE data"); } else if (status != length) { @@ -1027,13 +1075,13 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { fprintf(stderr, "SET INTERFACE\n"); /* just reset toggle/halt for the interface's endpoints */ status = 0; - if (ioctl(in_fd, GADGETFS_CLEAR_HALT) < 0) { + if (ioctl(source_fd, GADGETFS_CLEAR_HALT) < 0) { status = errno; - perror("reset in fd"); + perror("reset source fd"); } - if (ioctl(out_fd, GADGETFS_CLEAR_HALT) < 0) { + if (ioctl(sink_fd, GADGETFS_CLEAR_HALT) < 0) { status = errno; - perror("reset out fd"); + perror("reset sink fd"); } /* FIXME eventually reset the status endpoint too */ if (status) @@ -1098,7 +1146,7 @@ static void *ep0_thread(void *param) { time_t now, last; struct pollfd ep0_poll; - in = out = ep0 = pthread_self(); + source = sink = ep0 = pthread_self(); pthread_cleanup_push(close_fd, param); /* REVISIT signal handling ... normally one pthread should @@ -1223,8 +1271,8 @@ int main(int argc, char **argv) { serial[i++] = c; } - in_thread = simple_in_thread; - out_thread = simple_out_thread; + source_thread = simple_source_thread; + sink_thread = simple_sink_thread; while ((c = getopt(argc, argv, "I:a:i:o:p:r:s:v")) != EOF) { switch (c) { @@ -1236,21 +1284,21 @@ int main(int argc, char **argv) { * ignored if high bandwidth could kick in */ interval = atoi(optarg); - in_thread = aio_in_thread; - out_thread = aio_out_thread; + source_thread = aio_in_thread; + sink_thread = aio_out_thread; continue; case 'a': /* aio IN/OUT qlen */ aio_in = aio_out = atoi(optarg); - in_thread = aio_in_thread; - out_thread = aio_out_thread; + source_thread = aio_in_thread; + sink_thread = aio_out_thread; continue; case 'i': /* aio IN qlen */ aio_in = atoi(optarg); - in_thread = aio_in_thread; + source_thread = aio_in_thread; continue; case 'o': /* aio OUT qlen */ aio_out = atoi(optarg); - out_thread = aio_out_thread; + sink_thread = aio_out_thread; continue; case 's': /* iso buffer size */ /* for iso, "-s 1025" and higher is high bandwidth */ diff --git a/usb.c b/usb.c index 5296be8..e1db9eb 100644 --- a/usb.c +++ b/usb.c @@ -5,7 +5,7 @@ /* * this is an example pthreaded USER MODE driver implementing a - * USB Gadget/Device with simple bulk in/out functionality. + * USB Gadget/Device with simple bulk source/sink functionality. * you could implement pda sync software this way, or some usb class * protocols (printers, test-and-measurement equipment, and so on). * @@ -19,23 +19,23 @@ #include #include +#include +#include #include #include #include -#include #include -#include +#include +#include #include #include -#include -#include #include #include -#include #include +#include #ifdef AIO /* this aio code works with libaio-0.3.106 */ @@ -53,8 +53,8 @@ static int pattern; * Instead: allocate your own, using normal USB-IF procedures. */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ -#define DRIVER_ISO_PRODUCT_NUM 0xa4a3 /* user mode iso out/src */ -#define DRIVER_PRODUCT_NUM 0xa4a4 /* user mode out/src */ +#define DRIVER_ISO_PRODUCT_NUM 0xa4a3 /* user mode iso sink/src */ +#define DRIVER_PRODUCT_NUM 0xa4a4 /* user mode sink/src */ /* NOTE: these IDs don't imply endpoint numbering; host side drivers * should use endpoint descriptors, or perhaps bcdDevice, to configure @@ -71,86 +71,92 @@ static int pattern; #define STRINGID_CONFIG 4 #define STRINGID_INTERFACE 5 -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - // .bMaxPacketSize0 ... set by gadgetfs - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), - .iManufacturer = STRINGID_MFGR, - .iProduct = STRINGID_PRODUCT, - .iSerialNumber = STRINGID_SERIAL, - .bNumConfigurations = 1, +static struct usb_device_descriptor + device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + // .bMaxPacketSize0 ... set by gadgetfs + .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), + .iManufacturer = STRINGID_MFGR, + .iProduct = STRINGID_PRODUCT, + .iSerialNumber = STRINGID_SERIAL, + .bNumConfigurations = 1, }; #define MAX_USB_POWER 1 #define CONFIG_VALUE 3 -static const struct usb_config_descriptor config = { - .bLength = sizeof config, - .bDescriptorType = USB_DT_CONFIG, - - /* must compute wTotalLength ... */ - .bNumInterfaces = 1, - .bConfigurationValue = CONFIG_VALUE, - .iConfiguration = STRINGID_CONFIG, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = (MAX_USB_POWER + 1) / 2, +static const struct usb_config_descriptor + config = { + .bLength = sizeof config, + .bDescriptorType = USB_DT_CONFIG, + + /* must compute wTotalLength ... */ + .bNumInterfaces = 1, + .bConfigurationValue = CONFIG_VALUE, + .iConfiguration = STRINGID_CONFIG, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = (MAX_USB_POWER + 1) / 2, }; -static struct usb_interface_descriptor in_out_intf = { - .bLength = sizeof in_out_intf, - .bDescriptorType = USB_DT_INTERFACE, +static struct usb_interface_descriptor + source_sink_intf = { + .bLength = sizeof source_sink_intf, + .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .iInterface = STRINGID_INTERFACE, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = STRINGID_INTERFACE, }; /* Full speed configurations are used for full-speed only devices as * well as dual-speed ones (the only kind with high speed support). */ -static struct usb_endpoint_descriptor fs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, +static struct usb_endpoint_descriptor + fs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* NOTE some controllers may need FS bulk max packet size - * to be smaller. it would be a chip-specific option. - */ - .wMaxPacketSize = __constant_cpu_to_le16(64), + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* NOTE some controllers may need FS bulk max packet size + * to be smaller. it would be a chip-specific option. + */ + .wMaxPacketSize = __constant_cpu_to_le16(64), }; -static struct usb_endpoint_descriptor fs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, +static struct usb_endpoint_descriptor + fs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(64), }; /* some devices can handle other status packet sizes */ #define STATUS_MAXPACKET 8 #define LOG2_STATUS_POLL_MSEC 3 -static struct usb_endpoint_descriptor fs_status_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, +static struct usb_endpoint_descriptor + fs_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET), - .bInterval = (1 << LOG2_STATUS_POLL_MSEC), + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET), + .bInterval = (1 << LOG2_STATUS_POLL_MSEC), }; static const struct usb_endpoint_descriptor *fs_eps[3] = { - &fs_in_desc, - &fs_out_desc, + &fs_source_desc, + &fs_sink_desc, &fs_status_desc, }; @@ -159,36 +165,39 @@ static const struct usb_endpoint_descriptor *fs_eps[3] = { * Of course, not all hardware supports high speed configurations. */ -static struct usb_endpoint_descriptor hs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, +static struct usb_endpoint_descriptor + hs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_endpoint_descriptor hs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, +static struct usb_endpoint_descriptor + hs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), - .bInterval = 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), + .bInterval = 1, }; -static struct usb_endpoint_descriptor hs_status_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, +static struct usb_endpoint_descriptor + hs_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET), - .bInterval = LOG2_STATUS_POLL_MSEC + 3, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET), + .bInterval = LOG2_STATUS_POLL_MSEC + 3, }; static const struct usb_endpoint_descriptor *hs_eps[] = { - &hs_in_desc, - //&hs_out_desc, - //&hs_status_desc, + &hs_source_desc, + &hs_sink_desc, + &hs_status_desc, }; /*-------------------------------------------------------------------------*/ @@ -198,11 +207,11 @@ static char serial[64]; static struct usb_string stringtab[] = { { STRINGID_MFGR, - "Licensed to VaultMicro", + "Licensed to Code, LLC", }, { STRINGID_PRODUCT, - "hvperf", + "My Source/Sink Product", }, { STRINGID_SERIAL, @@ -214,7 +223,7 @@ static struct usb_string stringtab[] = { }, { STRINGID_INTERFACE, - "hvperf", + "Source/Sink", }, }; @@ -240,25 +249,193 @@ static char *EP_IN_NAME, *EP_OUT_NAME, *EP_STATUS_NAME; static enum usb_device_speed current_speed; -static inline int min(unsigned a, unsigned b) { return (a < b) ? a : b; } +static inline int min(unsigned a, unsigned b) +{ + return (a < b) ? a : b; +} -static int autoconfig() { +static int autoconfig() +{ struct stat statb; - if (stat(DEVNAME = "fe980000.usb", &statb) == 0) { + + /* NetChip 2280 PCI device or dummy_hcd, high/full speed */ + if (stat(DEVNAME = "net2280", &statb) == 0 || + stat(DEVNAME = "dummy_udc", &statb) == 0) + { + HIGHSPEED = 1; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0100), + + fs_source_desc.bEndpointAddress = hs_source_desc.bEndpointAddress = USB_DIR_IN | 7; + EP_IN_NAME = "ep-a"; + fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress = USB_DIR_OUT | 3; + EP_OUT_NAME = "ep-b"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = hs_status_desc.bEndpointAddress = USB_DIR_IN | 11; + EP_STATUS_NAME = "ep-f"; + + /* Intel PXA 2xx processor, full speed only */ + } + else if (stat(DEVNAME = "pxa2xx_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0101), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 6; + EP_IN_NAME = "ep6in-bulk"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 7; + EP_OUT_NAME = "ep7out-bulk"; + + /* using bulk for this since the pxa interrupt endpoints + * always use the no-toggle scheme (discouraged). + */ + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 11; + EP_STATUS_NAME = "ep11in-bulk"; +#if 0 + /* AMD au1x00 processor, full speed only */ + } else if (stat (DEVNAME = "au1x00_udc", &statb) == 0) { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0102), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 2; + EP_IN_NAME = "ep2in"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 4; + EP_OUT_NAME = "ep4out"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3in"; + + /* Intel SA-1100 processor, full speed only */ + } else if (stat (DEVNAME = "sa1100", &statb) == 0) { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0103), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 2; + EP_IN_NAME = "ep2in-bulk"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1; + EP_OUT_NAME = "ep1out-bulk"; + + source_sink_intf.bNumEndpoints = 2; + EP_STATUS_NAME = 0; +#endif + + /* Toshiba TC86c001 PCI device, full speed only */ + } + else if (stat(DEVNAME = "goku_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0104), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 2; + EP_IN_NAME = "ep2-bulk"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1; + EP_OUT_NAME = "ep1-bulk"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3-bulk"; + + /* Renesas SH77xx processors, full speed only */ + } + else if (stat(DEVNAME = "sh_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0105), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 2; + EP_IN_NAME = "ep2in-bulk"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1; + EP_OUT_NAME = "ep1out-bulk"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3in-bulk"; + + /* OMAP 1610 and newer devices, full speed only, fifo mode 0 or 3 */ + } + else if (stat(DEVNAME = "omap_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0106), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 1; + EP_IN_NAME = "ep1in-bulk"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2; + EP_OUT_NAME = "ep2out-bulk"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3in-int"; + + /* Something based on Mentor USB Highspeed Dual-Role Controller */ + //} else if (stat (DEVNAME = "musb_hdrc", &statb) == 0) { + } + else if (stat(DEVNAME = "fe980000.usb", &statb) == 0) + { HIGHSPEED = 1; device_desc.bcdDevice = __constant_cpu_to_le16(0x0107), - fs_in_desc.bEndpointAddress = hs_in_desc.bEndpointAddress = USB_DIR_IN | 1; + fs_source_desc.bEndpointAddress = hs_source_desc.bEndpointAddress = USB_DIR_IN | 1; EP_IN_NAME = "ep1in"; - fs_out_desc.bEndpointAddress = hs_out_desc.bEndpointAddress = USB_DIR_OUT | 1; + fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1; EP_OUT_NAME = "ep1out"; - in_out_intf.bNumEndpoints = 3; + source_sink_intf.bNumEndpoints = 3; fs_status_desc.bEndpointAddress = hs_status_desc.bEndpointAddress = USB_DIR_IN | 3; EP_STATUS_NAME = "ep3"; /* Atmel AT91 processors, full speed only */ - } else { + } + else if (stat(DEVNAME = "at91_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0106), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 1; + EP_IN_NAME = "ep1"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2; + EP_OUT_NAME = "ep2"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3-int"; + + /* Sharp LH740x processors, full speed only */ + } + else if (stat(DEVNAME = "lh740x_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0106), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 1; + EP_IN_NAME = "ep1in-bulk"; + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2; + EP_OUT_NAME = "ep2out-bulk"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3in-int"; + + /* Atmel AT32AP700x processors, high/full speed */ + } + else if (stat(DEVNAME = "atmel_usba_udc", &statb) == 0) + { + HIGHSPEED = 1; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0108); + + fs_source_desc.bEndpointAddress = hs_source_desc.bEndpointAddress = USB_DIR_IN | 1; + EP_IN_NAME = "ep1in-bulk"; + fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2; + EP_OUT_NAME = "ep2out-bulk"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = hs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3in-int"; + } + else + { DEVNAME = 0; return -ENODEV; } @@ -275,7 +452,8 @@ static unsigned bufsize = USB_BUFSIZE; /* This is almost the only place where usb needs to know whether we're * driving an isochronous stream or a bulk one. */ -static int iso_autoconfig() { +static int iso_autoconfig() +{ struct stat statb; /* ISO endpoints "must not be part of a default interface setting". @@ -286,39 +464,207 @@ static int iso_autoconfig() { */ device_desc.idProduct = __constant_cpu_to_le16(DRIVER_ISO_PRODUCT_NUM); - if (stat(DEVNAME = "fe980000.usb", &statb) == 0) { - unsigned bInterval; + /* NetChip 2280 PCI device or dummy_hcd, high/full speed */ + if (stat(DEVNAME = "net2280", &statb) == 0 || + stat(DEVNAME = "dummy_udc", &statb) == 0) + { + unsigned bInterval, wMaxPacketSize; - bInterval = interval; + HIGHSPEED = 1; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0100); + + /* this code won't use two or four uframe periods */ + if (bufsize > 1024) + { + interval = 0; + bInterval = 1; + /* "modprobe net2280 fifo_mode=1" may be needed */ + if (bufsize > (2 * 1024)) + { + wMaxPacketSize = min((bufsize + 2) / 3, 1024); + bufsize = min(3 * wMaxPacketSize, bufsize); + wMaxPacketSize |= 2 << 11; + } + else + { + wMaxPacketSize = min((bufsize + 1) / 2, 1024); + wMaxPacketSize |= 1 << 11; + } + } + else + { + bInterval = interval + 4; + wMaxPacketSize = bufsize; + } + + fs_source_desc.bEndpointAddress = hs_source_desc.bEndpointAddress = USB_DIR_IN | 7; + fs_source_desc.bmAttributes = hs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_source_desc.wMaxPacketSize = min(bufsize, 1023); + hs_source_desc.wMaxPacketSize = wMaxPacketSize; + fs_source_desc.bInterval = interval + 1; + hs_source_desc.bInterval = bInterval; + EP_IN_NAME = "ep-a"; + + fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress = USB_DIR_OUT | 3; + fs_sink_desc.bmAttributes = hs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_sink_desc.wMaxPacketSize = min(bufsize, 1023); + hs_sink_desc.wMaxPacketSize = wMaxPacketSize; + fs_sink_desc.bInterval = interval + 1; + hs_sink_desc.bInterval = bInterval; + EP_OUT_NAME = "ep-b"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = hs_status_desc.bEndpointAddress = USB_DIR_IN | 11; + EP_STATUS_NAME = "ep-f"; + + /* Intel PXA 2xx processor, full speed only */ + } + else if (stat(DEVNAME = "pxa2xx_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0101), + + bufsize = min(bufsize, 256); + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 3; + fs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_source_desc.wMaxPacketSize = bufsize; + fs_source_desc.bInterval = interval; + EP_IN_NAME = "ep3in-iso"; + + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 4; + fs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_sink_desc.wMaxPacketSize = bufsize; + fs_sink_desc.bInterval = interval; + EP_OUT_NAME = "ep4out-iso"; + + /* using bulk for this since the pxa interrupt endpoints + * always use the no-toggle scheme (discouraged). + */ + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 11; + EP_STATUS_NAME = "ep11in-bulk"; + + /* OMAP 1610 and newer devices, full speed only, fifo mode 3 */ + } + else if (stat(DEVNAME = "omap_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0102), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 7; + fs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_source_desc.wMaxPacketSize = min(bufsize, 256); + fs_source_desc.bInterval = interval; + EP_IN_NAME = "ep7in-iso"; + + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 8; + fs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_sink_desc.wMaxPacketSize = min(bufsize, 256); + fs_sink_desc.bInterval = interval; + EP_OUT_NAME = "ep8out-iso"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 9; + EP_STATUS_NAME = "ep9in-int"; + + /* Something based on Mentor USB Highspeed Dual-Role Controller; + * assumes a core that doesn't include high bandwidth support. + */ + //} else if (stat (DEVNAME = "musb_hdrc", &statb) == 0) { + } + else if (stat(DEVNAME = "fe980000.usb", &statb) == 0) + { + unsigned bInterval, wMaxPacketSize; HIGHSPEED = 1; device_desc.bcdDevice = __constant_cpu_to_le16(0x0103); - unsigned short wMaxPacketSize = (unsigned short)bufsize; + bInterval = interval; + wMaxPacketSize = bufsize; + + fs_source_desc.bEndpointAddress = hs_source_desc.bEndpointAddress = USB_DIR_IN | 1; + fs_source_desc.bmAttributes = hs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_source_desc.wMaxPacketSize = min(bufsize, 1023); + hs_source_desc.wMaxPacketSize = wMaxPacketSize; + fs_source_desc.bInterval = interval + 1; + hs_source_desc.bInterval = bInterval; + EP_IN_NAME = "ep1in"; - fprintf(stderr,"\n\n%04x\n\n", wMaxPacketSize); + fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1; + fs_sink_desc.bmAttributes = hs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_sink_desc.wMaxPacketSize = min(bufsize, 1023); + hs_sink_desc.wMaxPacketSize = wMaxPacketSize; + fs_sink_desc.bInterval = interval + 1; + hs_sink_desc.bInterval = bInterval; + EP_OUT_NAME = "ep1out"; - fs_in_desc.bEndpointAddress = hs_in_desc.bEndpointAddress = USB_DIR_IN | 1; - fs_in_desc.bmAttributes = hs_in_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; - fs_in_desc.wMaxPacketSize = min(bufsize, 1023); - hs_in_desc.wMaxPacketSize = wMaxPacketSize; - fs_in_desc.bInterval = interval + 1; - hs_in_desc.bInterval = bInterval; - EP_IN_NAME = "ep1in"; - - in_out_intf.bNumEndpoints = 1; + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = hs_status_desc.bEndpointAddress = USB_DIR_IN | 11; + EP_STATUS_NAME = "ep3"; /* Atmel AT91 processors, full speed only */ - } else { + } + else if (stat(DEVNAME = "at91_udc", &statb) == 0) + { + HIGHSPEED = 0; + device_desc.bcdDevice = __constant_cpu_to_le16(0x0104), + + fs_source_desc.bEndpointAddress = USB_DIR_IN | 4; + fs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_source_desc.wMaxPacketSize = min(bufsize, 256); + fs_source_desc.bInterval = interval; + EP_IN_NAME = "ep4"; + + fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2; + fs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_sink_desc.wMaxPacketSize = min(bufsize, 256); + fs_sink_desc.bInterval = interval; + EP_OUT_NAME = "ep5"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3-int"; + + /* Atmel AT32AP700x processors, high/full speed */ + } + else if (stat(DEVNAME = "atmel_usba_udc", &statb) == 0) + { + HIGHSPEED = 1; + + device_desc.bcdDevice = __constant_cpu_to_le16(0x0105); + + fs_source_desc.bEndpointAddress = hs_source_desc.bEndpointAddress = USB_DIR_IN | 5; + fs_source_desc.bmAttributes = hs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_source_desc.wMaxPacketSize = hs_source_desc.wMaxPacketSize = __cpu_to_le16(min(bufsize, 1024)); + fs_source_desc.bInterval = hs_source_desc.bInterval = interval; + EP_IN_NAME = "ep5in-iso"; + + fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress = USB_DIR_OUT | 6; + fs_sink_desc.bmAttributes = hs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC; + fs_sink_desc.wMaxPacketSize = hs_sink_desc.wMaxPacketSize = __cpu_to_le16(min(bufsize, 1024)); + fs_sink_desc.bInterval = hs_sink_desc.bInterval = interval; + EP_OUT_NAME = "ep6out-iso"; + + source_sink_intf.bNumEndpoints = 3; + fs_status_desc.bEndpointAddress = hs_status_desc.bEndpointAddress = USB_DIR_IN | 3; + EP_STATUS_NAME = "ep3in-int"; + } + else + { DEVNAME = 0; return -ENODEV; } - if (verbose) { + if (verbose) + { fprintf(stderr, "iso fs wMaxPacket %04x bInterval %02x\n", - __le16_to_cpu(fs_in_desc.wMaxPacketSize), fs_in_desc.bInterval); + __le16_to_cpu(fs_sink_desc.wMaxPacketSize), + fs_sink_desc.bInterval); if (HIGHSPEED) - fprintf(stderr, "iso hs wMaxPacket %04x bInterval %02x\n", - __le16_to_cpu(hs_in_desc.wMaxPacketSize), hs_in_desc.bInterval); + fprintf(stderr, + "iso hs wMaxPacket %04x bInterval %02x\n", + __le16_to_cpu(hs_sink_desc.wMaxPacketSize), + hs_sink_desc.bInterval); } return 0; } @@ -329,34 +675,41 @@ static int iso_autoconfig() { /*-------------------------------------------------------------------------*/ -/* full duplex data, with at least three threads: ep0, out, and in */ +/* full duplex data, with at least three threads: ep0, sink, and source */ static pthread_t ep0; -static pthread_t in; -static int in_fd = -1; +static pthread_t source; +static int source_fd = -1; -static pthread_t out; -static int out_fd = -1; +static pthread_t sink; +static int sink_fd = -1; // FIXME no status i/o yet -static void close_fd(void *fd_ptr) { +static void close_fd(void *fd_ptr) +{ int status, fd; fd = *(int *)fd_ptr; *(int *)fd_ptr = -1; /* test the FIFO ioctls (non-ep0 code paths) */ - if (pthread_self() != ep0) { + if (pthread_self() != ep0) + { status = ioctl(fd, GADGETFS_FIFO_STATUS); - if (status < 0) { + if (status < 0) + { /* ENODEV reported after disconnect */ if (errno != ENODEV && errno != -EOPNOTSUPP) perror("get fifo status"); - } else { - fprintf(stderr, "fd %d, unclaimed = %d\n", fd, status); - if (status) { + } + else + { + fprintf(stderr, "fd %d, unclaimed = %d\n", + fd, status); + if (status) + { status = ioctl(fd, GADGETFS_FIFO_FLUSH); if (status < 0) perror("fifo flush"); @@ -371,16 +724,21 @@ static void close_fd(void *fd_ptr) { /* you should be able to open and configure endpoints * whether or not the host is connected */ -static int ep_config(char *name, const char *label, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs) { +static int +ep_config(char *name, const char *label, + struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ int fd, status; char buf[USB_BUFSIZE]; /* open and initialize with endpoint descriptor(s) */ fd = open(name, O_RDWR); - if (fd < 0) { + if (fd < 0) + { status = -errno; - fprintf(stderr, "%s open %s error %d (%s)\n", label, name, errno, strerror(errno)); + fprintf(stderr, "%s open %s error %d (%s)\n", + label, name, errno, strerror(errno)); return status; } @@ -388,14 +746,19 @@ static int ep_config(char *name, const char *label, struct usb_endpoint_descript *(__u32 *)buf = 1; /* tag for this format */ memcpy(buf + 4, fs, USB_DT_ENDPOINT_SIZE); if (HIGHSPEED) - memcpy(buf + 4 + USB_DT_ENDPOINT_SIZE, hs, USB_DT_ENDPOINT_SIZE); + memcpy(buf + 4 + USB_DT_ENDPOINT_SIZE, + hs, USB_DT_ENDPOINT_SIZE); status = write(fd, buf, 4 + USB_DT_ENDPOINT_SIZE + (HIGHSPEED ? USB_DT_ENDPOINT_SIZE : 0)); - if (status < 0) { + if (status < 0) + { status = -errno; - fprintf(stderr, "%s config %s error %d (%s)\n", label, name, errno, strerror(errno)); + fprintf(stderr, "%s config %s error %d (%s)\n", + label, name, errno, strerror(errno)); close(fd); return status; - } else if (verbose) { + } + else if (verbose) + { unsigned long id; id = pthread_self(); @@ -404,21 +767,26 @@ static int ep_config(char *name, const char *label, struct usb_endpoint_descript return fd; } -#define in_open(name) ep_config(name, __FUNCTION__, &fs_in_desc, &hs_in_desc) -#define out_open(name) ep_config(name, __FUNCTION__, &fs_out_desc, &hs_out_desc) +#define source_open(name) \ + ep_config(name, __FUNCTION__, &fs_source_desc, &hs_source_desc) +#define sink_open(name) \ + ep_config(name, __FUNCTION__, &fs_sink_desc, &hs_sink_desc) -static unsigned long fill_in_buf(void *buf, unsigned long nbytes) { +static unsigned long fill_in_buf(void *buf, unsigned long nbytes) +{ #ifdef DO_PIPE /* pipe stdin to host */ nbytes = fread(buf, 1, nbytes, stdin); - if (nbytes == 0) { + if (nbytes == 0) + { if (ferror(stdin)) perror("read stdin"); if (feof(stdin)) errno = ENODEV; } #else - switch (pattern) { + switch (pattern) + { unsigned i; default: @@ -435,13 +803,15 @@ static unsigned long fill_in_buf(void *buf, unsigned long nbytes) { return nbytes; } -static int empty_out_buf(void *buf, unsigned long nbytes) { +static int empty_out_buf(void *buf, unsigned long nbytes) +{ unsigned len; #ifdef DO_PIPE /* pipe from host to stdout */ len = fwrite(buf, nbytes, 1, stdout); - if (len != nbytes) { + if (len != nbytes) + { if (ferror(stdout)) perror("write stdout"); } @@ -449,8 +819,10 @@ static int empty_out_buf(void *buf, unsigned long nbytes) { unsigned i; __u8 expected, *data; - for (i = 0, data = buf; i < nbytes; i++, data++) { - switch (pattern) { + for (i = 0, data = buf; i < nbytes; i++, data++) + { + switch (pattern) + { case 0: expected = 0; break; @@ -463,8 +835,10 @@ static int empty_out_buf(void *buf, unsigned long nbytes) { } if (*data == expected) continue; - fprintf(stderr, "bad OUT byte %d, expected %02x got %02x\n", i, expected, *data); - for (i = 0, data = 0; i < nbytes; i++, data++) { + fprintf(stderr, "bad OUT byte %d, expected %02x got %02x\n", + i, expected, *data); + for (i = 0, data = 0; i < nbytes; i++, data++) + { if (0 == (i % 16)) fprintf(stderr, "%4d:", i); fprintf(stderr, " %02x", *data); @@ -479,18 +853,20 @@ static int empty_out_buf(void *buf, unsigned long nbytes) { return len; } -static void *simple_in_thread(void *param) { +static void *simple_source_thread(void *param) +{ char *name = (char *)param; int status; char buf[USB_BUFSIZE]; - status = in_open(name); + status = source_open(name); if (status < 0) return 0; - in_fd = status; + source_fd = status; - pthread_cleanup_push(close_fd, &in_fd); - do { + pthread_cleanup_push(close_fd, &source_fd); + do + { unsigned long len; /* original LinuxThreads cancelation didn't work right @@ -500,15 +876,17 @@ static void *simple_in_thread(void *param) { len = fill_in_buf(buf, sizeof buf); if (len > 0) - status = write(in_fd, buf, len); + status = write(source_fd, buf, len); else status = 0; } while (status > 0); - if (status == 0) { + if (status == 0) + { if (verbose) fprintf(stderr, "done %s\n", __FUNCTION__); - } else if (verbose > 2 || errno != ESHUTDOWN) /* normal disconnect */ + } + else if (verbose > 2 || errno != ESHUTDOWN) /* normal disconnect */ perror("write"); fflush(stdout); fflush(stderr); @@ -517,34 +895,38 @@ static void *simple_in_thread(void *param) { return 0; } -static void *simple_out_thread(void *param) { +static void *simple_sink_thread(void *param) +{ char *name = (char *)param; int status; char buf[USB_BUFSIZE]; - status = out_open(name); + status = sink_open(name); if (status < 0) return 0; - out_fd = status; + sink_fd = status; /* synchronous reads of endless streams of data */ - pthread_cleanup_push(close_fd, &out_fd); - do { + pthread_cleanup_push(close_fd, &sink_fd); + do + { /* original LinuxThreads cancelation didn't work right * so test for it explicitly. */ pthread_testcancel(); errno = 0; - status = read(out_fd, buf, sizeof buf); + status = read(sink_fd, buf, sizeof buf); if (status < 0) break; status = empty_out_buf(buf, status); } while (status > 0); - if (status == 0) { + if (status == 0) + { if (verbose) fprintf(stderr, "done %s\n", __FUNCTION__); - } else if (verbose > 2 || errno != ESHUTDOWN) /* normal disconnect */ + } + else if (verbose > 2 || errno != ESHUTDOWN) /* normal disconnect */ perror("read"); fflush(stdout); fflush(stderr); @@ -553,8 +935,8 @@ static void *simple_out_thread(void *param) { return 0; } -static void *(*in_thread)(void *); -static void *(*out_thread)(void *); +static void *(*source_thread)(void *); +static void *(*sink_thread)(void *); #ifdef AIO @@ -570,14 +952,19 @@ static unsigned aio_out = 0; /* urgh, this is messy ... should couple it to the io_context */ static unsigned aio_in_pending, aio_out_pending; -static void queue_release(void *ctx_ptr) { io_destroy(*(io_context_t *)ctx_ptr); } +static void queue_release(void *ctx_ptr) +{ + io_destroy(*(io_context_t *)ctx_ptr); +} -static int io_run(io_context_t ctx, volatile unsigned *pending) { +static int io_run(io_context_t ctx, volatile unsigned *pending) +{ int ret; struct io_event e[5]; /* process iocbs so long as they reissue */ - while (pending) { + while (pending) + { unsigned i; struct iocb *iocb; io_callback_t io_complete; @@ -586,7 +973,8 @@ static int io_run(io_context_t ctx, volatile unsigned *pending) { ret = io_getevents(ctx, 1, 5, &e[0], 0); if (ret < 0) break; - for (i = 0; i < ret; i++) { + for (i = 0; i < ret; i++) + { io_complete = (io_callback_t)e[i].data; iocb = (struct iocb *)e[i].obj; io_complete(ctx, iocb, e[i].res, e[i].res2); @@ -596,11 +984,15 @@ static int io_run(io_context_t ctx, volatile unsigned *pending) { return ret; } -static void in_complete(io_context_t ctx, struct iocb *iocb, long res, long res2) { +static void +in_complete(io_context_t ctx, struct iocb *iocb, long res, long res2) +{ int status; if (verbose > 2) - fprintf(stderr, "%s uiocb %p status %ld %ld\n", __FUNCTION__, iocb, res, res2); + fprintf(stderr, "%s uiocb %p status %ld %ld\n", + __FUNCTION__, iocb, + res, res2); /* fail on short write _OR_ fault */ if (res != iocb->u.c.nbytes || res2 != 0) @@ -608,8 +1000,11 @@ static void in_complete(io_context_t ctx, struct iocb *iocb, long res, long res2 /* get data we'll write to the host */ iocb->u.c.nbytes = fill_in_buf(iocb->u.c.buf, iosize); - if (iocb->u.c.nbytes < 0) { - fprintf(stderr, "%s %p refill fail, %d (%s)\n", __FUNCTION__, iocb, errno, strerror(errno)); + if (iocb->u.c.nbytes < 0) + { + fprintf(stderr, "%s %p refill fail, %d (%s)\n", + __FUNCTION__, iocb, + errno, strerror(errno)); goto clean; } @@ -618,7 +1013,9 @@ static void in_complete(io_context_t ctx, struct iocb *iocb, long res, long res2 status = io_submit(ctx, 1, &iocb); if (status == 1) return; - fprintf(stderr, "%s %p resubmit fail, %d (%s)\n", __FUNCTION__, iocb, errno, strerror(errno)); + fprintf(stderr, "%s %p resubmit fail, %d (%s)\n", + __FUNCTION__, iocb, + errno, strerror(errno)); goto clean; fail: @@ -626,7 +1023,9 @@ static void in_complete(io_context_t ctx, struct iocb *iocb, long res, long res2 errno = -res; else if (res2 < 0) errno = -res2; - fprintf(stderr, "%s %p fail %ld/%ld, %d (%s)\n", __FUNCTION__, iocb, res, iocb->u.c.nbytes, + fprintf(stderr, "%s %p fail %ld/%ld, %d (%s)\n", + __FUNCTION__, iocb, + res, iocb->u.c.nbytes, errno, strerror(errno)); goto resubmit; clean: @@ -634,22 +1033,24 @@ static void in_complete(io_context_t ctx, struct iocb *iocb, long res, long res2 return; } -static void *aio_in_thread(void *param) { +static void *aio_in_thread(void *param) +{ char *name = (char *)param; int status; io_context_t ctx = 0; struct iocb *queue, *iocb; unsigned i; - status = in_open(name); + status = source_open(name); if (status < 0) return 0; - in_fd = status; - pthread_cleanup_push(close_fd, &in_fd); + source_fd = status; + pthread_cleanup_push(close_fd, &source_fd); /* initialize i/o queue */ status = io_setup(aio_in, &ctx); - if (status < 0) { + if (status < 0) + { perror("aio_in_thread, io_setup"); return 0; } @@ -660,27 +1061,34 @@ static void *aio_in_thread(void *param) { queue = alloca(aio_in * sizeof *iocb); /* populate and (re)run the queue */ - for (i = 0, iocb = queue; i < aio_in; i++, iocb++) { + for (i = 0, iocb = queue; i < aio_in; i++, iocb++) + { char *buf = malloc(iosize); - if (!buf) { - fprintf(stderr, "%s can't get buffer[%d]\n", __FUNCTION__, i); + if (!buf) + { + fprintf(stderr, "%s can't get buffer[%d]\n", + __FUNCTION__, i); return 0; } /* host receives the data we're writing */ - io_prep_pwrite(iocb, in_fd, buf, fill_in_buf(buf, iosize), 0); + io_prep_pwrite(iocb, source_fd, + buf, fill_in_buf(buf, iosize), + 0); io_set_callback(iocb, in_complete); iocb->key = USB_DIR_IN; status = io_submit(ctx, 1, &iocb); - if (status < 0) { + if (status < 0) + { perror(__FUNCTION__); break; } aio_in_pending++; if (verbose > 2) - fprintf(stderr, "%s submit uiocb %p\n", __FUNCTION__, iocb); + fprintf(stderr, "%s submit uiocb %p\n", + __FUNCTION__, iocb); } status = io_run(ctx, &aio_in_pending); @@ -695,11 +1103,15 @@ static void *aio_in_thread(void *param) { return 0; } -static void out_complete(io_context_t ctx, struct iocb *iocb, long res, long res2) { +static void +out_complete(io_context_t ctx, struct iocb *iocb, long res, long res2) +{ int status; if (verbose > 2) - fprintf(stderr, "%s uiocb %p status %ld %ld\n", __FUNCTION__, iocb, res, res2); + fprintf(stderr, "%s uiocb %p status %ld %ld\n", + __FUNCTION__, iocb, + res, res2); /* fail on all errors we can see. (short reads MAY mask faults.) */ if (res < 0) @@ -713,34 +1125,38 @@ static void out_complete(io_context_t ctx, struct iocb *iocb, long res, long res status = io_submit(ctx, 1, &iocb); if (status == 1) return; - fprintf(stderr, "aio read %p resubmit fail, %d (%s)\n", iocb, errno, strerror(errno)); + fprintf(stderr, "aio read %p resubmit fail, %d (%s)\n", iocb, + errno, strerror(errno)); goto clean; fail: errno = -res; - fprintf(stderr, "aio read %p fail, %d (%s)\n", iocb, errno, strerror(errno)); + fprintf(stderr, "aio read %p fail, %d (%s)\n", iocb, + errno, strerror(errno)); goto resubmit; clean: aio_out_pending--; return; } -static void *aio_out_thread(void *param) { +static void *aio_out_thread(void *param) +{ char *name = (char *)param; int status; io_context_t ctx = 0; struct iocb *queue, *iocb; unsigned i; - status = out_open(name); + status = sink_open(name); if (status < 0) return 0; - out_fd = status; - pthread_cleanup_push(close_fd, &out_fd); + sink_fd = status; + pthread_cleanup_push(close_fd, &sink_fd); /* initialize i/o queue */ status = io_setup(aio_out, &ctx); - if (status < 0) { + if (status < 0) + { perror("aio_out_thread, io_setup"); return 0; } @@ -751,27 +1167,32 @@ static void *aio_out_thread(void *param) { queue = alloca(aio_out * sizeof *iocb); /* populate and (re)run the queue */ - for (i = 0, iocb = queue; i < aio_out; i++, iocb++) { + for (i = 0, iocb = queue; i < aio_out; i++, iocb++) + { char *buf = malloc(iosize); - if (!buf) { - fprintf(stderr, "%s can't get buffer[%d]\n", __FUNCTION__, i); + if (!buf) + { + fprintf(stderr, "%s can't get buffer[%d]\n", + __FUNCTION__, i); return 0; } /* data can be processed in out_complete() */ - io_prep_pread(iocb, out_fd, buf, iosize, 0); + io_prep_pread(iocb, sink_fd, buf, iosize, 0); io_set_callback(iocb, out_complete); iocb->key = USB_DIR_OUT; status = io_submit(ctx, 1, &iocb); - if (status < 0) { + if (status < 0) + { perror(__FUNCTION__); break; } aio_out_pending++; if (verbose > 2) - fprintf(stderr, "%s submit uiocb %p\n", __FUNCTION__, iocb); + fprintf(stderr, "%s submit uiocb %p\n", + __FUNCTION__, iocb); } status = io_run(ctx, &aio_out_pending); @@ -788,7 +1209,8 @@ static void *aio_out_thread(void *param) { #endif /* AIO */ -static void start_io() { +static void start_io() +{ sigset_t allsig, oldsig; #ifdef AIO @@ -796,21 +1218,18 @@ static void start_io() { * (u)frame's worth of data per i/o request, and the host * polls that queue once per interval. */ - switch (current_speed) { + switch (current_speed) + { case USB_SPEED_FULL: if (iso) - iosize = __le16_to_cpup(&fs_in_desc.wMaxPacketSize); + iosize = __le16_to_cpup(&fs_source_desc + .wMaxPacketSize); else iosize = bufsize; break; case USB_SPEED_HIGH: /* for iso, we updated bufsize earlier */ - if(hs_in_desc.wMaxPacketSize > 1024){ - iosize = 3072; - } else{ - iosize = hs_in_desc.wMaxPacketSize; - } - iosize = 3072; + iosize = bufsize; break; default: fprintf(stderr, "bogus link speed %d\n", current_speed); @@ -820,7 +1239,8 @@ static void start_io() { sigfillset(&allsig); errno = pthread_sigmask(SIG_SETMASK, &allsig, &oldsig); - if (errno < 0) { + if (errno < 0) + { perror("set thread signal mask"); return; } @@ -830,8 +1250,19 @@ static void start_io() { * why? this clearly doesn't ... */ - if (pthread_create(&in, 0, in_thread, (void *)EP_IN_NAME) != 0) { - perror("can't create in thread"); + if (pthread_create(&source, 0, + source_thread, (void *)EP_IN_NAME) != 0) + { + perror("can't create source thread"); + goto cleanup; + } + + if (pthread_create(&sink, 0, + sink_thread, (void *)EP_OUT_NAME) != 0) + { + perror("can't create sink thread"); + pthread_cancel(source); + source = ep0; goto cleanup; } @@ -844,31 +1275,37 @@ static void start_io() { cleanup: errno = pthread_sigmask(SIG_SETMASK, &oldsig, 0); - if (errno != 0) { + if (errno != 0) + { perror("restore sigmask"); exit(-1); } } -static void stop_io() { - if (!pthread_equal(in, ep0)) { - pthread_cancel(in); - if (pthread_join(in, 0) != 0) - perror("can't join in thread"); - in = ep0; +static void stop_io() +{ + if (!pthread_equal(source, ep0)) + { + pthread_cancel(source); + if (pthread_join(source, 0) != 0) + perror("can't join source thread"); + source = ep0; } - if (!pthread_equal(out, ep0)) { - pthread_cancel(out); - if (pthread_join(out, 0) != 0) - perror("can't join out thread"); - out = ep0; + if (!pthread_equal(sink, ep0)) + { + pthread_cancel(sink); + if (pthread_join(sink, 0) != 0) + perror("can't join sink thread"); + sink = ep0; } } /*-------------------------------------------------------------------------*/ -static char *build_config(char *cp, const struct usb_endpoint_descriptor **ep) { +static char * +build_config(char *cp, const struct usb_endpoint_descriptor **ep) +{ struct usb_config_descriptor *c; int i; @@ -876,10 +1313,11 @@ static char *build_config(char *cp, const struct usb_endpoint_descriptor **ep) { memcpy(cp, &config, config.bLength); cp += config.bLength; - memcpy(cp, &in_out_intf, in_out_intf.bLength); - cp += in_out_intf.bLength; + memcpy(cp, &source_sink_intf, source_sink_intf.bLength); + cp += source_sink_intf.bLength; - for (i = 0; i < in_out_intf.bNumEndpoints; i++) { + for (i = 0; i < source_sink_intf.bNumEndpoints; i++) + { memcpy(cp, ep[i], USB_DT_ENDPOINT_SIZE); cp += USB_DT_ENDPOINT_SIZE; } @@ -887,7 +1325,8 @@ static char *build_config(char *cp, const struct usb_endpoint_descriptor **ep) { return cp; } -static int init_device(void) { +static int init_device(void) +{ char buf[4096], *cp = &buf[0]; int fd; int status; @@ -898,13 +1337,16 @@ static int init_device(void) { else #endif status = autoconfig(); - if (status < 0) { - fprintf(stderr, "?? don't recognize /dev/gadget %s device\n", iso ? "iso" : "bulk"); + if (status < 0) + { + fprintf(stderr, "?? don't recognize /dev/gadget %s device\n", + iso ? "iso" : "bulk"); return status; } fd = open(DEVNAME, O_RDWR); - if (fd < 0) { + if (fd < 0) + { perror(DEVNAME); return -errno; } @@ -922,19 +1364,24 @@ static int init_device(void) { cp += sizeof device_desc; status = write(fd, &buf[0], cp - &buf[0]); - if (status < 0) { + if (status < 0) + { perror("write dev descriptors"); close(fd); return status; - } else if (status != (cp - buf)) { - fprintf(stderr, "dev init, wrote %d expected %d\n", status, cp - buf); + } + else if (status != (cp - buf)) + { + fprintf(stderr, "dev init, wrote %d expected %d\n", + status, cp - buf); close(fd); return -EIO; } return fd; } -static void handle_control(int fd, struct usb_ctrlrequest *setup) { +static void handle_control(int fd, struct usb_ctrlrequest *setup) +{ int status, tmp; __u8 buf[256]; __u16 value, index, length; @@ -944,26 +1391,30 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { length = __le16_to_cpu(setup->wLength); if (verbose) - fprintf(stderr, - "SETUP %02x.%02x " - "v%04x i%04x %d\n", - setup->bRequestType, setup->bRequest, value, index, length); + fprintf(stderr, "SETUP %02x.%02x " + "v%04x i%04x %d\n", + setup->bRequestType, setup->bRequest, + value, index, length); /* if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) goto special; */ - switch (setup->bRequest) { /* usb 2.0 spec ch9 requests */ + switch (setup->bRequest) + { /* usb 2.0 spec ch9 requests */ case USB_REQ_GET_DESCRIPTOR: fprintf(stderr, "GET DESC"); if (setup->bRequestType != USB_DIR_IN) goto stall; - switch (value >> 8) { + switch (value >> 8) + { case USB_DT_STRING: tmp = value & 0x0ff; if (verbose > 1) - fprintf(stderr, "... get string %d lang %04x\n", tmp, index); + fprintf(stderr, + "... get string %d lang %04x\n", + tmp, index); if (tmp != 0 && index != strings.language) goto stall; status = usb_gadget_get_string(&strings, tmp, buf); @@ -973,13 +1424,17 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { if (length < tmp) tmp = length; status = write(fd, buf, tmp); - if (status < 0) { + if (status < 0) + { if (errno == EIDRM) fprintf(stderr, "string timeout\n"); else perror("write string data"); - } else if (status != tmp) { - fprintf(stderr, "short string write, %d\n", status); + } + else if (status != tmp) + { + fprintf(stderr, "short string write, %d\n", + status); } break; default: @@ -1003,7 +1458,8 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { * the endpoints always active and don't rely on seeing any * config change events, either this or SET_INTERFACE. */ - switch (value) { + switch (value) + { case CONFIG_VALUE: start_io(); break; @@ -1028,13 +1484,17 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { /* only one altsetting in this driver */ buf[0] = 0; status = write(fd, buf, length); - if (status < 0) { + if (status < 0) + { if (errno == EIDRM) - fprintf(stderr, "GET_INTERFACE timeout %s\n", strerror(errno)); + fprintf(stderr, "GET_INTERFACE timeout\n"); else perror("write GET_INTERFACE data"); - } else if (status != length) { - fprintf(stderr, "short GET_INTERFACE write, %d\n", status); + } + else if (status != length) + { + fprintf(stderr, "short GET_INTERFACE write, %d\n", + status); } return; case USB_REQ_SET_INTERFACE: @@ -1043,13 +1503,15 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { fprintf(stderr, "SET INTERFACE\n"); /* just reset toggle/halt for the interface's endpoints */ status = 0; - if (ioctl(in_fd, GADGETFS_CLEAR_HALT) < 0) { + if (ioctl(source_fd, GADGETFS_CLEAR_HALT) < 0) + { status = errno; - perror("reset in fd"); + perror("reset source fd"); } - if (ioctl(out_fd, GADGETFS_CLEAR_HALT) < 0) { + if (ioctl(sink_fd, GADGETFS_CLEAR_HALT) < 0) + { status = errno; - perror("reset out fd"); + perror("reset sink fd"); } /* FIXME eventually reset the status endpoint too */ if (status) @@ -1066,7 +1528,8 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { stall: if (verbose) - fprintf(stderr, "... protocol stall %02x.%02x\n", setup->bRequestType, setup->bRequest); + fprintf(stderr, "... protocol stall %02x.%02x\n", + setup->bRequestType, setup->bRequest); /* non-iso endpoints are stalled by issuing an i/o request * in the "wrong" direction. ep0 is special only because @@ -1077,19 +1540,23 @@ static void handle_control(int fd, struct usb_ctrlrequest *setup) { else status = write(fd, &status, 0); if (status != -1) - fprintf(stderr, "can't stall ep0 for %02x.%02x\n", setup->bRequestType, setup->bRequest); + fprintf(stderr, "can't stall ep0 for %02x.%02x\n", + setup->bRequestType, setup->bRequest); else if (errno != EL2HLT) perror("ep0 stall"); } -static void signothing(int sig, siginfo_t *info, void *ptr) { +static void signothing(int sig, siginfo_t *info, void *ptr) +{ /* NOP */ if (verbose > 2) fprintf(stderr, "%s %d\n", __FUNCTION__, sig); } -static const char *speed(enum usb_device_speed s) { - switch (s) { +static const char *speed(enum usb_device_speed s) +{ + switch (s) + { case USB_SPEED_LOW: return "low speed"; case USB_SPEED_FULL: @@ -1108,13 +1575,14 @@ static const char *speed(enum usb_device_speed s) { #define NEVENT 5 #define LOGDELAY (15 * 60) /* seconds before stdout timestamp */ -static void *ep0_thread(void *param) { +static void *ep0_thread(void *param) +{ int fd = *(int *)param; struct sigaction action; time_t now, last; struct pollfd ep0_poll; - in = out = ep0 = pthread_self(); + source = sink = ep0 = pthread_self(); pthread_cleanup_push(close_fd, param); /* REVISIT signal handling ... normally one pthread should @@ -1123,11 +1591,13 @@ static void *ep0_thread(void *param) { action.sa_sigaction = signothing; sigfillset(&action.sa_mask); action.sa_flags = SA_SIGINFO; - if (sigaction(SIGINT, &action, NULL) < 0) { + if (sigaction(SIGINT, &action, NULL) < 0) + { perror("SIGINT"); return 0; } - if (sigaction(SIGQUIT, &action, NULL) < 0) { + if (sigaction(SIGQUIT, &action, NULL) < 0) + { perror("SIGQUIT"); return 0; } @@ -1137,7 +1607,8 @@ static void *ep0_thread(void *param) { /* event loop */ last = 0; - for (;;) { + for (;;) + { int tmp; struct usb_gadgetfs_event event[NEVENT]; int connected = 0; @@ -1150,9 +1621,11 @@ static void *ep0_thread(void *param) { * instead using SIGIO. */ tmp = poll(&ep0_poll, 1, -1); - if (verbose) { + if (verbose) + { time(&now); - if ((now - last) > LOGDELAY) { + if ((now - last) > LOGDELAY) + { char timebuf[26]; last = now; @@ -1160,15 +1633,18 @@ static void *ep0_thread(void *param) { printf("\n** %s", timebuf); } } - if (tmp < 0) { + if (tmp < 0) + { /* exit path includes EINTR exits */ perror("poll"); break; } tmp = read(fd, &event, sizeof event); - if (tmp < 0) { - if (errno == EAGAIN) { + if (tmp < 0) + { + if (errno == EAGAIN) + { sleep(1); continue; } @@ -1177,10 +1653,13 @@ static void *ep0_thread(void *param) { } nevent = tmp / sizeof event[0]; if (nevent != 1 && verbose) - fprintf(stderr, "read %d ep0 events\n", nevent); + fprintf(stderr, "read %d ep0 events\n", + nevent); - for (i = 0; i < nevent; i++) { - switch (event[i].type) { + for (i = 0; i < nevent; i++) + { + switch (event[i].type) + { case GADGETFS_NOP: if (verbose) fprintf(stderr, "NOP\n"); @@ -1189,7 +1668,9 @@ static void *ep0_thread(void *param) { connected = 1; current_speed = event[i].u.speed; if (verbose) - fprintf(stderr, "CONNECT %s\n", speed(event[i].u.speed)); + fprintf(stderr, + "CONNECT %s\n", + speed(event[i].u.speed)); break; case GADGETFS_SETUP: connected = 1; @@ -1208,7 +1689,9 @@ static void *ep0_thread(void *param) { fprintf(stderr, "SUSPEND\n"); break; default: - fprintf(stderr, "* unhandled event %d\n", event[i].type); + fprintf(stderr, + "* unhandled event %d\n", + event[i].type); } } continue; @@ -1228,22 +1711,26 @@ static void *ep0_thread(void *param) { /*-------------------------------------------------------------------------*/ -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ int fd, c, i; /* random initial serial number */ srand((int)time(0)); - for (i = 0; i < sizeof serial - 1;) { + for (i = 0; i < sizeof serial - 1;) + { c = rand() % 127; if ((('a' <= c && c <= 'z') || ('0' <= c && c <= '9'))) serial[i++] = c; } - in_thread = simple_in_thread; - out_thread = simple_out_thread; + source_thread = simple_source_thread; + sink_thread = simple_sink_thread; - while ((c = getopt(argc, argv, "I:a:i:o:p:r:s:v")) != EOF) { - switch (c) { + while ((c = getopt(argc, argv, "I:a:i:o:p:r:s:v")) != EOF) + { + switch (c) + { #ifdef AIO /* "-s1020 -I0 -a20" does ~1K/usec, 20 usecs buffered */ case 'I': /* ISO */ @@ -1252,21 +1739,21 @@ int main(int argc, char **argv) { * ignored if high bandwidth could kick in */ interval = atoi(optarg); - in_thread = aio_in_thread; - out_thread = aio_out_thread; + source_thread = aio_in_thread; + sink_thread = aio_out_thread; continue; case 'a': /* aio IN/OUT qlen */ aio_in = aio_out = atoi(optarg); - in_thread = aio_in_thread; - out_thread = aio_out_thread; + source_thread = aio_in_thread; + sink_thread = aio_out_thread; continue; case 'i': /* aio IN qlen */ aio_in = atoi(optarg); - in_thread = aio_in_thread; + source_thread = aio_in_thread; continue; case 'o': /* aio OUT qlen */ aio_out = atoi(optarg); - out_thread = aio_out_thread; + sink_thread = aio_out_thread; continue; case 's': /* iso buffer size */ /* for iso, "-s 1025" and higher is high bandwidth */ @@ -1283,16 +1770,16 @@ int main(int argc, char **argv) { verbose++; continue; } - fprintf(stderr, - "usage: %s " + fprintf(stderr, "usage: %s " #ifdef AIO - "[-I interval] [-a num] [-s iso_size] " + "[-I interval] [-a num] [-s iso_size] " #endif - "[-p pattern] [-r serial] [-v]\n", + "[-p pattern] [-r serial] [-v]\n", argv[0]); return 1; } - if (chdir("/dev/gadget") < 0) { + if (chdir("/dev/gadget") < 0) + { perror("can't chdir /dev/gadget"); return 1; } @@ -1300,7 +1787,8 @@ int main(int argc, char **argv) { fd = init_device(); if (fd < 0) return 1; - fprintf(stderr, "/dev/gadget/%s ep0 configured\nserial=\"%s\"\n", DEVNAME, serial); + fprintf(stderr, "/dev/gadget/%s ep0 configured\nserial=\"%s\"\n", + DEVNAME, serial); fflush(stderr); (void)ep0_thread(&fd); return 0;