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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bf7b747 was bf7b747, checked in by Petr Manek <petr.manek@…>, 8 years ago

usbdiag: add data validity tests

  • Property mode set to 100644
File size: 10.2 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\n", 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.\n", 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\n", 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 = uint32_host2usb(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 if (size % sizeof(test_data))
150 return EINVAL;
151
152 char *buffer = (char *) malloc(size);
153 if (!buffer)
154 return ENOMEM;
155
156 // TODO: Are we sure that no other test is running on this endpoint?
157
158 usb_log_info("Performing %s IN data test.", usb_str_transfer_type(pipe->desc.transfer_type));
159
160 int rc = EOK;
161 struct timeval start_time;
162 gettimeofday(&start_time, NULL);
163
164 for (int i = 0; i < cycles; ++i) {
165 // Read device's response.
166 size_t remaining = size;
167 size_t transferred;
168
169 while (remaining > 0) {
170 if ((rc = usb_pipe_read(pipe, buffer + size - remaining, remaining, &transferred))) {
171 usb_log_error("Read of %s IN endpoint failed with error: %s\n", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
172 break;
173 }
174
175 if (transferred > remaining) {
176 usb_log_error("Read of %s IN endpoint returned more data than expected.\n", usb_str_transfer_type(pipe->desc.transfer_type));
177 rc = EINVAL;
178 break;
179 }
180
181 remaining -= transferred;
182 }
183
184 if (rc)
185 break;
186
187 for (size_t i = 0; i < size; i += sizeof(test_data)) {
188 if (*(uint32_t *)(buffer + i) != test_data) {
189 usb_log_error("Read of %s IN endpoint returned invald data at address %lu.\n", usb_str_transfer_type(pipe->desc.transfer_type), i);
190 rc = EINVAL;
191 break;
192 }
193 }
194
195 if (rc)
196 break;
197 }
198
199 struct timeval final_time;
200 gettimeofday(&final_time, NULL);
201 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
202 ((final_time.tv_sec - start_time.tv_sec) * 1000);
203
204 usb_log_info("Data test on %s IN endpoint completed in %lu ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
205
206 free(buffer);
207 if (duration)
208 *duration = in_duration;
209
210 return rc;
211}
212
213static int data_out_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
214{
215 if (!pipe)
216 return EBADMEM;
217
218 if (size % sizeof(test_data))
219 return EINVAL;
220
221 char *buffer = (char *) malloc(size);
222 if (!buffer)
223 return ENOMEM;
224
225 for (size_t i = 0; i < size; i += sizeof(test_data)) {
226 memcpy(buffer + i, &test_data, sizeof(test_data));
227 }
228
229 // TODO: Are we sure that no other test is running on this endpoint?
230
231 usb_log_info("Performing %s OUT data test.", usb_str_transfer_type(pipe->desc.transfer_type));
232
233 int rc = EOK;
234 struct timeval start_time;
235 gettimeofday(&start_time, NULL);
236
237 for (int i = 0; i < cycles; ++i) {
238 // Write buffer to device.
239 if ((rc = usb_pipe_write(pipe, buffer, size))) {
240 usb_log_error("Write to %s OUT endpoint failed with error: %s\n", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
241 break;
242 }
243 }
244
245 struct timeval final_time;
246 gettimeofday(&final_time, NULL);
247 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
248 ((final_time.tv_sec - start_time.tv_sec) * 1000);
249
250 usb_log_info("Data test on %s OUT endpoint completed in %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
251
252 free(buffer);
253 if (duration)
254 *duration = in_duration;
255
256 return rc;
257}
258
259int usbdiag_burst_test_intr_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
260{
261 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
262 if (!dev)
263 return EBADMEM;
264
265 return burst_in_test(dev->intr_in, cycles, size, duration);
266}
267
268int usbdiag_burst_test_intr_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
269{
270 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
271 if (!dev)
272 return EBADMEM;
273
274 return burst_out_test(dev->intr_out, cycles, size, duration);
275}
276
277int usbdiag_burst_test_bulk_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
278{
279 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
280 if (!dev)
281 return EBADMEM;
282
283 return burst_in_test(dev->bulk_in, cycles, size, duration);
284}
285
286int usbdiag_burst_test_bulk_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
287{
288 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
289 if (!dev)
290 return EBADMEM;
291
292 return burst_out_test(dev->bulk_out, cycles, size, duration);
293}
294
295int usbdiag_burst_test_isoch_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
296{
297 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
298 if (!dev)
299 return EBADMEM;
300
301 return burst_in_test(dev->isoch_in, cycles, size, duration);
302}
303
304int usbdiag_burst_test_isoch_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
305{
306 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
307 if (!dev)
308 return EBADMEM;
309
310 return burst_out_test(dev->isoch_out, cycles, size, duration);
311}
312
313int usbdiag_data_test_intr_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
314{
315 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
316 if (!dev)
317 return EBADMEM;
318
319 return data_in_test(dev->intr_in, cycles, size, duration);
320}
321
322int usbdiag_data_test_intr_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
323{
324 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
325 if (!dev)
326 return EBADMEM;
327
328 return data_out_test(dev->intr_out, cycles, size, duration);
329}
330
331int usbdiag_data_test_bulk_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
332{
333 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
334 if (!dev)
335 return EBADMEM;
336
337 return data_in_test(dev->bulk_in, cycles, size, duration);
338}
339
340int usbdiag_data_test_bulk_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
341{
342 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
343 if (!dev)
344 return EBADMEM;
345
346 return data_out_test(dev->bulk_out, cycles, size, duration);
347}
348
349int usbdiag_data_test_isoch_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
350{
351 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
352 if (!dev)
353 return EBADMEM;
354
355 return data_in_test(dev->isoch_in, cycles, size, duration);
356}
357
358int usbdiag_data_test_isoch_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
359{
360 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
361 if (!dev)
362 return EBADMEM;
363
364 return data_out_test(dev->isoch_out, cycles, size, duration);
365}
366
367/**
368 * @}
369 */
Note: See TracBrowser for help on using the repository browser.