On Wed, Jan 29 2014, Robert Baldyga wrote: > +++ b/tools/usb/aio_multibuff/device_app/aio_multibuff.c
> +#define BUF_LEN 8192
> +#define BUFS_MAX 128
> +#define AIO_MAX (BUFS_MAX*2)
> +
> +struct iocb *iocb1[AIO_MAX];
> +struct iocb *iocb2[AIO_MAX];
> +
> +unsigned char *buf1[BUFS_MAX];
> +unsigned char *buf2[BUFS_MAX];
Why are there twice as many iocb structures as there are buffers?
> +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]);
> + default:
> + break;
> + }
Weird indent level throughout the function.
> +}
> +
> +static void handle_ep0(int ep0, bool *ready)
> +{
> + struct usb_functionfs_event event;
> + int ret;
> +
> + struct pollfd pfds[1];
> + pfds[0].fd = ep0;
> + pfds[0].events = POLLIN;
> +
> + ret = poll(pfds, 1, 0);
> +
> + if (ret && (pfds[0].revents & POLLIN)) {
> + ret = read(ep0, &event, sizeof(struct usb_functionfs_event));
ret = read(ep0, &event, sizeof(event));
> + if (!ret)
> + return;
At the very least call perror.
> + 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;
> + }
> + }
> +}
> +int main(int argc, char *argv[])
> +{
> + int i, ret;
> + char ep_path[64];
Better yet, allocate this dynamically. Just before the first snprintf.
> +
> + int ep0, ep1;
> +
> + io_context_t ctx;
> +
> + int requested1 = 0, requested2 = 0;
> + int actual;
> + bool ready;
> +
> + if (argc != 2) {
> + printf("ffs directory not specified!\n");
> + return 1;
> + }
> +
> + /* open endpoint files */
ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
if (!ep_path) {
perror("malloc");
return 1;
}
At this point you could get away with sprintf.
> + snprintf(ep_path, sizeof(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;
> + }
> + snprintf(ep_path, sizeof(ep_path), "%s/ep1", argv[1]);
> + ep1 = open(ep_path, O_RDWR);
> + if (ep1 < 0) {
> + perror("unable to open ep1");
> + return 1;
> + }
> +
> + memset(&ctx, 0, sizeof(ctx));
> + /* setup aio context to handle up to AIO_MAX requests */
> + io_setup(AIO_MAX, &ctx);
> +
> + init_bufs();
> +
> + while (1) {
> + 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
> + */
> + if (!requested1) { /* if all req's from iocb1 completed */
> + actual = 2;
> + for (i = 0; i < BUFS_MAX; ++i) /* prepare requests */
> + io_prep_pwrite(iocb1[i], ep1, buf1[i],
> + BUF_LEN, 0);
> + /* submit table of requests */
> + ret = io_submit(ctx, BUFS_MAX, iocb1);
> + requested1 = ret;
> + printf("submit: %d requests from buf 1\n", ret);
> + }
> + if (!requested2) { /* if all req's from iocb2 completed */
> + actual = 1;
> + for (i = 0; i < BUFS_MAX; ++i) /* prepare requests */
> + io_prep_pwrite(iocb2[i], ep1, buf2[i],
> + BUF_LEN, 0);
> + /* submit table of requests */
> + ret = io_submit(ctx, BUFS_MAX, iocb2);
> + requested2 = ret;
> + printf("submit: %d requests from buf 2\n", ret);
> + }
> + /* if something was submitted we wait for event */
> + if (requested1 || requested2) {
> + struct io_event e;
> + struct timespec timeout = {0, 1000};
> + /* we wait for one event */
> + ret = io_getevents(ctx, 1, 1, &e, &timeout);
What's the purpose of the timeout?
> + if (ret > 0) { /* if we got event */
> + if (actual == 1)
> + requested1--;
> + else
> + requested2--;
> + }
This whole loop would look cleaner if buf, iocb and requested variables
were two-element arrays. Or better yet, if you had a structure with
a buffer, iocb and requested count. With a structure, you could easily
go away without a global variables, if init_bufs and delete_bufs took
the structure as an argument.
> + }
> + }
> +
> + /* free resources */
> +
> + delete_bufs();
> + io_destroy(ctx);
> +
> + close(ep1);
> + close(ep0);
> +
> + return 0;
> +}
Haven't looked at the other files.
--
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michał “mina86” Nazarewicz (o o)
ooo +--<[email protected]>--<xmpp:[email protected]>--ooO--(_)--Ooo--
signature.asc
Description: PGP signature
