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, or
5  * distribute this software, either in source code form or as a compiled
6  * binary, for any purpose, commercial or non-commercial, and by any
7  * means.
8  *
9  * In jurisdictions that recognize copyright laws, the author or authors
10  * of this software dedicate any and all copyright interest in the
11  * software to the public domain. We make this dedication for the benefit
12  * of the public at large and to the detriment of our heirs and
13  * successors. We intend this dedication to be an overt act of
14  * relinquishment in perpetuity of all present and future rights to this
15  * 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 OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * 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 OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * For more information, please refer to <http://unlicense.org/>
26  */
27 
28 #include <libusb.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #define VENDOR	0x1d6b
34 #define PRODUCT	0x0105
35 
36 #define BUF_LEN		8192
37 
38 /*
39  * struct test_state - describes test program state
40  * @list: list of devices returned by libusb_get_device_list function
41  * @found: pointer to struct describing tested device
42  * @ctx: context, set to NULL
43  * @handle: handle of tested device
44  * @attached: indicates that device was attached to kernel, and has to be
45  *            reattached at the end of test program
46  */
47 
48 struct test_state {
49 	libusb_device *found;
50 	libusb_context *ctx;
51 	libusb_device_handle *handle;
52 	int attached;
53 };
54 
55 /*
56  * test_init - initialize test program
57  */
58 
59 int test_init(struct test_state *state)
60 {
61 	int i, ret;
62 	ssize_t cnt;
63 	libusb_device **list;
64 
65 	state->found = NULL;
66 	state->ctx = NULL;
67 	state->handle = NULL;
68 	state->attached = 0;
69 
70 	ret = libusb_init(&state->ctx);
71 	if (ret) {
72 		printf("cannot init libusb: %s\n", libusb_error_name(ret));
73 		return 1;
74 	}
75 
76 	cnt = libusb_get_device_list(state->ctx, &list);
77 	if (cnt <= 0) {
78 		printf("no devices found\n");
79 		goto error1;
80 	}
81 
82 	for (i = 0; i < cnt; ++i) {
83 		libusb_device *dev = list[i];
84 		struct libusb_device_descriptor desc;
85 		ret = libusb_get_device_descriptor(dev, &desc);
86 		if (ret) {
87 			printf("unable to get device descriptor: %s\n",
88 			       libusb_error_name(ret));
89 			goto error2;
90 		}
91 		if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
92 			state->found = dev;
93 			break;
94 		}
95 	}
96 
97 	if (!state->found) {
98 		printf("no devices found\n");
99 		goto error2;
100 	}
101 
102 	ret = libusb_open(state->found, &state->handle);
103 	if (ret) {
104 		printf("cannot open device: %s\n", libusb_error_name(ret));
105 		goto error2;
106 	}
107 
108 	if (libusb_claim_interface(state->handle, 0)) {
109 		ret = libusb_detach_kernel_driver(state->handle, 0);
110 		if (ret) {
111 			printf("unable to detach kernel driver: %s\n",
112 			       libusb_error_name(ret));
113 			goto error3;
114 		}
115 		state->attached = 1;
116 		ret = libusb_claim_interface(state->handle, 0);
117 		if (ret) {
118 			printf("cannot claim interface: %s\n",
119 			       libusb_error_name(ret));
120 			goto error4;
121 		}
122 	}
123 
124 	return 0;
125 
126 error4:
127 	if (state->attached == 1)
128 		libusb_attach_kernel_driver(state->handle, 0);
129 
130 error3:
131 	libusb_close(state->handle);
132 
133 error2:
134 	libusb_free_device_list(list, 1);
135 
136 error1:
137 	libusb_exit(state->ctx);
138 	return 1;
139 }
140 
141 /*
142  * test_exit - cleanup test program
143  */
144 
145 void test_exit(struct test_state *state)
146 {
147 	libusb_release_interface(state->handle, 0);
148 	if (state->attached == 1)
149 		libusb_attach_kernel_driver(state->handle, 0);
150 	libusb_close(state->handle);
151 	libusb_exit(state->ctx);
152 }
153 
154 int main(void)
155 {
156 	struct test_state state;
157 	struct libusb_config_descriptor *conf;
158 	struct libusb_interface_descriptor const *iface;
159 	unsigned char in_addr, out_addr;
160 
161 	if (test_init(&state))
162 		return 1;
163 
164 	libusb_get_config_descriptor(state.found, 0, &conf);
165 	iface = &conf->interface[0].altsetting[0];
166 	in_addr = iface->endpoint[0].bEndpointAddress;
167 	out_addr = iface->endpoint[1].bEndpointAddress;
168 
169 	while (1) {
170 		static unsigned char buffer[BUF_LEN];
171 		int bytes;
172 		libusb_bulk_transfer(state.handle, in_addr, buffer, BUF_LEN,
173 				     &bytes, 500);
174 		libusb_bulk_transfer(state.handle, out_addr, buffer, BUF_LEN,
175 				     &bytes, 500);
176 	}
177 	test_exit(&state);
178 }
179