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

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

drv: refactor usbdiag interface

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