source: mainline/uspace/drv/bus/usb/usbdiag/tests.c@ ddbd088

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ddbd088 was bf0398c, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

usbdiag: endianity is resolved at runtime

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * Copyright (c) 2017 Petr Manek
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbdiag
30 * @{
31 */
32/**
33 * @file
34 * Code for executing diagnostic tests.
35 */
36#include <errno.h>
37#include <str_error.h>
38#include <usb/debug.h>
39#include <usbdiag_iface.h>
40#include <time.h>
41#include "device.h"
42#include "tests.h"
43
44#define NAME "usbdiag"
45
46static int burst_in_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
47{
48 if (!pipe)
49 return EBADMEM;
50
51 char *buffer = (char *) malloc(size);
52 if (!buffer)
53 return ENOMEM;
54
55 // TODO: Are we sure that no other test is running on this endpoint?
56
57 usb_log_info("Performing %s IN burst test.", usb_str_transfer_type(pipe->desc.transfer_type));
58
59 int rc = EOK;
60 struct timeval start_time;
61 gettimeofday(&start_time, NULL);
62
63 for (int i = 0; i < cycles; ++i) {
64 // Read device's response.
65 size_t remaining = size;
66 size_t transferred;
67
68 while (remaining > 0) {
69 if ((rc = usb_pipe_read(pipe, buffer + size - remaining, remaining, &transferred))) {
70 usb_log_error("Read of %s IN endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
71 break;
72 }
73
74 if (transferred > remaining) {
75 usb_log_error("Read of %s IN endpoint returned more data than expected.", usb_str_transfer_type(pipe->desc.transfer_type));
76 rc = EINVAL;
77 break;
78 }
79
80 remaining -= transferred;
81 }
82
83 if (rc)
84 break;
85 }
86
87 struct timeval final_time;
88 gettimeofday(&final_time, NULL);
89 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
90 ((final_time.tv_sec - start_time.tv_sec) * 1000);
91
92 usb_log_info("Burst test on %s IN endpoint completed in %lu ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
93
94 free(buffer);
95 if (duration)
96 *duration = in_duration;
97
98 return rc;
99}
100
101static int burst_out_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
102{
103 if (!pipe)
104 return EBADMEM;
105
106 char *buffer = (char *) malloc(size);
107 if (!buffer)
108 return ENOMEM;
109
110 memset(buffer, 42, size);
111
112 // TODO: Are we sure that no other test is running on this endpoint?
113
114 usb_log_info("Performing %s OUT burst test.", usb_str_transfer_type(pipe->desc.transfer_type));
115
116 int rc = EOK;
117 struct timeval start_time;
118 gettimeofday(&start_time, NULL);
119
120 for (int i = 0; i < cycles; ++i) {
121 // Write buffer to device.
122 if ((rc = usb_pipe_write(pipe, buffer, size))) {
123 usb_log_error("Write to %s OUT endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
124 break;
125 }
126 }
127
128 struct timeval final_time;
129 gettimeofday(&final_time, NULL);
130 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
131 ((final_time.tv_sec - start_time.tv_sec) * 1000);
132
133 usb_log_info("Burst test on %s OUT endpoint completed in %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
134
135 free(buffer);
136 if (duration)
137 *duration = in_duration;
138
139 return rc;
140}
141
142static const uint32_t test_data_src = 0xDEADBEEF;
143
144static int data_in_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
145{
146 if (!pipe)
147 return EBADMEM;
148
149 const uint32_t test_data = uint32_host2usb(test_data_src);
150
151 if (size % sizeof(test_data))
152 return EINVAL;
153
154 char *buffer = (char *) malloc(size);
155 if (!buffer)
156 return ENOMEM;
157
158 // TODO: Are we sure that no other test is running on this endpoint?
159
160 usb_log_info("Performing %s IN data test.", usb_str_transfer_type(pipe->desc.transfer_type));
161
162 int rc = EOK;
163 struct timeval start_time;
164 gettimeofday(&start_time, NULL);
165
166 for (int i = 0; i < cycles; ++i) {
167 // Read device's response.
168 size_t remaining = size;
169 size_t transferred;
170
171 while (remaining > 0) {
172 if ((rc = usb_pipe_read(pipe, buffer + size - remaining, remaining, &transferred))) {
173 usb_log_error("Read of %s IN endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
174 break;
175 }
176
177 if (transferred > remaining) {
178 usb_log_error("Read of %s IN endpoint returned more data than expected.", usb_str_transfer_type(pipe->desc.transfer_type));
179 rc = EINVAL;
180 break;
181 }
182
183 remaining -= transferred;
184 }
185
186 if (rc)
187 break;
188
189 for (size_t i = 0; i < size; i += sizeof(test_data)) {
190 if (*(uint32_t *)(buffer + i) != test_data) {
191 usb_log_error("Read of %s IN endpoint returned "
192 "invald data at address %zu.",
193 usb_str_transfer_type(pipe->desc.transfer_type), i);
194 rc = EINVAL;
195 break;
196 }
197 }
198
199 if (rc)
200 break;
201 }
202
203 struct timeval final_time;
204 gettimeofday(&final_time, NULL);
205 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
206 ((final_time.tv_sec - start_time.tv_sec) * 1000);
207
208 usb_log_info("Data test on %s IN endpoint completed in %lu ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
209
210 free(buffer);
211 if (duration)
212 *duration = in_duration;
213
214 return rc;
215}
216
217static int data_out_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
218{
219 if (!pipe)
220 return EBADMEM;
221
222 const uint32_t test_data = uint32_host2usb(test_data_src);
223
224 if (size % sizeof(test_data))
225 return EINVAL;
226
227 char *buffer = (char *) malloc(size);
228 if (!buffer)
229 return ENOMEM;
230
231 for (size_t i = 0; i < size; i += sizeof(test_data)) {
232 memcpy(buffer + i, &test_data, sizeof(test_data));
233 }
234
235 // TODO: Are we sure that no other test is running on this endpoint?
236
237 usb_log_info("Performing %s OUT data test.", usb_str_transfer_type(pipe->desc.transfer_type));
238
239 int rc = EOK;
240 struct timeval start_time;
241 gettimeofday(&start_time, NULL);
242
243 for (int i = 0; i < cycles; ++i) {
244 // Write buffer to device.
245 if ((rc = usb_pipe_write(pipe, buffer, size))) {
246 usb_log_error("Write to %s OUT endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
247 break;
248 }
249 }
250
251 struct timeval final_time;
252 gettimeofday(&final_time, NULL);
253 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
254 ((final_time.tv_sec - start_time.tv_sec) * 1000);
255
256 usb_log_info("Data test on %s OUT endpoint completed in %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
257
258 free(buffer);
259 if (duration)
260 *duration = in_duration;
261
262 return rc;
263}
264
265int usbdiag_burst_test_intr_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
266{
267 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
268 if (!dev)
269 return EBADMEM;
270
271 return burst_in_test(dev->intr_in, cycles, size, duration);
272}
273
274int usbdiag_burst_test_intr_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
275{
276 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
277 if (!dev)
278 return EBADMEM;
279
280 return burst_out_test(dev->intr_out, cycles, size, duration);
281}
282
283int usbdiag_burst_test_bulk_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
284{
285 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
286 if (!dev)
287 return EBADMEM;
288
289 return burst_in_test(dev->bulk_in, cycles, size, duration);
290}
291
292int usbdiag_burst_test_bulk_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
293{
294 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
295 if (!dev)
296 return EBADMEM;
297
298 return burst_out_test(dev->bulk_out, cycles, size, duration);
299}
300
301int usbdiag_burst_test_isoch_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
302{
303 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
304 if (!dev)
305 return EBADMEM;
306
307 return burst_in_test(dev->isoch_in, cycles, size, duration);
308}
309
310int usbdiag_burst_test_isoch_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
311{
312 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
313 if (!dev)
314 return EBADMEM;
315
316 return burst_out_test(dev->isoch_out, cycles, size, duration);
317}
318
319int usbdiag_data_test_intr_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
320{
321 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
322 if (!dev)
323 return EBADMEM;
324
325 return data_in_test(dev->intr_in, cycles, size, duration);
326}
327
328int usbdiag_data_test_intr_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
329{
330 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
331 if (!dev)
332 return EBADMEM;
333
334 return data_out_test(dev->intr_out, cycles, size, duration);
335}
336
337int usbdiag_data_test_bulk_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
338{
339 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
340 if (!dev)
341 return EBADMEM;
342
343 return data_in_test(dev->bulk_in, cycles, size, duration);
344}
345
346int usbdiag_data_test_bulk_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
347{
348 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
349 if (!dev)
350 return EBADMEM;
351
352 return data_out_test(dev->bulk_out, cycles, size, duration);
353}
354
355int usbdiag_data_test_isoch_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
356{
357 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
358 if (!dev)
359 return EBADMEM;
360
361 return data_in_test(dev->isoch_in, cycles, size, duration);
362}
363
364int usbdiag_data_test_isoch_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
365{
366 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
367 if (!dev)
368 return EBADMEM;
369
370 return data_out_test(dev->isoch_out, cycles, size, duration);
371}
372
373/**
374 * @}
375 */
Note: See TracBrowser for help on using the repository browser.