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

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

usb: pass buffers as base + ptr to support partial writes/reads

  • Property mode set to 100644
File size: 7.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 const uint32_t test_data_src = 0xDEADBEEF;
47
48static errno_t 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 size_t test_data_size = size / sizeof(test_data);
63 char *buffer = usb_pipe_alloc_buffer(pipe, size);
64 if (!buffer)
65 return ENOMEM;
66
67 // TODO: Are we sure that no other test is running on this endpoint?
68
69 usb_log_info("Performing %s IN test with duration %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), params->min_duration);
70
71 errno_t rc = EOK;
72 uint32_t transfer_count = 0;
73
74 struct timeval start_time, final_time, stop_time;
75 gettimeofday(&start_time, NULL);
76 gettimeofday(&stop_time, NULL);
77
78 tv_add_diff(&stop_time, params->min_duration * 1000);
79 gettimeofday(&final_time, NULL);
80
81 while (!tv_gt(&final_time, &stop_time)) {
82 ++transfer_count;
83
84 // Read device's response.
85 size_t remaining = size;
86 size_t transferred;
87
88 while (remaining > 0) {
89 if ((rc = usb_pipe_read_dma(pipe, buffer, buffer + size - remaining, remaining, &transferred))) {
90 usb_log_error("Read of %s IN endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
91 break;
92 }
93
94 if (transferred > remaining) {
95 usb_log_error("Read of %s IN endpoint returned more data than expected.", usb_str_transfer_type(pipe->desc.transfer_type));
96 rc = EINVAL;
97 break;
98 }
99
100 remaining -= transferred;
101 }
102
103 if (rc)
104 break;
105
106 if (validate) {
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) {
112 usb_log_error("Read of %s IN endpoint returned "
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);
115 rc = EINVAL;
116 }
117 }
118
119 if (rc)
120 break;
121 }
122
123 gettimeofday(&final_time, NULL);
124 }
125
126 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
127 ((final_time.tv_sec - start_time.tv_sec) * 1000);
128
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;
134
135 usb_pipe_free_buffer(pipe, buffer);
136
137 return rc;
138}
139
140static errno_t test_out(usb_pipe_t *pipe, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
141{
142 if (!pipe)
143 return EBADMEM;
144
145 bool validate = params->validate_data;
146 size_t size = params->transfer_size;
147 if (!size)
148 size = pipe->desc.max_transfer_size;
149
150 const uint32_t test_data = uint32_host2usb(test_data_src);
151
152 if (validate && size % sizeof(test_data))
153 return EINVAL;
154
155 char *buffer = usb_pipe_alloc_buffer(pipe, size);
156 if (!buffer)
157 return ENOMEM;
158
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 }
163 }
164
165 // TODO: Are we sure that no other test is running on this endpoint?
166
167 usb_log_info("Performing %s OUT test.", usb_str_transfer_type(pipe->desc.transfer_type));
168
169 errno_t rc = EOK;
170 uint32_t transfer_count = 0;
171
172 struct timeval start_time, final_time, stop_time;
173 gettimeofday(&start_time, NULL);
174 gettimeofday(&stop_time, NULL);
175
176 tv_add_diff(&stop_time, params->min_duration * 1000);
177 gettimeofday(&final_time, NULL);
178
179 while (!tv_gt(&final_time, &stop_time)) {
180 ++transfer_count;
181
182 // Write buffer to device.
183 if ((rc = usb_pipe_write_dma(pipe, buffer, buffer, size))) {
184 usb_log_error("Write to %s OUT endpoint failed with error: %s", usb_str_transfer_type(pipe->desc.transfer_type), str_error(rc));
185 break;
186 }
187
188 gettimeofday(&final_time, NULL);
189 }
190
191 usbdiag_dur_t in_duration = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
192 ((final_time.tv_sec - start_time.tv_sec) * 1000);
193
194 usb_log_info("Test on %s OUT endpoint completed in %ld ms.", usb_str_transfer_type(pipe->desc.transfer_type), in_duration);
195
196 results->act_duration = in_duration;
197 results->transfer_count = transfer_count;
198 results->transfer_size = size;
199
200 usb_pipe_free_buffer(pipe, buffer);
201
202 return rc;
203}
204
205errno_t usbdiag_dev_test_in(ddf_fun_t *fun, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
206{
207 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
208 if (!dev)
209 return EBADMEM;
210
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 }
226
227 return test_in(pipe, params, results);
228}
229
230errno_t usbdiag_dev_test_out(ddf_fun_t *fun, const usbdiag_test_params_t *params, usbdiag_test_results_t *results)
231{
232 usbdiag_dev_t *dev = ddf_fun_to_usbdiag_dev(fun);
233 if (!dev)
234 return EBADMEM;
235
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 }
251
252 return test_out(pipe, params, results);
253}
254
255/**
256 * @}
257 */
Note: See TracBrowser for help on using the repository browser.