source: mainline/uspace/lib/usbvirt/transaction.c@ 36bcf84f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 36bcf84f was aab02fb, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Debugging support for libusbvirt

Added methods debug and lib_debug to device structure to simplify
debugging. Each method gets as a parameter debug level describing
verbosity of the message and also message tag that allows filtering
based on message type (e.g. messages related to transactions, to
device requests etc.).

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
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 libusbvirt usb
30 * @{
31 */
32/** @file
33 * @brief Transaction processing.
34 */
35#include <errno.h>
36#include <stdlib.h>
37#include <mem.h>
38
39#include "hub.h"
40#include "private.h"
41
42static usb_direction_t setup_transaction_direction(usbvirt_device_t *,
43 usb_endpoint_t, void *, size_t);
44static void process_control_transfer(usbvirt_device_t *,
45 usb_endpoint_t, usbvirt_control_transfer_t *);
46
47/** Convert virtual USB transaction type to string.
48 */
49const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type)
50{
51 switch (type) {
52 case USBVIRT_TRANSACTION_SETUP:
53 return "setup";
54 case USBVIRT_TRANSACTION_IN:
55 return "in";
56 case USBVIRT_TRANSACTION_OUT:
57 return "out";
58 default:
59 return "unknown";
60 }
61}
62
63/** SETUP transaction handling.
64 * The setup transaction only prepares control transfer on given endpoint.
65 */
66int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
67 void *buffer, size_t size)
68{
69 device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
70 "setup transaction: endpoint=%d, size=%u", endpoint, size);
71
72 usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
73
74 if (transfer->request != NULL) {
75 free(transfer->request);
76 }
77 if (transfer->data != NULL) {
78 free(transfer->data);
79 }
80
81 transfer->direction = setup_transaction_direction(device, endpoint,
82 buffer, size);
83 transfer->request = malloc(size);
84 memcpy(transfer->request, buffer, size);
85 transfer->request_size = size;
86 transfer->data = NULL;
87 transfer->data_size = 0;
88
89 if (transfer->direction == USB_DIRECTION_IN) {
90 process_control_transfer(device, endpoint, transfer);
91 }
92
93 return EOK;
94}
95
96/** OUT transaction handling.
97 * The OUT transaction can trigger processing of a control transfer.
98 */
99int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
100 void *buffer, size_t size)
101{
102 device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
103 "out transaction: endpoint=%d, size=%u", endpoint, size);
104
105 /*
106 * First check whether it is a transaction over control pipe.
107 */
108 usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
109 if (transfer->request != NULL) {
110 if (transfer->direction == USB_DIRECTION_OUT) {
111 /*
112 * For out transactions, append the data to the buffer.
113 */
114 uint8_t *new_buffer = (uint8_t *) malloc(transfer->data_size + size);
115 if (transfer->data) {
116 memcpy(new_buffer, transfer->data, transfer->data_size);
117 }
118 memcpy(new_buffer + transfer->data_size, buffer, size);
119
120 if (transfer->data) {
121 free(transfer->data);
122 }
123 transfer->data = new_buffer;
124 transfer->data_size += size;
125 } else {
126 /*
127 * For in transactions, this means end of the
128 * transaction.
129 */
130 free(transfer->request);
131 if (transfer->data) {
132 free(transfer->data);
133 }
134 transfer->request = NULL;
135 transfer->request_size = 0;
136 transfer->data = NULL;
137 transfer->data_size = 0;
138 }
139
140 return EOK;
141 }
142
143 /*
144 * Otherwise, announce that some data has come.
145 */
146 if (device->ops && device->ops->on_data) {
147 return device->ops->on_data(device, endpoint, buffer, size);
148 } else {
149 return ENOTSUP;
150 }
151}
152
153/** IN transaction handling.
154 * The IN transaction can trigger processing of a control transfer.
155 */
156int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
157 void *buffer, size_t size, size_t *data_size)
158{
159 device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
160 "in transaction: endpoint=%d, size=%u", endpoint, size);
161
162 /*
163 * First check whether it is a transaction over control pipe.
164 */
165 usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
166 if (transfer->request != NULL) {
167 if (transfer->direction == USB_DIRECTION_OUT) {
168 /*
169 * This means end of input data.
170 */
171 process_control_transfer(device, endpoint, transfer);
172 } else {
173 /*
174 * For in transactions, this means sending next part
175 * of the buffer.
176 */
177 // FIXME: handle when the HC wants the data back
178 // in more chunks
179 size_t actual_size = 0;
180 if (transfer->data) {
181 actual_size = transfer->data_size;
182 }
183 if (actual_size > size) {
184 actual_size = size;
185 }
186 if (actual_size > 0) {
187 memcpy(buffer, transfer->data, actual_size);
188 if (data_size) {
189 *data_size = actual_size;
190 }
191 }
192 }
193
194 return EOK;
195 }
196
197 if (size == 0) {
198 return EINVAL;
199 }
200
201 int rc = 1;
202
203 if (device->ops && device->ops->on_data_request) {
204 rc = device->ops->on_data_request(device, endpoint, buffer, size, data_size);
205 }
206
207 return rc;
208}
209
210/** Determine direction of control transfer.
211 * First, try the user provided callback, otherwise guess, believing that
212 * it uses the same format as control pipe 0.
213 */
214static usb_direction_t setup_transaction_direction(usbvirt_device_t *device,
215 usb_endpoint_t endpoint,
216 void *data, size_t size)
217{
218 int direction = -1;
219 if (device->ops && device->ops->decide_control_transfer_direction) {
220 direction = device->ops->decide_control_transfer_direction(endpoint,
221 data, size);
222 }
223
224 /*
225 * If the user-supplied routine have not handled the direction
226 * (or simply was not provided) we will guess, hoping that it
227 * uses same format as standard request on control pipe zero.
228 */
229 if (direction < 0) {
230 if (size > 0) {
231 uint8_t *ptr = (uint8_t *) data;
232 if ((ptr[0] & 128) == 128) {
233 direction = USB_DIRECTION_IN;
234 } else {
235 direction = USB_DIRECTION_OUT;
236 }
237 } else {
238 /* This shall not happen anyway. */
239 direction = USB_DIRECTION_OUT;
240 }
241 }
242
243 return (usb_direction_t) direction;
244}
245
246/** Process control transfer.
247 */
248static void process_control_transfer(usbvirt_device_t *device,
249 usb_endpoint_t endpoint,
250 usbvirt_control_transfer_t *transfer)
251{
252 int rc = EFORWARD;
253
254 if (device->ops && device->ops->on_control_transfer) {
255 rc = device->ops->on_control_transfer(device, endpoint, transfer);
256 }
257
258 if (rc == EFORWARD) {
259 if (endpoint == 0) {
260 rc = control_pipe(device, transfer);
261 }
262 }
263}
264
265/**
266 * @}
267 */
Note: See TracBrowser for help on using the repository browser.