162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This is free and unencumbered software released into the public domain.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Anyone is free to copy, modify, publish, use, compile, sell, or
562306a36Sopenharmony_ci * distribute this software, either in source code form or as a compiled
662306a36Sopenharmony_ci * binary, for any purpose, commercial or non-commercial, and by any
762306a36Sopenharmony_ci * means.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * In jurisdictions that recognize copyright laws, the author or authors
1062306a36Sopenharmony_ci * of this software dedicate any and all copyright interest in the
1162306a36Sopenharmony_ci * software to the public domain. We make this dedication for the benefit
1262306a36Sopenharmony_ci * of the public at large and to the detriment of our heirs and
1362306a36Sopenharmony_ci * successors. We intend this dedication to be an overt act of
1462306a36Sopenharmony_ci * relinquishment in perpetuity of all present and future rights to this
1562306a36Sopenharmony_ci * software under copyright law.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1862306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1962306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2062306a36Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2162306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2262306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2362306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * For more information, please refer to <http://unlicense.org/>
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <libusb.h>
2962306a36Sopenharmony_ci#include <stdio.h>
3062306a36Sopenharmony_ci#include <string.h>
3162306a36Sopenharmony_ci#include <unistd.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define VENDOR	0x1d6b
3462306a36Sopenharmony_ci#define PRODUCT	0x0105
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define BUF_LEN		8192
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/*
3962306a36Sopenharmony_ci * struct test_state - describes test program state
4062306a36Sopenharmony_ci * @list: list of devices returned by libusb_get_device_list function
4162306a36Sopenharmony_ci * @found: pointer to struct describing tested device
4262306a36Sopenharmony_ci * @ctx: context, set to NULL
4362306a36Sopenharmony_ci * @handle: handle of tested device
4462306a36Sopenharmony_ci * @attached: indicates that device was attached to kernel, and has to be
4562306a36Sopenharmony_ci *            reattached at the end of test program
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct test_state {
4962306a36Sopenharmony_ci	libusb_device *found;
5062306a36Sopenharmony_ci	libusb_context *ctx;
5162306a36Sopenharmony_ci	libusb_device_handle *handle;
5262306a36Sopenharmony_ci	int attached;
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * test_init - initialize test program
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciint test_init(struct test_state *state)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int i, ret;
6262306a36Sopenharmony_ci	ssize_t cnt;
6362306a36Sopenharmony_ci	libusb_device **list;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	state->found = NULL;
6662306a36Sopenharmony_ci	state->ctx = NULL;
6762306a36Sopenharmony_ci	state->handle = NULL;
6862306a36Sopenharmony_ci	state->attached = 0;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ret = libusb_init(&state->ctx);
7162306a36Sopenharmony_ci	if (ret) {
7262306a36Sopenharmony_ci		printf("cannot init libusb: %s\n", libusb_error_name(ret));
7362306a36Sopenharmony_ci		return 1;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	cnt = libusb_get_device_list(state->ctx, &list);
7762306a36Sopenharmony_ci	if (cnt <= 0) {
7862306a36Sopenharmony_ci		printf("no devices found\n");
7962306a36Sopenharmony_ci		goto error1;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	for (i = 0; i < cnt; ++i) {
8362306a36Sopenharmony_ci		libusb_device *dev = list[i];
8462306a36Sopenharmony_ci		struct libusb_device_descriptor desc;
8562306a36Sopenharmony_ci		ret = libusb_get_device_descriptor(dev, &desc);
8662306a36Sopenharmony_ci		if (ret) {
8762306a36Sopenharmony_ci			printf("unable to get device descriptor: %s\n",
8862306a36Sopenharmony_ci			       libusb_error_name(ret));
8962306a36Sopenharmony_ci			goto error2;
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci		if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
9262306a36Sopenharmony_ci			state->found = dev;
9362306a36Sopenharmony_ci			break;
9462306a36Sopenharmony_ci		}
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (!state->found) {
9862306a36Sopenharmony_ci		printf("no devices found\n");
9962306a36Sopenharmony_ci		goto error2;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	ret = libusb_open(state->found, &state->handle);
10362306a36Sopenharmony_ci	if (ret) {
10462306a36Sopenharmony_ci		printf("cannot open device: %s\n", libusb_error_name(ret));
10562306a36Sopenharmony_ci		goto error2;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (libusb_claim_interface(state->handle, 0)) {
10962306a36Sopenharmony_ci		ret = libusb_detach_kernel_driver(state->handle, 0);
11062306a36Sopenharmony_ci		if (ret) {
11162306a36Sopenharmony_ci			printf("unable to detach kernel driver: %s\n",
11262306a36Sopenharmony_ci			       libusb_error_name(ret));
11362306a36Sopenharmony_ci			goto error3;
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci		state->attached = 1;
11662306a36Sopenharmony_ci		ret = libusb_claim_interface(state->handle, 0);
11762306a36Sopenharmony_ci		if (ret) {
11862306a36Sopenharmony_ci			printf("cannot claim interface: %s\n",
11962306a36Sopenharmony_ci			       libusb_error_name(ret));
12062306a36Sopenharmony_ci			goto error4;
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cierror4:
12762306a36Sopenharmony_ci	if (state->attached == 1)
12862306a36Sopenharmony_ci		libusb_attach_kernel_driver(state->handle, 0);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cierror3:
13162306a36Sopenharmony_ci	libusb_close(state->handle);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cierror2:
13462306a36Sopenharmony_ci	libusb_free_device_list(list, 1);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cierror1:
13762306a36Sopenharmony_ci	libusb_exit(state->ctx);
13862306a36Sopenharmony_ci	return 1;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * test_exit - cleanup test program
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_civoid test_exit(struct test_state *state)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	libusb_release_interface(state->handle, 0);
14862306a36Sopenharmony_ci	if (state->attached == 1)
14962306a36Sopenharmony_ci		libusb_attach_kernel_driver(state->handle, 0);
15062306a36Sopenharmony_ci	libusb_close(state->handle);
15162306a36Sopenharmony_ci	libusb_exit(state->ctx);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciint main(void)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct test_state state;
15762306a36Sopenharmony_ci	struct libusb_config_descriptor *conf;
15862306a36Sopenharmony_ci	struct libusb_interface_descriptor const *iface;
15962306a36Sopenharmony_ci	unsigned char addr;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (test_init(&state))
16262306a36Sopenharmony_ci		return 1;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	libusb_get_config_descriptor(state.found, 0, &conf);
16562306a36Sopenharmony_ci	iface = &conf->interface[0].altsetting[0];
16662306a36Sopenharmony_ci	addr = iface->endpoint[0].bEndpointAddress;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	while (1) {
16962306a36Sopenharmony_ci		static unsigned char buffer[BUF_LEN];
17062306a36Sopenharmony_ci		int bytes;
17162306a36Sopenharmony_ci		libusb_bulk_transfer(state.handle, addr, buffer, BUF_LEN,
17262306a36Sopenharmony_ci				     &bytes, 500);
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	test_exit(&state);
17562306a36Sopenharmony_ci}
176