source: mainline/uspace/drv/vhc/transfer.c@ 3e95cd7

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

Merge mainline changes

Conflicts:
kernel/generic/src/console/console.c

size of klog, taken upstream

uspace/app/klog/klog.c

taken upstream (upstream fixed the broken output on huge load)

uspace/app/tester/Makefile
uspace/app/tester/tester.c
uspace/app/tester/tester.h

merged without problems

uspace/lib/c/include/as.h

merged without problems (upstream use bare declarations)

Also needed to fix some missing includes.

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