mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
380
tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
Normal file
380
tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
#define _BSD_SOURCE /* for endian.h */
|
||||
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
#include "libaio.h"
|
||||
#define IOCB_FLAG_RESFD (1 << 0)
|
||||
|
||||
#include <linux/usb/functionfs.h>
|
||||
|
||||
#define BUF_LEN 8192
|
||||
#define BUFS_MAX 128
|
||||
#define AIO_MAX (BUFS_MAX*2)
|
||||
|
||||
/******************** Descriptors and Strings *******************************/
|
||||
|
||||
static const struct {
|
||||
struct usb_functionfs_descs_head_v2 header;
|
||||
__le32 fs_count;
|
||||
__le32 hs_count;
|
||||
struct {
|
||||
struct usb_interface_descriptor intf;
|
||||
struct usb_endpoint_descriptor_no_audio bulk_sink;
|
||||
struct usb_endpoint_descriptor_no_audio bulk_source;
|
||||
} __attribute__ ((__packed__)) fs_descs, hs_descs;
|
||||
} __attribute__ ((__packed__)) descriptors = {
|
||||
.header = {
|
||||
.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
|
||||
.flags = htole32(FUNCTIONFS_HAS_FS_DESC |
|
||||
FUNCTIONFS_HAS_HS_DESC),
|
||||
.length = htole32(sizeof(descriptors)),
|
||||
},
|
||||
.fs_count = htole32(3),
|
||||
.fs_descs = {
|
||||
.intf = {
|
||||
.bLength = sizeof(descriptors.fs_descs.intf),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.iInterface = 1,
|
||||
},
|
||||
.bulk_sink = {
|
||||
.bLength = sizeof(descriptors.fs_descs.bulk_sink),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 1 | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
},
|
||||
.bulk_source = {
|
||||
.bLength = sizeof(descriptors.fs_descs.bulk_source),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 2 | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
},
|
||||
},
|
||||
.hs_count = htole32(3),
|
||||
.hs_descs = {
|
||||
.intf = {
|
||||
.bLength = sizeof(descriptors.hs_descs.intf),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.iInterface = 1,
|
||||
},
|
||||
.bulk_sink = {
|
||||
.bLength = sizeof(descriptors.hs_descs.bulk_sink),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 1 | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = htole16(512),
|
||||
},
|
||||
.bulk_source = {
|
||||
.bLength = sizeof(descriptors.hs_descs.bulk_source),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 2 | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = htole16(512),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#define STR_INTERFACE "AIO Test"
|
||||
|
||||
static const struct {
|
||||
struct usb_functionfs_strings_head header;
|
||||
struct {
|
||||
__le16 code;
|
||||
const char str1[sizeof(STR_INTERFACE)];
|
||||
} __attribute__ ((__packed__)) lang0;
|
||||
} __attribute__ ((__packed__)) strings = {
|
||||
.header = {
|
||||
.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
|
||||
.length = htole32(sizeof(strings)),
|
||||
.str_count = htole32(1),
|
||||
.lang_count = htole32(1),
|
||||
},
|
||||
.lang0 = {
|
||||
htole16(0x0409), /* en-us */
|
||||
STR_INTERFACE,
|
||||
},
|
||||
};
|
||||
|
||||
/********************** Buffer structure *******************************/
|
||||
|
||||
struct io_buffer {
|
||||
struct iocb **iocb;
|
||||
unsigned char **buf;
|
||||
unsigned cnt;
|
||||
unsigned len;
|
||||
unsigned requested;
|
||||
};
|
||||
|
||||
/******************** Endpoints handling *******************************/
|
||||
|
||||
static void display_event(struct usb_functionfs_event *event)
|
||||
{
|
||||
static const char *const names[] = {
|
||||
[FUNCTIONFS_BIND] = "BIND",
|
||||
[FUNCTIONFS_UNBIND] = "UNBIND",
|
||||
[FUNCTIONFS_ENABLE] = "ENABLE",
|
||||
[FUNCTIONFS_DISABLE] = "DISABLE",
|
||||
[FUNCTIONFS_SETUP] = "SETUP",
|
||||
[FUNCTIONFS_SUSPEND] = "SUSPEND",
|
||||
[FUNCTIONFS_RESUME] = "RESUME",
|
||||
};
|
||||
switch (event->type) {
|
||||
case FUNCTIONFS_BIND:
|
||||
case FUNCTIONFS_UNBIND:
|
||||
case FUNCTIONFS_ENABLE:
|
||||
case FUNCTIONFS_DISABLE:
|
||||
case FUNCTIONFS_SETUP:
|
||||
case FUNCTIONFS_SUSPEND:
|
||||
case FUNCTIONFS_RESUME:
|
||||
printf("Event %s\n", names[event->type]);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ep0(int ep0, bool *ready)
|
||||
{
|
||||
int ret;
|
||||
struct usb_functionfs_event event;
|
||||
|
||||
ret = read(ep0, &event, sizeof(event));
|
||||
if (!ret) {
|
||||
perror("unable to read event from ep0");
|
||||
return;
|
||||
}
|
||||
display_event(&event);
|
||||
switch (event.type) {
|
||||
case FUNCTIONFS_SETUP:
|
||||
if (event.u.setup.bRequestType & USB_DIR_IN)
|
||||
write(ep0, NULL, 0);
|
||||
else
|
||||
read(ep0, NULL, 0);
|
||||
break;
|
||||
|
||||
case FUNCTIONFS_ENABLE:
|
||||
*ready = true;
|
||||
break;
|
||||
|
||||
case FUNCTIONFS_DISABLE:
|
||||
*ready = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
iobuf->buf = malloc(n*sizeof(*iobuf->buf));
|
||||
iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
|
||||
iobuf->cnt = n;
|
||||
iobuf->len = len;
|
||||
iobuf->requested = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
|
||||
iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
|
||||
}
|
||||
iobuf->cnt = n;
|
||||
}
|
||||
|
||||
void delete_bufs(struct io_buffer *iobuf)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < iobuf->cnt; ++i) {
|
||||
free(iobuf->buf[i]);
|
||||
free(iobuf->iocb[i]);
|
||||
}
|
||||
free(iobuf->buf);
|
||||
free(iobuf->iocb);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
unsigned i, j;
|
||||
char *ep_path;
|
||||
|
||||
int ep0, ep1;
|
||||
|
||||
io_context_t ctx;
|
||||
|
||||
int evfd;
|
||||
fd_set rfds;
|
||||
|
||||
struct io_buffer iobuf[2];
|
||||
int actual = 0;
|
||||
bool ready;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("ffs directory not specified!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
|
||||
if (!ep_path) {
|
||||
perror("malloc");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* open endpoint files */
|
||||
sprintf(ep_path, "%s/ep0", argv[1]);
|
||||
ep0 = open(ep_path, O_RDWR);
|
||||
if (ep0 < 0) {
|
||||
perror("unable to open ep0");
|
||||
return 1;
|
||||
}
|
||||
if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
|
||||
perror("unable do write descriptors");
|
||||
return 1;
|
||||
}
|
||||
if (write(ep0, &strings, sizeof(strings)) < 0) {
|
||||
perror("unable to write strings");
|
||||
return 1;
|
||||
}
|
||||
sprintf(ep_path, "%s/ep1", argv[1]);
|
||||
ep1 = open(ep_path, O_RDWR);
|
||||
if (ep1 < 0) {
|
||||
perror("unable to open ep1");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(ep_path);
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
/* setup aio context to handle up to AIO_MAX requests */
|
||||
if (io_setup(AIO_MAX, &ctx) < 0) {
|
||||
perror("unable to setup aio");
|
||||
return 1;
|
||||
}
|
||||
|
||||
evfd = eventfd(0, 0);
|
||||
if (evfd < 0) {
|
||||
perror("unable to open eventfd");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
|
||||
init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ep0, &rfds);
|
||||
FD_SET(evfd, &rfds);
|
||||
|
||||
ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
|
||||
&rfds, NULL, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
perror("select");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(ep0, &rfds))
|
||||
handle_ep0(ep0, &ready);
|
||||
|
||||
/* we are waiting for function ENABLE */
|
||||
if (!ready)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* when we're preparing new data to submit,
|
||||
* second buffer being transmitted
|
||||
*/
|
||||
for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
|
||||
if (iobuf[i].requested)
|
||||
continue;
|
||||
/* prepare requests */
|
||||
for (j = 0; j < iobuf[i].cnt; ++j) {
|
||||
io_prep_pwrite(iobuf[i].iocb[j], ep1,
|
||||
iobuf[i].buf[j],
|
||||
iobuf[i].len, 0);
|
||||
/* enable eventfd notification */
|
||||
iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
|
||||
iobuf[i].iocb[j]->u.c.resfd = evfd;
|
||||
}
|
||||
/* submit table of requests */
|
||||
ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
|
||||
if (ret >= 0) {
|
||||
iobuf[i].requested = ret;
|
||||
printf("submit: %d requests buf: %d\n", ret, i);
|
||||
} else
|
||||
perror("unable to submit reqests");
|
||||
}
|
||||
|
||||
/* if event is ready to read */
|
||||
if (!FD_ISSET(evfd, &rfds))
|
||||
continue;
|
||||
|
||||
uint64_t ev_cnt;
|
||||
ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
|
||||
if (ret < 0) {
|
||||
perror("unable to read eventfd");
|
||||
break;
|
||||
}
|
||||
|
||||
struct io_event e[BUFS_MAX];
|
||||
/* we read aio events */
|
||||
ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
|
||||
if (ret > 0) /* if we got events */
|
||||
iobuf[actual].requested -= ret;
|
||||
|
||||
/* if all req's from iocb completed */
|
||||
if (!iobuf[actual].requested)
|
||||
actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
|
||||
}
|
||||
|
||||
/* free resources */
|
||||
|
||||
for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
|
||||
delete_bufs(&iobuf[i]);
|
||||
io_destroy(ctx);
|
||||
|
||||
close(ep1);
|
||||
close(ep0);
|
||||
|
||||
return 0;
|
||||
}
|
13
tools/usb/ffs-aio-example/multibuff/host_app/Makefile
Normal file
13
tools/usb/ffs-aio-example/multibuff/host_app/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
CC = gcc
|
||||
LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
|
||||
LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
|
||||
WARNINGS = -Wall -Wextra
|
||||
CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
|
||||
LDFLAGS = $(LIBUSB_LIBS)
|
||||
|
||||
all: test
|
||||
%: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) test
|
173
tools/usb/ffs-aio-example/multibuff/host_app/test.c
Normal file
173
tools/usb/ffs-aio-example/multibuff/host_app/test.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
#include <libusb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define VENDOR 0x1d6b
|
||||
#define PRODUCT 0x0105
|
||||
|
||||
/* endpoints indexes */
|
||||
|
||||
#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||
|
||||
#define BUF_LEN 8192
|
||||
|
||||
/*
|
||||
* struct test_state - describes test program state
|
||||
* @list: list of devices returned by libusb_get_device_list function
|
||||
* @found: pointer to struct describing tested device
|
||||
* @ctx: context, set to NULL
|
||||
* @handle: handle of tested device
|
||||
* @attached: indicates that device was attached to kernel, and has to be
|
||||
* reattached at the end of test program
|
||||
*/
|
||||
|
||||
struct test_state {
|
||||
libusb_device *found;
|
||||
libusb_context *ctx;
|
||||
libusb_device_handle *handle;
|
||||
int attached;
|
||||
};
|
||||
|
||||
/*
|
||||
* test_init - initialize test program
|
||||
*/
|
||||
|
||||
int test_init(struct test_state *state)
|
||||
{
|
||||
int i, ret;
|
||||
ssize_t cnt;
|
||||
libusb_device **list;
|
||||
|
||||
state->found = NULL;
|
||||
state->ctx = NULL;
|
||||
state->handle = NULL;
|
||||
state->attached = 0;
|
||||
|
||||
ret = libusb_init(&state->ctx);
|
||||
if (ret) {
|
||||
printf("cannot init libusb: %s\n", libusb_error_name(ret));
|
||||
return 1;
|
||||
}
|
||||
|
||||
cnt = libusb_get_device_list(state->ctx, &list);
|
||||
if (cnt <= 0) {
|
||||
printf("no devices found\n");
|
||||
goto error1;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
libusb_device *dev = list[i];
|
||||
struct libusb_device_descriptor desc;
|
||||
ret = libusb_get_device_descriptor(dev, &desc);
|
||||
if (ret) {
|
||||
printf("unable to get device descriptor: %s\n",
|
||||
libusb_error_name(ret));
|
||||
goto error2;
|
||||
}
|
||||
if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
|
||||
state->found = dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!state->found) {
|
||||
printf("no devices found\n");
|
||||
goto error2;
|
||||
}
|
||||
|
||||
ret = libusb_open(state->found, &state->handle);
|
||||
if (ret) {
|
||||
printf("cannot open device: %s\n", libusb_error_name(ret));
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if (libusb_claim_interface(state->handle, 0)) {
|
||||
ret = libusb_detach_kernel_driver(state->handle, 0);
|
||||
if (ret) {
|
||||
printf("unable to detach kernel driver: %s\n",
|
||||
libusb_error_name(ret));
|
||||
goto error3;
|
||||
}
|
||||
state->attached = 1;
|
||||
ret = libusb_claim_interface(state->handle, 0);
|
||||
if (ret) {
|
||||
printf("cannot claim interface: %s\n",
|
||||
libusb_error_name(ret));
|
||||
goto error4;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error4:
|
||||
if (state->attached == 1)
|
||||
libusb_attach_kernel_driver(state->handle, 0);
|
||||
|
||||
error3:
|
||||
libusb_close(state->handle);
|
||||
|
||||
error2:
|
||||
libusb_free_device_list(list, 1);
|
||||
|
||||
error1:
|
||||
libusb_exit(state->ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_exit - cleanup test program
|
||||
*/
|
||||
|
||||
void test_exit(struct test_state *state)
|
||||
{
|
||||
libusb_release_interface(state->handle, 0);
|
||||
if (state->attached == 1)
|
||||
libusb_attach_kernel_driver(state->handle, 0);
|
||||
libusb_close(state->handle);
|
||||
libusb_exit(state->ctx);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct test_state state;
|
||||
|
||||
if (test_init(&state))
|
||||
return 1;
|
||||
|
||||
while (1) {
|
||||
static unsigned char buffer[BUF_LEN];
|
||||
int bytes;
|
||||
libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
|
||||
&bytes, 500);
|
||||
}
|
||||
test_exit(&state);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue