source: mainline/uspace/lib/usbvirt/src/transaction.c@ 75732da

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

Merge development/ changes

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