00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00034 #include <errno.h>
00035 #include <str_error.h>
00036
00037 #include <usb/usb.h>
00038 #include <usb/debug.h>
00039
00040 #include "batch.h"
00041 #include "transfer_list.h"
00042 #include "hw_struct/transfer_descriptor.h"
00043 #include "utils/malloc32.h"
00044
00045 #define DEFAULT_ERROR_COUNT 3
00046
00048 typedef struct uhci_transfer_batch {
00053 qh_t *qh;
00055 td_t *tds;
00057 size_t td_count;
00059 void *device_buffer;
00060 } uhci_transfer_batch_t;
00061
00062 static void batch_control(usb_transfer_batch_t *instance,
00063 usb_packet_id data_stage, usb_packet_id status_stage);
00064 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid);
00065
00070 static void uhci_transfer_batch_dispose(void *uhci_batch)
00071 {
00072 uhci_transfer_batch_t *instance = uhci_batch;
00073 assert(instance);
00074 free32(instance->device_buffer);
00075 free(instance);
00076 }
00077
00096 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
00097 char *buffer, size_t buffer_size,
00098 const char* setup_buffer, size_t setup_size,
00099 usbhc_iface_transfer_in_callback_t func_in,
00100 usbhc_iface_transfer_out_callback_t func_out, void *arg)
00101 {
00102 assert(ep);
00103 assert(func_in == NULL || func_out == NULL);
00104 assert(func_in != NULL || func_out != NULL);
00105
00106 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
00107 if (ptr == NULL) { \
00108 usb_log_error(message); \
00109 if (uhci_data) { \
00110 uhci_transfer_batch_dispose(uhci_data); \
00111 } \
00112 return NULL; \
00113 } else (void)0
00114
00115 uhci_transfer_batch_t *uhci_data =
00116 malloc(sizeof(uhci_transfer_batch_t));
00117 CHECK_NULL_DISPOSE_RETURN(uhci_data,
00118 "Failed to allocate UHCI batch.\n");
00119 bzero(uhci_data, sizeof(uhci_transfer_batch_t));
00120
00121 uhci_data->td_count =
00122 (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
00123 if (ep->transfer_type == USB_TRANSFER_CONTROL) {
00124 uhci_data->td_count += 2;
00125 }
00126
00127 assert((sizeof(td_t) % 16) == 0);
00128 const size_t total_size = (sizeof(td_t) * uhci_data->td_count)
00129 + sizeof(qh_t) + setup_size + buffer_size;
00130 uhci_data->device_buffer = malloc32(total_size);
00131 CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,
00132 "Failed to allocate UHCI buffer.\n");
00133 bzero(uhci_data->device_buffer, total_size);
00134
00135 uhci_data->tds = uhci_data->device_buffer;
00136 uhci_data->qh =
00137 (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));
00138
00139 qh_init(uhci_data->qh);
00140 qh_set_element_td(uhci_data->qh, uhci_data->tds);
00141
00142 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
00143 CHECK_NULL_DISPOSE_RETURN(instance,
00144 "Failed to allocate batch instance.\n");
00145 void *setup =
00146 uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)
00147 + sizeof(qh_t);
00148 void *data_buffer = setup + setup_size;
00149 usb_target_t target =
00150 { .address = ep->address, .endpoint = ep->endpoint };
00151 usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size,
00152 setup, setup_size, func_in, func_out, arg, fun,
00153 uhci_data, uhci_transfer_batch_dispose);
00154
00155 memcpy(instance->setup_buffer, setup_buffer, setup_size);
00156 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
00157 instance, target.address, target.endpoint);
00158 return instance;
00159 }
00160
00170 bool batch_is_complete(usb_transfer_batch_t *instance)
00171 {
00172 assert(instance);
00173 uhci_transfer_batch_t *data = instance->private_data;
00174 assert(data);
00175
00176 usb_log_debug2("Batch(%p) checking %zu transfer(s) for completion.\n",
00177 instance, data->td_count);
00178 instance->transfered_size = 0;
00179 size_t i = 0;
00180 for (;i < data->td_count; ++i) {
00181 if (td_is_active(&data->tds[i])) {
00182 return false;
00183 }
00184
00185 instance->error = td_status(&data->tds[i]);
00186 if (instance->error != EOK) {
00187 usb_log_debug("Batch(%p) found error TD(%zu):%"
00188 PRIx32 ".\n", instance, i, data->tds[i].status);
00189 td_print_status(&data->tds[i]);
00190
00191 assert(instance->ep != NULL);
00192 endpoint_toggle_set(instance->ep,
00193 td_toggle(&data->tds[i]));
00194 if (i > 0)
00195 goto substract_ret;
00196 return true;
00197 }
00198
00199 instance->transfered_size += td_act_size(&data->tds[i]);
00200 if (td_is_short(&data->tds[i]))
00201 goto substract_ret;
00202 }
00203 substract_ret:
00204 instance->transfered_size -= instance->setup_size;
00205 return true;
00206 }
00207
00214 void batch_control_write(usb_transfer_batch_t *instance)
00215 {
00216 assert(instance);
00217
00218 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
00219 batch_control(instance, USB_PID_OUT, USB_PID_IN);
00220 instance->next_step = usb_transfer_batch_call_out_and_dispose;
00221 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
00222 }
00223
00230 void batch_control_read(usb_transfer_batch_t *instance)
00231 {
00232 assert(instance);
00233 batch_control(instance, USB_PID_IN, USB_PID_OUT);
00234 instance->next_step = usb_transfer_batch_call_in_and_dispose;
00235 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
00236 }
00237
00244 void batch_interrupt_in(usb_transfer_batch_t *instance)
00245 {
00246 assert(instance);
00247 batch_data(instance, USB_PID_IN);
00248 instance->next_step = usb_transfer_batch_call_in_and_dispose;
00249 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
00250 }
00251
00258 void batch_interrupt_out(usb_transfer_batch_t *instance)
00259 {
00260 assert(instance);
00261
00262 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
00263 batch_data(instance, USB_PID_OUT);
00264 instance->next_step = usb_transfer_batch_call_out_and_dispose;
00265 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
00266 }
00267
00274 void batch_bulk_in(usb_transfer_batch_t *instance)
00275 {
00276 assert(instance);
00277 batch_data(instance, USB_PID_IN);
00278 instance->next_step = usb_transfer_batch_call_in_and_dispose;
00279 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
00280 }
00281
00288 void batch_bulk_out(usb_transfer_batch_t *instance)
00289 {
00290 assert(instance);
00291
00292 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
00293 batch_data(instance, USB_PID_OUT);
00294 instance->next_step = usb_transfer_batch_call_out_and_dispose;
00295 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
00296 }
00297
00306 void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid)
00307 {
00308 assert(instance);
00309 uhci_transfer_batch_t *data = instance->private_data;
00310 assert(data);
00311
00312 const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
00313 int toggle = endpoint_toggle_get(instance->ep);
00314 assert(toggle == 0 || toggle == 1);
00315
00316 size_t td = 0;
00317 size_t remain_size = instance->buffer_size;
00318 char *buffer = instance->data_buffer;
00319 while (remain_size > 0) {
00320 const size_t packet_size =
00321 (instance->ep->max_packet_size > remain_size) ?
00322 remain_size : instance->ep->max_packet_size;
00323
00324 td_t *next_td = (td + 1 < data->td_count)
00325 ? &data->tds[td + 1] : NULL;
00326
00327
00328 usb_target_t target =
00329 { instance->ep->address, instance->ep->endpoint };
00330
00331 assert(td < data->td_count);
00332 td_init(
00333 &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
00334 toggle, false, low_speed, target, pid, buffer, next_td);
00335
00336 ++td;
00337 toggle = 1 - toggle;
00338 buffer += packet_size;
00339 assert(packet_size <= remain_size);
00340 remain_size -= packet_size;
00341 }
00342 td_set_ioc(&data->tds[td - 1]);
00343 endpoint_toggle_set(instance->ep, toggle);
00344 }
00345
00357 void batch_control(usb_transfer_batch_t *instance,
00358 usb_packet_id data_stage, usb_packet_id status_stage)
00359 {
00360 assert(instance);
00361 uhci_transfer_batch_t *data = instance->private_data;
00362 assert(data);
00363 assert(data->td_count >= 2);
00364
00365 const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
00366 const usb_target_t target =
00367 { instance->ep->address, instance->ep->endpoint };
00368
00369
00370 td_init(
00371 data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false,
00372 low_speed, target, USB_PID_SETUP, instance->setup_buffer,
00373 &data->tds[1]);
00374
00375
00376 size_t td = 1;
00377 unsigned toggle = 1;
00378 size_t remain_size = instance->buffer_size;
00379 char *buffer = instance->data_buffer;
00380 while (remain_size > 0) {
00381 const size_t packet_size =
00382 (instance->ep->max_packet_size > remain_size) ?
00383 remain_size : instance->ep->max_packet_size;
00384
00385 td_init(
00386 &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
00387 toggle, false, low_speed, target, data_stage,
00388 buffer, &data->tds[td + 1]);
00389
00390 ++td;
00391 toggle = 1 - toggle;
00392 buffer += packet_size;
00393 assert(td < data->td_count);
00394 assert(packet_size <= remain_size);
00395 remain_size -= packet_size;
00396 }
00397
00398
00399 assert(td == data->td_count - 1);
00400
00401 td_init(
00402 &data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
00403 target, status_stage, NULL, NULL);
00404 td_set_ioc(&data->tds[td]);
00405
00406 usb_log_debug2("Control last TD status: %x.\n",
00407 data->tds[td].status);
00408 }
00409
00415 qh_t * batch_qh(usb_transfer_batch_t *instance)
00416 {
00417 assert(instance);
00418 uhci_transfer_batch_t *data = instance->private_data;
00419 assert(data);
00420 return data->qh;
00421 }