source: mainline/uspace/drv/uhci-hcd/batch.c@ a60150a

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

Track toggle on errors

  • Property mode set to 100644
File size: 12.3 KB
RevLine 
[4192d3d6]1/*
2 * Copyright (c) 2011 Jan Vesely
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/** @addtogroup usb
29 * @{
30 */
31/** @file
32 * @brief UHCI driver
33 */
34#include <errno.h>
[86c2ccd]35#include <str_error.h>
[4192d3d6]36
[bdc8ab1]37#include <usb/usb.h>
[4192d3d6]38#include <usb/debug.h>
39
[83c439c]40#include "batch.h"
[53338bda]41#include "transfer_list.h"
[9a818a9]42#include "uhci.h"
43#include "utils/malloc32.h"
[4192d3d6]44
45#define DEFAULT_ERROR_COUNT 3
46
[83c439c]47static int batch_schedule(batch_t *instance);
[9a818a9]48
[eae83aa]49static void batch_control(batch_t *instance,
50 usb_packet_id data_stage, usb_packet_id status_stage);
[5620bd4]51static void batch_data(batch_t *instance, usb_packet_id pid);
[83c439c]52static void batch_call_in(batch_t *instance);
53static void batch_call_out(batch_t *instance);
54static void batch_call_in_and_dispose(batch_t *instance);
55static void batch_call_out_and_dispose(batch_t *instance);
[a60150a]56static void batch_dispose(batch_t *instance);
[4192d3d6]57
58
[eb1a2f4]59batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
[9a818a9]60 usb_transfer_type_t transfer_type, size_t max_packet_size,
[1a93bb0]61 usb_speed_t speed, char *buffer, size_t size,
[7dd3318]62 char* setup_buffer, size_t setup_size,
[4192d3d6]63 usbhc_iface_transfer_in_callback_t func_in,
[5620bd4]64 usbhc_iface_transfer_out_callback_t func_out, void *arg,
65 device_keeper_t *manager
66 )
[4192d3d6]67{
68 assert(func_in == NULL || func_out == NULL);
69 assert(func_in != NULL || func_out != NULL);
70
[83c439c]71 batch_t *instance = malloc(sizeof(batch_t));
[7dd3318]72 if (instance == NULL) {
[83c439c]73 usb_log_error("Failed to allocate batch instance.\n");
[7dd3318]74 return NULL;
75 }
76
77 instance->qh = queue_head_get();
78 if (instance->qh == NULL) {
79 usb_log_error("Failed to allocate queue head.\n");
80 free(instance);
81 return NULL;
82 }
83
84 instance->packets = (size + max_packet_size - 1) / max_packet_size;
85 if (transfer_type == USB_TRANSFER_CONTROL) {
86 instance->packets += 2;
87 }
88
[c5b93dc]89 instance->tds = malloc32(sizeof(td_t) * instance->packets);
[7dd3318]90 if (instance->tds == NULL) {
91 usb_log_error("Failed to allocate transfer descriptors.\n");
92 queue_head_dispose(instance->qh);
93 free(instance);
[9a818a9]94 return NULL;
95 }
[c5b93dc]96 bzero(instance->tds, sizeof(td_t) * instance->packets);
[9a818a9]97
[7dd3318]98 const size_t transport_size = max_packet_size * instance->packets;
99
100 instance->transport_buffer =
101 (size > 0) ? malloc32(transport_size) : NULL;
[bdc8ab1]102
[7dd3318]103 if ((size > 0) && (instance->transport_buffer == NULL)) {
104 usb_log_error("Failed to allocate device accessible buffer.\n");
105 queue_head_dispose(instance->qh);
106 free32(instance->tds);
[9a818a9]107 free(instance);
108 return NULL;
[4192d3d6]109 }
110
[7dd3318]111 instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL;
112 if ((setup_size > 0) && (instance->setup_buffer == NULL)) {
113 usb_log_error("Failed to allocate device accessible setup buffer.\n");
114 queue_head_dispose(instance->qh);
115 free32(instance->tds);
116 free32(instance->transport_buffer);
[9a818a9]117 free(instance);
118 return NULL;
[4192d3d6]119 }
[7dd3318]120 if (instance->setup_buffer) {
121 memcpy(instance->setup_buffer, setup_buffer, setup_size);
122 }
123
[4192d3d6]124 instance->max_packet_size = max_packet_size;
125
126 link_initialize(&instance->link);
[7dd3318]127
[4192d3d6]128 instance->target = target;
[9a818a9]129 instance->transfer_type = transfer_type;
[4192d3d6]130
131 if (func_out)
132 instance->callback_out = func_out;
133 if (func_in)
134 instance->callback_in = func_in;
[7dd3318]135
[4192d3d6]136 instance->buffer = buffer;
137 instance->buffer_size = size;
[7dd3318]138 instance->setup_size = setup_size;
[eb1a2f4]139 instance->fun = fun;
[4192d3d6]140 instance->arg = arg;
[014d5033]141 instance->speed = speed;
[5620bd4]142 instance->manager = manager;
[9a818a9]143
[7dd3318]144 queue_head_element_td(instance->qh, addr_to_phys(instance->tds));
[4abc304]145 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
146 instance, target.address, target.endpoint);
[9a818a9]147 return instance;
[4192d3d6]148}
149/*----------------------------------------------------------------------------*/
[83c439c]150bool batch_is_complete(batch_t *instance)
[4192d3d6]151{
152 assert(instance);
[48563a3]153 usb_log_debug2("Batch(%p) checking %d packet(s) for completion.\n",
[7dd3318]154 instance, instance->packets);
[600733e]155 instance->transfered_size = 0;
[7dd3318]156 size_t i = 0;
157 for (;i < instance->packets; ++i) {
[c5b93dc]158 if (td_is_active(&instance->tds[i])) {
[7dd3318]159 return false;
[600733e]160 }
[c5b93dc]161
162 instance->error = td_status(&instance->tds[i]);
[7dd3318]163 if (instance->error != EOK) {
[48563a3]164 usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
[c5b93dc]165 instance, i, instance->tds[i].status);
[a60150a]166
167 device_keeper_set_toggle(instance->manager, instance->target,
168 td_toggle(&instance->tds[i]));
[c5b93dc]169 if (i > 0)
170 goto substract_ret;
[7dd3318]171 return true;
172 }
[c5b93dc]173
174 instance->transfered_size += td_act_size(&instance->tds[i]);
175 if (td_is_short(&instance->tds[i]))
176 goto substract_ret;
[4192d3d6]177 }
[c5b93dc]178substract_ret:
[600733e]179 instance->transfered_size -= instance->setup_size;
[7dd3318]180 return true;
[4192d3d6]181}
182/*----------------------------------------------------------------------------*/
[83c439c]183void batch_control_write(batch_t *instance)
[4192d3d6]184{
185 assert(instance);
[7dd3318]186 /* we are data out, we are supposed to provide data */
187 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
[bdc8ab1]188 batch_control(instance, USB_PID_OUT, USB_PID_IN);
[83c439c]189 instance->next_step = batch_call_out_and_dispose;
[4abc304]190 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
[83c439c]191 batch_schedule(instance);
[4192d3d6]192}
193/*----------------------------------------------------------------------------*/
[83c439c]194void batch_control_read(batch_t *instance)
[4192d3d6]195{
196 assert(instance);
[bdc8ab1]197 batch_control(instance, USB_PID_IN, USB_PID_OUT);
[83c439c]198 instance->next_step = batch_call_in_and_dispose;
[4abc304]199 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
[83c439c]200 batch_schedule(instance);
[4192d3d6]201}
202/*----------------------------------------------------------------------------*/
[5620bd4]203void batch_interrupt_in(batch_t *instance)
[4192d3d6]204{
[c8dd5b1]205 assert(instance);
[5620bd4]206 batch_data(instance, USB_PID_IN);
[83c439c]207 instance->next_step = batch_call_in_and_dispose;
[4abc304]208 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
[83c439c]209 batch_schedule(instance);
[4192d3d6]210}
211/*----------------------------------------------------------------------------*/
[5620bd4]212void batch_interrupt_out(batch_t *instance)
[4192d3d6]213{
[c8dd5b1]214 assert(instance);
[7dd3318]215 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
[5620bd4]216 batch_data(instance, USB_PID_OUT);
[0e06a14]217 instance->next_step = batch_call_out_and_dispose;
218 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
219 batch_schedule(instance);
220}
221/*----------------------------------------------------------------------------*/
[5620bd4]222void batch_bulk_in(batch_t *instance)
[0e06a14]223{
224 assert(instance);
[5620bd4]225 batch_data(instance, USB_PID_IN);
[0e06a14]226 instance->next_step = batch_call_in_and_dispose;
227 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
228 batch_schedule(instance);
229}
230/*----------------------------------------------------------------------------*/
[5620bd4]231void batch_bulk_out(batch_t *instance)
[0e06a14]232{
233 assert(instance);
234 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
[5620bd4]235 batch_data(instance, USB_PID_OUT);
[0e06a14]236 instance->next_step = batch_call_out_and_dispose;
237 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
238 batch_schedule(instance);
239}
240/*----------------------------------------------------------------------------*/
[5620bd4]241void batch_data(batch_t *instance, usb_packet_id pid)
[0e06a14]242{
243 assert(instance);
[c3ae877]244 const bool low_speed = instance->speed == USB_SPEED_LOW;
[5620bd4]245 int toggle = device_keeper_get_toggle(instance->manager, instance->target);
[3e37964]246 assert(toggle == 0 || toggle == 1);
[0e06a14]247
248 size_t packet = 0;
249 size_t remain_size = instance->buffer_size;
250 while (remain_size > 0) {
[7dd3318]251 char *data =
[0e06a14]252 instance->transport_buffer + instance->buffer_size
253 - remain_size;
254
[c8dd5b1]255
[0e06a14]256 const size_t packet_size =
257 (instance->max_packet_size > remain_size) ?
258 remain_size : instance->max_packet_size;
[c8dd5b1]259
[c5b93dc]260 td_init(&instance->tds[packet],
[0e06a14]261 DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
262 instance->target, pid, data,
263 &instance->tds[packet + 1]);
[30a4301]264
[3e37964]265 toggle = 1 - toggle;
[0e06a14]266 ++packet;
267 assert(packet <= instance->packets);
268 assert(packet_size <= remain_size);
269 remain_size -= packet_size;
270 }
[5620bd4]271 device_keeper_set_toggle(instance->manager, instance->target, toggle);
[0e06a14]272
273 instance->tds[packet - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
274 instance->tds[packet - 1].next = 0 | LINK_POINTER_TERMINATE_FLAG;
[4192d3d6]275}
276/*----------------------------------------------------------------------------*/
[3e37964]277void batch_control(batch_t *instance,
[eae83aa]278 usb_packet_id data_stage, usb_packet_id status_stage)
[bdc8ab1]279{
280 assert(instance);
281
282 const bool low_speed = instance->speed == USB_SPEED_LOW;
283 int toggle = 0;
284 /* setup stage */
[c5b93dc]285 td_init(instance->tds, DEFAULT_ERROR_COUNT,
[bdc8ab1]286 instance->setup_size, toggle, false, low_speed, instance->target,
287 USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
288
289 /* data stage */
290 size_t packet = 1;
291 size_t remain_size = instance->buffer_size;
292 while (remain_size > 0) {
293 char *data =
294 instance->transport_buffer + instance->buffer_size
295 - remain_size;
296
297 toggle = 1 - toggle;
298
299 const size_t packet_size =
300 (instance->max_packet_size > remain_size) ?
301 remain_size : instance->max_packet_size;
302
[c5b93dc]303 td_init(&instance->tds[packet],
[bdc8ab1]304 DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
305 instance->target, data_stage, data,
306 &instance->tds[packet + 1]);
307
308 ++packet;
309 assert(packet < instance->packets);
310 assert(packet_size <= remain_size);
311 remain_size -= packet_size;
312 }
313
314 /* status stage */
315 assert(packet == instance->packets - 1);
[c5b93dc]316 td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
[bdc8ab1]317 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
318
319
320 instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
321 usb_log_debug2("Control last TD status: %x.\n",
322 instance->tds[packet].status);
323}
324/*----------------------------------------------------------------------------*/
[83c439c]325void batch_call_in(batch_t *instance)
[4192d3d6]326{
327 assert(instance);
328 assert(instance->callback_in);
329
[7dd3318]330 memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size);
331
332 int err = instance->error;
[4abc304]333 usb_log_debug("Batch(%p) callback IN(type:%d): %s(%d), %zu.\n",
[48563a3]334 instance, instance->transfer_type, str_error(err), err,
335 instance->transfered_size);
[7dd3318]336
[eb1a2f4]337 instance->callback_in(instance->fun,
[7dd3318]338 err, instance->transfered_size,
[4192d3d6]339 instance->arg);
340}
341/*----------------------------------------------------------------------------*/
[83c439c]342void batch_call_out(batch_t *instance)
[4192d3d6]343{
344 assert(instance);
345 assert(instance->callback_out);
346
[7dd3318]347 int err = instance->error;
[4abc304]348 usb_log_debug("Batch(%p) callback OUT(type:%d): %s(%d).\n",
[48563a3]349 instance, instance->transfer_type, str_error(err), err);
[eb1a2f4]350 instance->callback_out(instance->fun,
[7dd3318]351 err, instance->arg);
[4192d3d6]352}
353/*----------------------------------------------------------------------------*/
[83c439c]354void batch_call_in_and_dispose(batch_t *instance)
[4192d3d6]355{
356 assert(instance);
[83c439c]357 batch_call_in(instance);
[a60150a]358 batch_dispose(instance);
[4192d3d6]359}
360/*----------------------------------------------------------------------------*/
[83c439c]361void batch_call_out_and_dispose(batch_t *instance)
[4192d3d6]362{
363 assert(instance);
[83c439c]364 batch_call_out(instance);
[a60150a]365 batch_dispose(instance);
366}
367/*----------------------------------------------------------------------------*/
368void batch_dispose(batch_t *instance)
369{
370 assert(instance);
[48563a3]371 usb_log_debug("Batch(%p) disposing.\n", instance);
[7dd3318]372 free32(instance->tds);
373 free32(instance->qh);
374 free32(instance->setup_buffer);
375 free32(instance->transport_buffer);
[4192d3d6]376 free(instance);
377}
[9a818a9]378/*----------------------------------------------------------------------------*/
[83c439c]379int batch_schedule(batch_t *instance)
[9a818a9]380{
381 assert(instance);
[eb1a2f4]382 uhci_t *hc = fun_to_uhci(instance->fun);
[9a818a9]383 assert(hc);
384 return uhci_schedule(hc, instance);
385}
[4192d3d6]386/**
387 * @}
388 */
Note: See TracBrowser for help on using the repository browser.