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

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

usbdiag: use the dma pipe operations

  • Property mode set to 100644
File size: 10.5 KB
RevLine 
[fd312d5]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>
[b10a434]39#include <usbdiag_iface.h>
[96c416a]40#include <time.h>
[b7b7898]41#include "device.h"
[fd312d5]42#include "tests.h"
43
44#define NAME "usbdiag"
45
[b10a434]46static int burst_in_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
[e9d600c2]47{
[b7b7898]48 if (!pipe)
[e9d600c2]49 return EBADMEM;
50
[da9d6ca]51 char *buffer = usb_pipe_alloc_buffer(pipe, size);
[e9d600c2]52 if (!buffer)
53 return ENOMEM;
54
55 // TODO: Are we sure that no other test is running on this endpoint?
56
[b7b7898]57 usb_log_info("Performing %s IN burst test.", usb_str_transfer_type(pipe->desc.transfer_type));
[96c416a]58
[e9d600c2]59 int rc = EOK;
[96c416a]60 struct timeval start_time;
61 gettimeofday(&start_time, NULL);
62
[e9d600c2]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) {
[da9d6ca]69 if ((rc = usb_pipe_read_dma(pipe, buffer + size - remaining, remaining, &transferred))) {
[a1732929]70 usb_log_error("Read of %s IN endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
[e9d600c2]71 break;
72 }
73
74 if (transferred > remaining) {
[a1732929]75 usb_log_error("Read of %s IN endpoint returned more data than expected.", usb_str_transfer_type(pipe->desc.transfer_type));
[e9d600c2]76 rc = EINVAL;
77 break;
78 }
79
80 remaining -= transferred;
81 }
82
83 if (rc)
84 break;
85 }
[96c416a]86
87 struct timeval final_time;
88 gettimeofday(&final_time, NULL);
[b10a434]89 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
[96c416a]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);
[e9d600c2]93
[da9d6ca]94 usb_pipe_free_buffer(pipe, buffer);
[96c416a]95 if (duration)
96 *duration = in_duration;
97
[e9d600c2]98 return rc;
99}
100
[b10a434]101static int burst_out_test(usb_pipe_t *pipe, int cycles, size_t size, usbdiag_dur_t *duration)
[fd312d5]102{
[b7b7898]103 if (!pipe)
[fd312d5]104 return EBADMEM;
105
[da9d6ca]106 char *buffer = usb_pipe_alloc_buffer(pipe, size);
[fd312d5]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
[b7b7898]114 usb_log_info("Performing %s OUT burst test.", usb_str_transfer_type(pipe->desc.transfer_type));
[96c416a]115
[fd312d5]116 int rc = EOK;
[96c416a]117 struct timeval start_time;
118 gettimeofday(&start_time, NULL);
119
[fd312d5]120 for (int i = 0; i < cycles; ++i) {
121 // Write buffer to device.
[da9d6ca]122 if ((rc = usb_pipe_write_dma(pipe, buffer, size))) {
[a1732929]123 usb_log_error("Write to %s OUT endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
[fd312d5]124 break;
125 }
126 }
[96c416a]127
128 struct timeval final_time;
129 gettimeofday(&final_time, NULL);
[b10a434]130 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
[96c416a]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);
[fd312d5]134
[da9d6ca]135 usb_pipe_free_buffer(pipe, buffer);
[96c416a]136 if (duration)
137 *duration = in_duration;
138
[fd312d5]139 return rc;
140}
141
[bf0398c]142static const uint32_t test_data_src = 0xDEADBEEF;
[bf7b747]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
[bf0398c]149 const uint32_t test_data = uint32_host2usb(test_data_src);
150
[bf7b747]151 if (size % sizeof(test_data))
152 return EINVAL;
153
[da9d6ca]154 char *buffer = usb_pipe_alloc_buffer(pipe, size);
[bf7b747]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) {
[da9d6ca]172 if ((rc = usb_pipe_read_dma(pipe, buffer + size - remaining, remaining, &transferred))) {
[a1732929]173 usb_log_error("Read of %s IN endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
[bf7b747]174 break;
175 }
176
177 if (transferred > remaining) {
[a1732929]178 usb_log_error("Read of %s IN endpoint returned more data than expected.", usb_str_transfer_type(pipe->desc.transfer_type));
[bf7b747]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) {
[80f7c54]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);
[bf7b747]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
[da9d6ca]210 usb_pipe_free_buffer(pipe, buffer);
[bf7b747]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
[bf0398c]222 const uint32_t test_data = uint32_host2usb(test_data_src);
223
[bf7b747]224 if (size % sizeof(test_data))
225 return EINVAL;
226
[da9d6ca]227 char *buffer = usb_pipe_alloc_buffer(pipe, size);
[bf7b747]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.
[da9d6ca]245 if ((rc = usb_pipe_write_dma(pipe, buffer, size))) {
[a1732929]246 usb_log_error("Write to %s OUT endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
[bf7b747]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
[da9d6ca]258 usb_pipe_free_buffer(pipe, buffer);
[bf7b747]259 if (duration)
260 *duration = in_duration;
261
262 return rc;
263}
264
[b10a434]265int usbdiag_burst_test_intr_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
[fd312d5]266{
[b7b7898]267 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
[fd312d5]268 if (!dev)
269 return EBADMEM;
270
[b10a434]271 return burst_in_test(dev->intr_in, cycles, size, duration);
[fd312d5]272}
273
[b10a434]274int usbdiag_burst_test_intr_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
[ff16da5f]275{
[b7b7898]276 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
[ff16da5f]277 if (!dev)
278 return EBADMEM;
279
[b10a434]280 return burst_out_test(dev->intr_out, cycles, size, duration);
[ff16da5f]281}
282
[b10a434]283int usbdiag_burst_test_bulk_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
[ff16da5f]284{
[b7b7898]285 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
[ff16da5f]286 if (!dev)
287 return EBADMEM;
288
[b10a434]289 return burst_in_test(dev->bulk_in, cycles, size, duration);
[b7b7898]290}
[ff16da5f]291
[b10a434]292int usbdiag_burst_test_bulk_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
[b7b7898]293{
294 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
295 if (!dev)
296 return EBADMEM;
[ff16da5f]297
[b10a434]298 return burst_out_test(dev->bulk_out, cycles, size, duration);
[b7b7898]299}
[ff16da5f]300
[b10a434]301int usbdiag_burst_test_isoch_in(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
[b7b7898]302{
303 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
304 if (!dev)
305 return EBADMEM;
[ff16da5f]306
[b10a434]307 return burst_in_test(dev->isoch_in, cycles, size, duration);
[b7b7898]308}
[ff16da5f]309
[b10a434]310int usbdiag_burst_test_isoch_out(ddf_fun_t *fun, int cycles, size_t size, usbdiag_dur_t *duration)
[b7b7898]311{
312 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
313 if (!dev)
314 return EBADMEM;
[ff16da5f]315
[b10a434]316 return burst_out_test(dev->isoch_out, cycles, size, duration);
[ff16da5f]317}
318
[bf7b747]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
[fd312d5]373/**
374 * @}
375 */
Note: See TracBrowser for help on using the repository browser.