brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · aaca1f4 Raw
381 lines · c
1/*2 * This is free and unencumbered software released into the public domain.3 *4 * Anyone is free to copy, modify, publish, use, compile, sell, or5 * distribute this software, either in source code form or as a compiled6 * binary, for any purpose, commercial or non-commercial, and by any7 * means.8 *9 * In jurisdictions that recognize copyright laws, the author or authors10 * of this software dedicate any and all copyright interest in the11 * software to the public domain. We make this dedication for the benefit12 * of the public at large and to the detriment of our heirs and13 * successors. We intend this dedication to be an overt act of14 * relinquishment in perpetuity of all present and future rights to this15 * software under copyright law.16 *17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR23 * OTHER DEALINGS IN THE SOFTWARE.24 *25 * For more information, please refer to <http://unlicense.org/>26 */27 28#define _BSD_SOURCE /* for endian.h */29 30#include <endian.h>31#include <errno.h>32#include <fcntl.h>33#include <stdarg.h>34#include <stdio.h>35#include <stdlib.h>36#include <string.h>37#include <sys/ioctl.h>38#include <sys/stat.h>39#include <sys/types.h>40#include <sys/poll.h>41#include <unistd.h>42#include <stdbool.h>43#include <sys/eventfd.h>44 45#include "libaio.h"46#define IOCB_FLAG_RESFD         (1 << 0)47 48#include <linux/usb/functionfs.h>49 50#define BUF_LEN		819251#define BUFS_MAX	12852#define AIO_MAX		(BUFS_MAX*2)53 54/******************** Descriptors and Strings *******************************/55 56static const struct {57	struct usb_functionfs_descs_head_v2 header;58	__le32 fs_count;59	__le32 hs_count;60	struct {61		struct usb_interface_descriptor intf;62		struct usb_endpoint_descriptor_no_audio bulk_sink;63		struct usb_endpoint_descriptor_no_audio bulk_source;64	} __attribute__ ((__packed__)) fs_descs, hs_descs;65} __attribute__ ((__packed__)) descriptors = {66	.header = {67		.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),68		.flags = htole32(FUNCTIONFS_HAS_FS_DESC |69				     FUNCTIONFS_HAS_HS_DESC),70		.length = htole32(sizeof(descriptors)),71	},72	.fs_count = htole32(3),73	.fs_descs = {74		.intf = {75			.bLength = sizeof(descriptors.fs_descs.intf),76			.bDescriptorType = USB_DT_INTERFACE,77			.bNumEndpoints = 2,78			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,79			.iInterface = 1,80		},81		.bulk_sink = {82			.bLength = sizeof(descriptors.fs_descs.bulk_sink),83			.bDescriptorType = USB_DT_ENDPOINT,84			.bEndpointAddress = 1 | USB_DIR_IN,85			.bmAttributes = USB_ENDPOINT_XFER_BULK,86		},87		.bulk_source = {88			.bLength = sizeof(descriptors.fs_descs.bulk_source),89			.bDescriptorType = USB_DT_ENDPOINT,90			.bEndpointAddress = 2 | USB_DIR_OUT,91			.bmAttributes = USB_ENDPOINT_XFER_BULK,92		},93	},94	.hs_count = htole32(3),95	.hs_descs = {96		.intf = {97			.bLength = sizeof(descriptors.hs_descs.intf),98			.bDescriptorType = USB_DT_INTERFACE,99			.bNumEndpoints = 2,100			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,101			.iInterface = 1,102		},103		.bulk_sink = {104			.bLength = sizeof(descriptors.hs_descs.bulk_sink),105			.bDescriptorType = USB_DT_ENDPOINT,106			.bEndpointAddress = 1 | USB_DIR_IN,107			.bmAttributes = USB_ENDPOINT_XFER_BULK,108			.wMaxPacketSize = htole16(512),109		},110		.bulk_source = {111			.bLength = sizeof(descriptors.hs_descs.bulk_source),112			.bDescriptorType = USB_DT_ENDPOINT,113			.bEndpointAddress = 2 | USB_DIR_OUT,114			.bmAttributes = USB_ENDPOINT_XFER_BULK,115			.wMaxPacketSize = htole16(512),116		},117	},118};119 120#define STR_INTERFACE "AIO Test"121 122static const struct {123	struct usb_functionfs_strings_head header;124	struct {125		__le16 code;126		const char str1[sizeof(STR_INTERFACE)];127	} __attribute__ ((__packed__)) lang0;128} __attribute__ ((__packed__)) strings = {129	.header = {130		.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),131		.length = htole32(sizeof(strings)),132		.str_count = htole32(1),133		.lang_count = htole32(1),134	},135	.lang0 = {136		htole16(0x0409), /* en-us */137		STR_INTERFACE,138	},139};140 141/********************** Buffer structure *******************************/142 143struct io_buffer {144	struct iocb **iocb;145	unsigned char **buf;146	unsigned cnt;147	unsigned len;148	unsigned requested;149};150 151/******************** Endpoints handling *******************************/152 153static void display_event(struct usb_functionfs_event *event)154{155	static const char *const names[] = {156		[FUNCTIONFS_BIND] = "BIND",157		[FUNCTIONFS_UNBIND] = "UNBIND",158		[FUNCTIONFS_ENABLE] = "ENABLE",159		[FUNCTIONFS_DISABLE] = "DISABLE",160		[FUNCTIONFS_SETUP] = "SETUP",161		[FUNCTIONFS_SUSPEND] = "SUSPEND",162		[FUNCTIONFS_RESUME] = "RESUME",163	};164	switch (event->type) {165	case FUNCTIONFS_BIND:166	case FUNCTIONFS_UNBIND:167	case FUNCTIONFS_ENABLE:168	case FUNCTIONFS_DISABLE:169	case FUNCTIONFS_SETUP:170	case FUNCTIONFS_SUSPEND:171	case FUNCTIONFS_RESUME:172		printf("Event %s\n", names[event->type]);173	}174}175 176static void handle_ep0(int ep0, bool *ready)177{178	int ret;179	struct usb_functionfs_event event;180 181	ret = read(ep0, &event, sizeof(event));182	if (!ret) {183		perror("unable to read event from ep0");184		return;185	}186	display_event(&event);187	switch (event.type) {188	case FUNCTIONFS_SETUP:189		if (event.u.setup.bRequestType & USB_DIR_IN)190			write(ep0, NULL, 0);191		else192			read(ep0, NULL, 0);193		break;194 195	case FUNCTIONFS_ENABLE:196		*ready = true;197		break;198 199	case FUNCTIONFS_DISABLE:200		*ready = false;201		break;202 203	default:204		break;205	}206}207 208void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)209{210	unsigned i;211	iobuf->buf = malloc(n*sizeof(*iobuf->buf));212	iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));213	iobuf->cnt = n;214	iobuf->len = len;215	iobuf->requested = 0;216	for (i = 0; i < n; ++i) {217		iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));218		iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));219	}220	iobuf->cnt = n;221}222 223void delete_bufs(struct io_buffer *iobuf)224{225	unsigned i;226	for (i = 0; i < iobuf->cnt; ++i) {227		free(iobuf->buf[i]);228		free(iobuf->iocb[i]);229	}230	free(iobuf->buf);231	free(iobuf->iocb);232}233 234int main(int argc, char *argv[])235{236	int ret;237	unsigned i, j;238	char *ep_path;239 240	int ep0, ep1;241 242	io_context_t ctx;243 244	int evfd;245	fd_set rfds;246 247	struct io_buffer iobuf[2];248	int actual = 0;249	bool ready;250 251	if (argc != 2) {252		printf("ffs directory not specified!\n");253		return 1;254	}255 256	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);257	if (!ep_path) {258		perror("malloc");259		return 1;260	}261 262	/* open endpoint files */263	sprintf(ep_path, "%s/ep0", argv[1]);264	ep0 = open(ep_path, O_RDWR);265	if (ep0 < 0) {266		perror("unable to open ep0");267		return 1;268	}269	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {270		perror("unable do write descriptors");271		return 1;272	}273	if (write(ep0, &strings, sizeof(strings)) < 0) {274		perror("unable to write strings");275		return 1;276	}277	sprintf(ep_path, "%s/ep1", argv[1]);278	ep1 = open(ep_path, O_RDWR);279	if (ep1 < 0) {280		perror("unable to open ep1");281		return 1;282	}283 284	free(ep_path);285 286	memset(&ctx, 0, sizeof(ctx));287	/* setup aio context to handle up to AIO_MAX requests */288	if (io_setup(AIO_MAX, &ctx) < 0) {289		perror("unable to setup aio");290		return 1;291	}292 293	evfd = eventfd(0, 0);294	if (evfd < 0) {295		perror("unable to open eventfd");296		return 1;297	}298 299	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)300		init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);301 302	while (1) {303		FD_ZERO(&rfds);304		FD_SET(ep0, &rfds);305		FD_SET(evfd, &rfds);306 307		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,308			     &rfds, NULL, NULL, NULL);309		if (ret < 0) {310			if (errno == EINTR)311				continue;312			perror("select");313			break;314		}315 316		if (FD_ISSET(ep0, &rfds))317			handle_ep0(ep0, &ready);318 319		/* we are waiting for function ENABLE */320		if (!ready)321			continue;322 323		/*324		 * when we're preparing new data to submit,325		 * second buffer being transmitted326		 */327		for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {328			if (iobuf[i].requested)329				continue;330			/* prepare requests */331			for (j = 0; j < iobuf[i].cnt; ++j) {332				io_prep_pwrite(iobuf[i].iocb[j], ep1,333					       iobuf[i].buf[j],334					       iobuf[i].len, 0);335				/* enable eventfd notification */336				iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;337				iobuf[i].iocb[j]->u.c.resfd = evfd;338			}339			/* submit table of requests */340			ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);341			if (ret >= 0) {342				iobuf[i].requested = ret;343				printf("submit: %d requests buf: %d\n", ret, i);344			} else345				perror("unable to submit requests");346		}347 348		/* if event is ready to read */349		if (!FD_ISSET(evfd, &rfds))350			continue;351 352		uint64_t ev_cnt;353		ret = read(evfd, &ev_cnt, sizeof(ev_cnt));354		if (ret < 0) {355			perror("unable to read eventfd");356			break;357		}358 359		struct io_event e[BUFS_MAX];360		/* we read aio events */361		ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);362		if (ret > 0) /* if we got events */363			iobuf[actual].requested -= ret;364 365		/* if all req's from iocb completed */366		if (!iobuf[actual].requested)367			actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));368	}369 370	/* free resources */371 372	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)373		delete_bufs(&iobuf[i]);374	io_destroy(ctx);375 376	close(ep1);377	close(ep0);378 379	return 0;380}381