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

Last change on this file since 8ad4ccfc was bd41ac52, checked in by Jakub Jermar <jakub@…>, 7 years ago

Get rid of sys/time.h

This commit moves the POSIX-like time functionality from libc's
sys/time.h to libposix and introduces C11-like or HelenOS-specific
interfaces to libc.

Specifically, use of sys/time.h, struct timeval, suseconds_t and
gettimeofday is replaced by time.h (C11), struct timespec (C11), usec_t
(HelenOS) and getuptime / getrealtime (HelenOS).

Also attempt to fix the implementation of clock() to return microseconds
(clocks) rather than processor cycles and move it to libc.

  • Property mode set to 100644
File size: 7.3 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
[bf0398c]46static const uint32_t test_data_src = 0xDEADBEEF;
[bf7b747]47
[7cba9f7]48static errno_t test_in(usb_pipe_t *pipe, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
[bf7b747]49{
50 if (!pipe)
51 return EBADMEM;
52
[8393c73b]53 bool validate = params->validate_data;
54 size_t size = params->transfer_size;
55 if (!size)
56 size = pipe->desc.max_transfer_size;
[bf0398c]57
[8393c73b]58 const uint32_t test_data = uint32_host2usb(test_data_src);
59 if (validate && size % sizeof(test_data))
[bf7b747]60 return EINVAL;
61
[290338b]62 size_t test_data_size = size / sizeof(test_data);
[961a5ee]63 char *buffer = usb_pipe_alloc_buffer(pipe, size);
[bf7b747]64 if (!buffer)
65 return ENOMEM;
66
67 // TODO: Are we sure that no other test is running on this endpoint?
68
[8393c73b]69 usb_log_info("Performing %s IN test with duration %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), params->min_duration);
[bf7b747]70
[7cba9f7]71 errno_t rc = EOK;
[8393c73b]72 uint32_t transfer_count = 0;
73
[bd41ac52]74 struct timespec start_time, final_time, stop_time;
75 getuptime(&start_time);
76 getuptime(&stop_time);
[8393c73b]77
[bd41ac52]78 ts_add_diff(&stop_time, MSEC2NSEC(params->min_duration));
79 getuptime(&final_time);
[8393c73b]80
[bd41ac52]81 while (!ts_gt(&final_time, &stop_time)) {
[8393c73b]82 ++transfer_count;
[bf7b747]83
84 // Read device's response.
85 size_t remaining = size;
86 size_t transferred;
87
88 while (remaining > 0) {
[d345ce2]89 if ((rc = usb_pipe_read_dma(pipe, buffer, buffer + size - remaining, remaining, &transferred))) {
[a1732929]90 usb_log_error("Read of %s IN endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
[bf7b747]91 break;
92 }
93
94 if (transferred > remaining) {
[a1732929]95 usb_log_error("Read of %s IN endpoint returned more data than expected.", usb_str_transfer_type(pipe->desc.transfer_type));
[bf7b747]96 rc = EINVAL;
97 break;
98 }
99
100 remaining -= transferred;
101 }
102
103 if (rc)
104 break;
105
[8393c73b]106 if (validate) {
[290338b]107 uint32_t *beef_buffer = (uint32_t *) buffer;
108
109 /* Check if the beef is really dead. */
110 for (size_t i = 0; i < test_data_size; ++i) {
111 if (beef_buffer[i] != test_data) {
[8393c73b]112 usb_log_error("Read of %s IN endpoint returned "
[3bacee1]113 "invalid data at address %zu. [ 0x%X != 0x%X ]",
114 usb_str_transfer_type(pipe->desc.transfer_type), i * sizeof(test_data), beef_buffer[i], test_data);
[8393c73b]115 rc = EINVAL;
116 }
[bf7b747]117 }
[8393c73b]118
119 if (rc)
120 break;
[bf7b747]121 }
122
[bd41ac52]123 getuptime(&final_time);
[bf7b747]124 }
125
[bd41ac52]126 usbdiag_dur_t in_duration = NSEC2MSEC(final_time.tv_nsec - start_time.tv_nsec) +
127 SEC2MSEC(final_time.tv_sec - start_time.tv_sec);
[bf7b747]128
[8393c73b]129 usb_log_info("Test on %s IN endpoint completed in %lu ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
130
131 results->act_duration = in_duration;
132 results->transfer_count = transfer_count;
133 results->transfer_size = size;
[bf7b747]134
[961a5ee]135 usb_pipe_free_buffer(pipe, buffer);
[bf7b747]136
137 return rc;
138}
139
[7cba9f7]140static errno_t test_out(usb_pipe_t *pipe, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
[bf7b747]141{
142 if (!pipe)
143 return EBADMEM;
144
[8393c73b]145 bool validate = params->validate_data;
146 size_t size = params->transfer_size;
147 if (!size)
148 size = pipe->desc.max_transfer_size;
149
[bf0398c]150 const uint32_t test_data = uint32_host2usb(test_data_src);
151
[8393c73b]152 if (validate && size % sizeof(test_data))
[bf7b747]153 return EINVAL;
154
[da9d6ca]155 char *buffer = usb_pipe_alloc_buffer(pipe, size);
[bf7b747]156 if (!buffer)
157 return ENOMEM;
158
[8393c73b]159 if (validate) {
160 for (size_t i = 0; i < size; i += sizeof(test_data)) {
161 memcpy(buffer + i, &test_data, sizeof(test_data));
162 }
[bf7b747]163 }
164
165 // TODO: Are we sure that no other test is running on this endpoint?
166
[8393c73b]167 usb_log_info("Performing %s OUT test.", usb_str_transfer_type(pipe->desc.transfer_type));
[bf7b747]168
[7cba9f7]169 errno_t rc = EOK;
[8393c73b]170 uint32_t transfer_count = 0;
171
[bd41ac52]172 struct timespec start_time, final_time, stop_time;
173 getuptime(&start_time);
174 getuptime(&stop_time);
[8393c73b]175
[bd41ac52]176 ts_add_diff(&stop_time, MSEC2NSEC(params->min_duration));
177 getuptime(&final_time);
[8393c73b]178
[bd41ac52]179 while (!ts_gt(&final_time, &stop_time)) {
[8393c73b]180 ++transfer_count;
[bf7b747]181
182 // Write buffer to device.
[d345ce2]183 if ((rc = usb_pipe_write_dma(pipe, buffer, buffer, size))) {
[a1732929]184 usb_log_error("Write to %s OUT endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
[bf7b747]185 break;
186 }
[8393c73b]187
[bd41ac52]188 getuptime(&final_time);
[bf7b747]189 }
190
[bd41ac52]191 usbdiag_dur_t in_duration = NSEC2MSEC(final_time.tv_nsec - start_time.tv_nsec) +
192 SEC2MSEC(final_time.tv_sec - start_time.tv_sec);
[bf7b747]193
[8393c73b]194 usb_log_info("Test on %s OUT endpoint completed in %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
[ff16da5f]195
[8393c73b]196 results->act_duration = in_duration;
197 results->transfer_count = transfer_count;
198 results->transfer_size = size;
[ff16da5f]199
[961a5ee]200 usb_pipe_free_buffer(pipe, buffer);
[bf7b747]201
202 return rc;
203}
204
[7cba9f7]205errno_t usbdiag_dev_test_in(ddf_fun_t *fun, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
[bf7b747]206{
207 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
208 if (!dev)
209 return EBADMEM;
210
[8393c73b]211 usb_pipe_t *pipe;
212
213 switch (params->transfer_type) {
214 case USB_TRANSFER_INTERRUPT:
215 pipe = params->validate_data ? dev->data_intr_in : dev->burst_intr_in;
216 break;
217 case USB_TRANSFER_BULK:
218 pipe = params->validate_data ? dev->data_bulk_in : dev->burst_bulk_in;
219 break;
220 case USB_TRANSFER_ISOCHRONOUS:
221 pipe = params->validate_data ? dev->data_isoch_in : dev->burst_isoch_in;
222 break;
223 default:
224 return ENOTSUP;
225 }
[bf7b747]226
[8393c73b]227 return test_in(pipe, params, results);
[bf7b747]228}
229
[7cba9f7]230errno_t usbdiag_dev_test_out(ddf_fun_t *fun, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
[bf7b747]231{
232 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
233 if (!dev)
234 return EBADMEM;
235
[8393c73b]236 usb_pipe_t *pipe;
237
238 switch (params->transfer_type) {
239 case USB_TRANSFER_INTERRUPT:
240 pipe = params->validate_data ? dev->data_intr_out : dev->burst_intr_out;
241 break;
242 case USB_TRANSFER_BULK:
243 pipe = params->validate_data ? dev->data_bulk_out : dev->burst_bulk_out;
244 break;
245 case USB_TRANSFER_ISOCHRONOUS:
246 pipe = params->validate_data ? dev->data_isoch_out : dev->burst_isoch_out;
247 break;
248 default:
249 return ENOTSUP;
250 }
[bf7b747]251
[8393c73b]252 return test_out(pipe, params, results);
[bf7b747]253}
254
[fd312d5]255/**
256 * @}
257 */
Note: See TracBrowser for help on using the repository browser.