source: mainline/uspace/drv/vhc/connhost.c@ 0c00dac

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

Merge low/high speed hack

  • Property mode set to 100644
File size: 12.6 KB
RevLine 
[b371844]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
[bd8c753d]29/** @addtogroup drvusbvhc
[b371844]30 * @{
31 */
32/** @file
33 * @brief Connection handling of calls from host (implementation).
34 */
35#include <assert.h>
36#include <errno.h>
[4b4c797]37#include <usb/usb.h>
[8555112]38#include <usb/addrkeep.h>
[b371844]39
40#include "vhcd.h"
41#include "conn.h"
42#include "hc.h"
43
[284c629]44
[c4ba29c7]45typedef struct {
46 usb_direction_t direction;
[4317827]47 usbhc_iface_transfer_out_callback_t out_callback;
48 usbhc_iface_transfer_in_callback_t in_callback;
49 device_t *dev;
[284c629]50 size_t reported_size;
[c4ba29c7]51 void *arg;
52} transfer_info_t;
53
[284c629]54typedef struct {
55 usb_direction_t direction;
56 usb_target_t target;
57 usbhc_iface_transfer_out_callback_t out_callback;
58 usbhc_iface_transfer_in_callback_t in_callback;
59 device_t *dev;
60 void *arg;
61 void *data_buffer;
62 size_t data_buffer_size;
63} control_transfer_info_t;
64
[c4ba29c7]65static void universal_callback(void *buffer, size_t size,
[daec5e04]66 int outcome, void *arg)
[c4ba29c7]67{
68 transfer_info_t *transfer = (transfer_info_t *) arg;
69
[284c629]70 if (transfer->reported_size != (size_t) -1) {
71 size = transfer->reported_size;
72 }
73
[c4ba29c7]74 switch (transfer->direction) {
75 case USB_DIRECTION_IN:
[4317827]76 transfer->in_callback(transfer->dev,
[eac610e]77 outcome, size,
[c4ba29c7]78 transfer->arg);
79 break;
80 case USB_DIRECTION_OUT:
[4317827]81 transfer->out_callback(transfer->dev,
[c4ba29c7]82 outcome,
83 transfer->arg);
84 break;
85 default:
86 assert(false && "unreachable");
87 break;
88 }
89
90 free(transfer);
91}
92
[4317827]93static transfer_info_t *create_transfer_info(device_t *dev,
[c4ba29c7]94 usb_direction_t direction, void *arg)
95{
96 transfer_info_t *transfer = malloc(sizeof(transfer_info_t));
97
98 transfer->direction = direction;
99 transfer->in_callback = NULL;
100 transfer->out_callback = NULL;
101 transfer->arg = arg;
[4317827]102 transfer->dev = dev;
[284c629]103 transfer->reported_size = (size_t) -1;
104
105 return transfer;
106}
107
108static void control_abort_prematurely(control_transfer_info_t *transfer,
[daec5e04]109 size_t size, int outcome)
[284c629]110{
111 switch (transfer->direction) {
112 case USB_DIRECTION_IN:
113 transfer->in_callback(transfer->dev,
114 outcome, size,
115 transfer->arg);
116 break;
117 case USB_DIRECTION_OUT:
118 transfer->out_callback(transfer->dev,
119 outcome,
120 transfer->arg);
121 break;
122 default:
123 assert(false && "unreachable");
124 break;
125 }
126}
127
128static void control_callback_two(void *buffer, size_t size,
[daec5e04]129 int outcome, void *arg)
[284c629]130{
131 control_transfer_info_t *ctrl_transfer = (control_transfer_info_t *) arg;
132
[daec5e04]133 if (outcome != EOK) {
[284c629]134 control_abort_prematurely(ctrl_transfer, outcome, size);
135 free(ctrl_transfer);
136 return;
137 }
138
139 transfer_info_t *transfer = create_transfer_info(ctrl_transfer->dev,
140 ctrl_transfer->direction, ctrl_transfer->arg);
141 transfer->out_callback = ctrl_transfer->out_callback;
142 transfer->in_callback = ctrl_transfer->in_callback;
143 transfer->reported_size = size;
144
145 switch (ctrl_transfer->direction) {
146 case USB_DIRECTION_IN:
147 hc_add_transaction_to_device(false, ctrl_transfer->target,
148 USB_TRANSFER_CONTROL,
149 NULL, 0,
150 universal_callback, transfer);
151 break;
152 case USB_DIRECTION_OUT:
153 hc_add_transaction_from_device(ctrl_transfer->target,
154 USB_TRANSFER_CONTROL,
155 NULL, 0,
156 universal_callback, transfer);
157 break;
158 default:
159 assert(false && "unreachable");
160 break;
161 }
162
163 free(ctrl_transfer);
164}
165
166static void control_callback_one(void *buffer, size_t size,
[daec5e04]167 int outcome, void *arg)
[284c629]168{
169 control_transfer_info_t *transfer = (control_transfer_info_t *) arg;
170
[daec5e04]171 if (outcome != EOK) {
[284c629]172 control_abort_prematurely(transfer, outcome, size);
173 free(transfer);
174 return;
175 }
176
177 switch (transfer->direction) {
178 case USB_DIRECTION_IN:
179 hc_add_transaction_from_device(transfer->target,
180 USB_TRANSFER_CONTROL,
181 transfer->data_buffer, transfer->data_buffer_size,
182 control_callback_two, transfer);
183 break;
184 case USB_DIRECTION_OUT:
185 hc_add_transaction_to_device(false, transfer->target,
186 USB_TRANSFER_CONTROL,
187 transfer->data_buffer, transfer->data_buffer_size,
188 control_callback_two, transfer);
189 break;
190 default:
191 assert(false && "unreachable");
192 break;
193 }
194}
195
196static control_transfer_info_t *create_control_transfer_info(device_t *dev,
197 usb_direction_t direction, usb_target_t target,
198 void *data_buffer, size_t data_buffer_size,
199 void *arg)
200{
201 control_transfer_info_t *transfer
202 = malloc(sizeof(control_transfer_info_t));
203
204 transfer->direction = direction;
205 transfer->target = target;
206 transfer->in_callback = NULL;
207 transfer->out_callback = NULL;
208 transfer->arg = arg;
209 transfer->dev = dev;
210 transfer->data_buffer = data_buffer;
211 transfer->data_buffer_size = data_buffer_size;
[c4ba29c7]212
213 return transfer;
214}
215
[4317827]216static int enqueue_transfer_out(device_t *dev,
217 usb_target_t target, usb_transfer_type_t transfer_type,
[63b4f90]218 void *buffer, size_t size,
[4317827]219 usbhc_iface_transfer_out_callback_t callback, void *arg)
[63b4f90]220{
[0b31409]221 usb_log_debug2("Transfer OUT [%d.%d (%s); %zu].\n",
[4317827]222 target.address, target.endpoint,
223 usb_str_transfer_type(transfer_type),
[63b4f90]224 size);
[c4ba29c7]225
226 transfer_info_t *transfer
[4317827]227 = create_transfer_info(dev, USB_DIRECTION_OUT, arg);
[c4ba29c7]228 transfer->out_callback = callback;
229
[76daaf9f]230 hc_add_transaction_to_device(false, target, transfer_type, buffer, size,
[c4ba29c7]231 universal_callback, transfer);
232
233 return EOK;
[63b4f90]234}
235
[4317827]236static int enqueue_transfer_setup(device_t *dev,
237 usb_target_t target, usb_transfer_type_t transfer_type,
[63b4f90]238 void *buffer, size_t size,
[4317827]239 usbhc_iface_transfer_out_callback_t callback, void *arg)
[63b4f90]240{
[0b31409]241 usb_log_debug2("Transfer SETUP [%d.%d (%s); %zu].\n",
[4317827]242 target.address, target.endpoint,
243 usb_str_transfer_type(transfer_type),
[63b4f90]244 size);
[c4ba29c7]245
246 transfer_info_t *transfer
[4317827]247 = create_transfer_info(dev, USB_DIRECTION_OUT, arg);
[c4ba29c7]248 transfer->out_callback = callback;
249
[76daaf9f]250 hc_add_transaction_to_device(true, target, transfer_type, buffer, size,
[c4ba29c7]251 universal_callback, transfer);
252
253 return EOK;
[63b4f90]254}
255
[4317827]256static int enqueue_transfer_in(device_t *dev,
257 usb_target_t target, usb_transfer_type_t transfer_type,
[63b4f90]258 void *buffer, size_t size,
[4317827]259 usbhc_iface_transfer_in_callback_t callback, void *arg)
[63b4f90]260{
[0b31409]261 usb_log_debug2("Transfer IN [%d.%d (%s); %zu].\n",
[4317827]262 target.address, target.endpoint,
263 usb_str_transfer_type(transfer_type),
[63b4f90]264 size);
[c4ba29c7]265
266 transfer_info_t *transfer
[4317827]267 = create_transfer_info(dev, USB_DIRECTION_IN, arg);
[c4ba29c7]268 transfer->in_callback = callback;
269
[76daaf9f]270 hc_add_transaction_from_device(target, transfer_type, buffer, size,
[c4ba29c7]271 universal_callback, transfer);
272
273 return EOK;
[63b4f90]274}
275
276
[4317827]277static int interrupt_out(device_t *dev, usb_target_t target,
[ec59693]278 size_t max_packet_size,
[4317827]279 void *data, size_t size,
280 usbhc_iface_transfer_out_callback_t callback, void *arg)
281{
282 return enqueue_transfer_out(dev, target, USB_TRANSFER_INTERRUPT,
283 data, size,
284 callback, arg);
285}
286
287static int interrupt_in(device_t *dev, usb_target_t target,
[ec59693]288 size_t max_packet_size,
[4317827]289 void *data, size_t size,
290 usbhc_iface_transfer_in_callback_t callback, void *arg)
291{
292 return enqueue_transfer_in(dev, target, USB_TRANSFER_INTERRUPT,
293 data, size,
294 callback, arg);
295}
296
297static int control_write_setup(device_t *dev, usb_target_t target,
[ec59693]298 size_t max_packet_size,
[4317827]299 void *data, size_t size,
300 usbhc_iface_transfer_out_callback_t callback, void *arg)
301{
302 return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
303 data, size,
304 callback, arg);
305}
306
307static int control_write_data(device_t *dev, usb_target_t target,
[ec59693]308 size_t max_packet_size,
[4317827]309 void *data, size_t size,
310 usbhc_iface_transfer_out_callback_t callback, void *arg)
311{
312 return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
313 data, size,
314 callback, arg);
315}
316
317static int control_write_status(device_t *dev, usb_target_t target,
318 usbhc_iface_transfer_in_callback_t callback, void *arg)
319{
320 return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
321 NULL, 0,
322 callback, arg);
323}
324
[284c629]325static int control_write(device_t *dev, usb_target_t target,
[ec59693]326 size_t max_packet_size,
[284c629]327 void *setup_packet, size_t setup_packet_size,
328 void *data, size_t data_size,
329 usbhc_iface_transfer_out_callback_t callback, void *arg)
330{
331 control_transfer_info_t *transfer
332 = create_control_transfer_info(dev, USB_DIRECTION_OUT, target,
333 data, data_size, arg);
334 transfer->out_callback = callback;
335
336 hc_add_transaction_to_device(true, target, USB_TRANSFER_CONTROL,
337 setup_packet, setup_packet_size,
338 control_callback_one, transfer);
339
340 return EOK;
341}
342
[4317827]343static int control_read_setup(device_t *dev, usb_target_t target,
[ec59693]344 size_t max_packet_size,
[4317827]345 void *data, size_t size,
346 usbhc_iface_transfer_out_callback_t callback, void *arg)
347{
348 return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
349 data, size,
350 callback, arg);
351}
352
353static int control_read_data(device_t *dev, usb_target_t target,
[ec59693]354 size_t max_packet_size,
[4317827]355 void *data, size_t size,
356 usbhc_iface_transfer_in_callback_t callback, void *arg)
357{
358 return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
359 data, size,
360 callback, arg);
361}
362
363static int control_read_status(device_t *dev, usb_target_t target,
364 usbhc_iface_transfer_out_callback_t callback, void *arg)
365{
366 return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
367 NULL, 0,
368 callback, arg);
369}
370
[284c629]371static int control_read(device_t *dev, usb_target_t target,
[ec59693]372 size_t max_packet_size,
[284c629]373 void *setup_packet, size_t setup_packet_size,
374 void *data, size_t data_size,
375 usbhc_iface_transfer_in_callback_t callback, void *arg)
376{
377 control_transfer_info_t *transfer
378 = create_control_transfer_info(dev, USB_DIRECTION_IN, target,
379 data, data_size, arg);
380 transfer->in_callback = callback;
381
382 hc_add_transaction_to_device(true, target, USB_TRANSFER_CONTROL,
383 setup_packet, setup_packet_size,
384 control_callback_one, transfer);
385
386 return EOK;
387}
388
[be9cbec]389static usb_address_keeping_t addresses;
390
391
[6427cf67]392static int reserve_default_address(device_t *dev, bool ignored)
[be9cbec]393{
394 usb_address_keeping_reserve_default(&addresses);
395 return EOK;
396}
397
398static int release_default_address(device_t *dev)
399{
400 usb_address_keeping_release_default(&addresses);
401 return EOK;
402}
403
[6427cf67]404static int request_address(device_t *dev, bool ignored, usb_address_t *address)
[be9cbec]405{
406 usb_address_t addr = usb_address_keeping_request(&addresses);
407 if (addr < 0) {
408 return (int)addr;
409 }
410
411 *address = addr;
412 return EOK;
413}
414
415static int release_address(device_t *dev, usb_address_t address)
416{
417 return usb_address_keeping_release(&addresses, address);
418}
419
420static int bind_address(device_t *dev, usb_address_t address,
421 devman_handle_t handle)
422{
423 usb_address_keeping_devman_bind(&addresses, address, handle);
424 return EOK;
425}
426
427static int tell_address(device_t *dev, devman_handle_t handle,
428 usb_address_t *address)
429{
430 usb_address_t addr = usb_address_keeping_find(&addresses, handle);
431 if (addr < 0) {
432 return addr;
433 }
434
435 *address = addr;
436 return EOK;
437}
438
439void address_init(void)
440{
441 usb_address_keeping_init(&addresses, 50);
442}
[4317827]443
444usbhc_iface_t vhc_iface = {
[ce687bbe]445 .tell_address = tell_address,
[ad104e0]446
447 .reserve_default_address = reserve_default_address,
448 .release_default_address = release_default_address,
449 .request_address = request_address,
[ce687bbe]450 .bind_address = bind_address,
[ad104e0]451 .release_address = release_address,
452
[4317827]453 .interrupt_out = interrupt_out,
454 .interrupt_in = interrupt_in,
[ad104e0]455
[4317827]456 .control_write_setup = control_write_setup,
457 .control_write_data = control_write_data,
458 .control_write_status = control_write_status,
[ad104e0]459
[284c629]460 .control_write = control_write,
461
[4317827]462 .control_read_setup = control_read_setup,
463 .control_read_data = control_read_data,
[284c629]464 .control_read_status = control_read_status,
465
466 .control_read = control_read
[63b4f90]467};
468
[b371844]469/**
470 * @}
471 */
Note: See TracBrowser for help on using the repository browser.