source: mainline/uspace/drv/bus/usb/vhc/transfer.c@ f6577d9

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f6577d9 was f6577d9, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

vhc: DCE

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2011 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#include <errno.h>
30#include <str_error.h>
31#include <usb/debug.h>
32#include <usbvirt/device.h>
33#include <usbvirt/ipc.h>
34#include "vhcd.h"
35
36int vhc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
37{
38 assert(hcd);
39 assert(batch);
40 vhc_data_t *vhc = hcd->private_data;
41 assert(vhc);
42
43 vhc_transfer_t *transfer = malloc(sizeof(vhc_transfer_t));
44 if (!transfer)
45 return ENOMEM;
46 link_initialize(&transfer->link);
47 transfer->batch = batch;
48
49 fibril_mutex_lock(&vhc->guard);
50
51 int targets = 0;
52
53 list_foreach(vhc->devices, pos) {
54 vhc_virtdev_t *dev = list_get_instance(pos, vhc_virtdev_t, link);
55 fibril_mutex_lock(&dev->guard);
56 if (dev->address == transfer->batch->ep->address) {
57 if (!targets) {
58 list_append(&transfer->link, &dev->transfer_queue);
59 }
60 ++targets;
61 }
62 fibril_mutex_unlock(&dev->guard);
63 }
64
65 fibril_mutex_unlock(&vhc->guard);
66
67 if (targets > 1)
68 usb_log_warning("Transfer would be accepted by more devices!\n");
69
70 return targets ? EOK : ENOENT;
71}
72
73static bool is_set_address_transfer(vhc_transfer_t *transfer)
74{
75 if (transfer->batch->ep->endpoint != 0) {
76 return false;
77 }
78 if (transfer->batch->ep->transfer_type != USB_TRANSFER_CONTROL) {
79 return false;
80 }
81 if (usb_transfer_batch_direction(transfer->batch) != USB_DIRECTION_OUT) {
82 return false;
83 }
84 const usb_device_request_setup_packet_t *setup =
85 (void*)transfer->batch->setup_buffer;
86 if (setup->request_type != 0) {
87 return false;
88 }
89 if (setup->request != USB_DEVREQ_SET_ADDRESS) {
90 return false;
91 }
92
93 return true;
94}
95
96static int process_transfer_local(usb_transfer_batch_t *batch,
97 usbvirt_device_t *dev, size_t *actual_data_size)
98{
99 int rc;
100
101 const usb_direction_t dir = usb_transfer_batch_direction(batch);
102
103 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
104 if (dir == USB_DIRECTION_IN) {
105 rc = usbvirt_control_read(dev,
106 batch->setup_buffer, batch->setup_size,
107 batch->buffer, batch->buffer_size,
108 actual_data_size);
109 } else {
110 assert(dir == USB_DIRECTION_OUT);
111 rc = usbvirt_control_write(dev,
112 batch->setup_buffer, batch->setup_size,
113 batch->buffer, batch->buffer_size);
114 }
115 } else {
116 if (dir == USB_DIRECTION_IN) {
117 rc = usbvirt_data_in(dev, batch->ep->transfer_type,
118 batch->ep->endpoint,
119 batch->buffer, batch->buffer_size,
120 actual_data_size);
121 } else {
122 assert(dir == USB_DIRECTION_OUT);
123 rc = usbvirt_data_out(dev, batch->ep->transfer_type,
124 batch->ep->endpoint,
125 batch->buffer, batch->buffer_size);
126 }
127 }
128
129 return rc;
130}
131
132static int process_transfer_remote(usb_transfer_batch_t *batch,
133 async_sess_t *sess, size_t *actual_data_size)
134{
135 int rc;
136
137 const usb_direction_t dir = usb_transfer_batch_direction(batch);
138
139 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
140 if (dir == USB_DIRECTION_IN) {
141 rc = usbvirt_ipc_send_control_read(sess,
142 batch->setup_buffer, batch->setup_size,
143 batch->buffer, batch->buffer_size,
144 actual_data_size);
145 } else {
146 assert(dir == USB_DIRECTION_OUT);
147 rc = usbvirt_ipc_send_control_write(sess,
148 batch->setup_buffer, batch->setup_size,
149 batch->buffer, batch->buffer_size);
150 }
151 } else {
152 if (dir == USB_DIRECTION_IN) {
153 rc = usbvirt_ipc_send_data_in(sess, batch->ep->endpoint,
154 batch->ep->transfer_type,
155 batch->buffer, batch->buffer_size,
156 actual_data_size);
157 } else {
158 assert(dir == USB_DIRECTION_OUT);
159 rc = usbvirt_ipc_send_data_out(sess, batch->ep->endpoint,
160 batch->ep->transfer_type,
161 batch->buffer, batch->buffer_size);
162 }
163 }
164
165 return rc;
166}
167
168static vhc_transfer_t *dequeue_first_transfer(vhc_virtdev_t *dev)
169{
170 assert(fibril_mutex_is_locked(&dev->guard));
171 assert(!list_empty(&dev->transfer_queue));
172
173 vhc_transfer_t *transfer = list_get_instance(
174 list_first(&dev->transfer_queue), vhc_transfer_t, link);
175 list_remove(&transfer->link);
176
177 return transfer;
178}
179
180static void execute_transfer_callback_and_free(vhc_transfer_t *transfer,
181 size_t data_transfer_size, int outcome)
182{
183 assert(outcome != ENAK);
184 assert(transfer);
185 assert(transfer->batch);
186 usb_transfer_batch_finish_error(transfer->batch, NULL,
187 data_transfer_size, outcome);
188 usb_transfer_batch_destroy(transfer->batch);
189 free(transfer);
190}
191
192int vhc_transfer_queue_processor(void *arg)
193{
194 vhc_virtdev_t *dev = arg;
195 fibril_mutex_lock(&dev->guard);
196 while (dev->plugged) {
197 if (list_empty(&dev->transfer_queue)) {
198 fibril_mutex_unlock(&dev->guard);
199 async_usleep(10 * 1000);
200 fibril_mutex_lock(&dev->guard);
201 continue;
202 }
203
204 vhc_transfer_t *transfer = dequeue_first_transfer(dev);
205 fibril_mutex_unlock(&dev->guard);
206
207 int rc = EOK;
208 size_t data_transfer_size = 0;
209 if (dev->dev_sess) {
210 rc = process_transfer_remote(transfer->batch,
211 dev->dev_sess, &data_transfer_size);
212 } else if (dev->dev_local != NULL) {
213 rc = process_transfer_local(transfer->batch,
214 dev->dev_local, &data_transfer_size);
215 } else {
216 usb_log_warning("Device has no remote phone nor local node.\n");
217 rc = ESTALL;
218 }
219
220 usb_log_debug2("Transfer %p processed: %s.\n",
221 transfer, str_error(rc));
222
223 fibril_mutex_lock(&dev->guard);
224 if (rc == EOK) {
225 if (is_set_address_transfer(transfer)) {
226 usb_device_request_setup_packet_t *setup
227 = (void*)transfer->batch->setup_buffer;
228 dev->address = setup->value;
229 usb_log_debug2("Address changed to %d\n",
230 dev->address);
231 }
232 }
233 if (rc == ENAK) {
234 // FIXME: this will work only because we do
235 // not NAK control transfers but this is generally
236 // a VERY bad idea indeed
237 list_append(&transfer->link, &dev->transfer_queue);
238 }
239 fibril_mutex_unlock(&dev->guard);
240
241 if (rc != ENAK) {
242 execute_transfer_callback_and_free(transfer,
243 data_transfer_size, rc);
244 }
245
246 async_usleep(1000 * 100);
247 fibril_mutex_lock(&dev->guard);
248 }
249
250 /* Immediately fail all remaining transfers. */
251 while (!list_empty(&dev->transfer_queue)) {
252 vhc_transfer_t *transfer = dequeue_first_transfer(dev);
253 execute_transfer_callback_and_free(transfer, 0, EBADCHECKSUM);
254 }
255
256 fibril_mutex_unlock(&dev->guard);
257
258 return EOK;
259}
Note: See TracBrowser for help on using the repository browser.