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 "hcd_endpoint.h"
00042 #include "utils/malloc32.h"
00043 #include "hw_struct/endpoint_descriptor.h"
00044 #include "hw_struct/transfer_descriptor.h"
00045
00047 typedef struct ohci_transfer_batch {
00049 ed_t *ed;
00051 td_t **tds;
00053 size_t td_count;
00055 size_t leave_td;
00057 void *device_buffer;
00058 } ohci_transfer_batch_t;
00059
00060 static void batch_control(usb_transfer_batch_t *instance,
00061 usb_direction_t data_dir, usb_direction_t status_dir);
00062 static void batch_data(usb_transfer_batch_t *instance);
00063
00068 static void ohci_transfer_batch_dispose(void *ohci_batch)
00069 {
00070 ohci_transfer_batch_t *instance = ohci_batch;
00071 if (!instance)
00072 return;
00073 free32(instance->device_buffer);
00074 unsigned i = 0;
00075 if (instance->tds) {
00076 for (; i< instance->td_count; ++i) {
00077 if (i != instance->leave_td)
00078 free32(instance->tds[i]);
00079 }
00080 free(instance->tds);
00081 }
00082 free(instance);
00083 }
00084
00101 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
00102 char *buffer, size_t buffer_size,
00103 const char *setup_buffer, size_t setup_size,
00104 usbhc_iface_transfer_in_callback_t func_in,
00105 usbhc_iface_transfer_out_callback_t func_out, void *arg)
00106 {
00107 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
00108 if (ptr == NULL) { \
00109 usb_log_error(message); \
00110 if (instance) { \
00111 usb_transfer_batch_dispose(instance); \
00112 } \
00113 return NULL; \
00114 } else (void)0
00115
00116 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
00117 CHECK_NULL_DISPOSE_RETURN(instance,
00118 "Failed to allocate batch instance.\n");
00119 usb_transfer_batch_init(instance, ep, buffer, NULL, buffer_size,
00120 NULL, setup_size, func_in, func_out, arg, fun, NULL,
00121 ohci_transfer_batch_dispose);
00122
00123 const hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
00124 assert(hcd_ep);
00125
00126 ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1);
00127 CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
00128 instance->private_data = data;
00129
00130 data->td_count =
00131 ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER);
00132
00133 if (ep->transfer_type == USB_TRANSFER_CONTROL) {
00134 data->td_count += 2;
00135 }
00136
00137
00138 data->tds = calloc(sizeof(td_t*), data->td_count + 1);
00139 CHECK_NULL_DISPOSE_RETURN(data->tds,
00140 "Failed to allocate transfer descriptors.\n");
00141
00142
00143 data->tds[0] = hcd_ep->td;
00144 data->leave_td = 0;
00145 unsigned i = 1;
00146 for (; i <= data->td_count; ++i) {
00147 data->tds[i] = malloc32(sizeof(td_t));
00148 CHECK_NULL_DISPOSE_RETURN(data->tds[i],
00149 "Failed to allocate TD %d.\n", i );
00150 }
00151
00152 data->ed = hcd_ep->ed;
00153
00154
00155
00156
00157
00158 if (setup_size + buffer_size > 0) {
00159 data->device_buffer = malloc32(setup_size + buffer_size);
00160 CHECK_NULL_DISPOSE_RETURN(data->device_buffer,
00161 "Failed to allocate device accessible buffer.\n");
00162 instance->setup_buffer = data->device_buffer;
00163 instance->data_buffer = data->device_buffer + setup_size;
00164 memcpy(instance->setup_buffer, setup_buffer, setup_size);
00165 }
00166
00167 return instance;
00168 }
00169
00179 bool batch_is_complete(usb_transfer_batch_t *instance)
00180 {
00181 assert(instance);
00182 ohci_transfer_batch_t *data = instance->private_data;
00183 assert(data);
00184 usb_log_debug("Batch(%p) checking %zu td(s) for completion.\n",
00185 instance, data->td_count);
00186 usb_log_debug("ED: %x:%x:%x:%x.\n",
00187 data->ed->status, data->ed->td_head, data->ed->td_tail,
00188 data->ed->next);
00189 size_t i = 0;
00190 instance->transfered_size = instance->buffer_size;
00191 for (; i < data->td_count; ++i) {
00192 assert(data->tds[i] != NULL);
00193 usb_log_debug("TD %zu: %x:%x:%x:%x.\n", i,
00194 data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next,
00195 data->tds[i]->be);
00196 if (!td_is_finished(data->tds[i])) {
00197 return false;
00198 }
00199 instance->error = td_error(data->tds[i]);
00200 if (instance->error != EOK) {
00201 usb_log_debug("Batch(%p) found error TD(%zu):%x.\n",
00202 instance, i, data->tds[i]->status);
00203
00204
00205 data->ed->td_tail =
00206 (data->ed->td_head & ED_TDTAIL_PTR_MASK);
00207 ++i;
00208 break;
00209 }
00210 }
00211 data->leave_td = i;
00212 assert(data->leave_td <= data->td_count);
00213 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(instance->ep);
00214 assert(hcd_ep);
00215 hcd_ep->td = data->tds[i];
00216 assert(i > 0);
00217 for (--i;i < data->td_count; ++i)
00218 instance->transfered_size -= td_remain_size(data->tds[i]);
00219
00220
00221 data->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
00222 const uint32_t pa = addr_to_phys(hcd_ep->td);
00223 assert(pa == (data->ed->td_head & ED_TDHEAD_PTR_MASK));
00224 assert(pa == (data->ed->td_tail & ED_TDTAIL_PTR_MASK));
00225
00226 return true;
00227 }
00228
00233 void batch_commit(usb_transfer_batch_t *instance)
00234 {
00235 assert(instance);
00236 ohci_transfer_batch_t *data = instance->private_data;
00237 assert(data);
00238 ed_set_end_td(data->ed, data->tds[data->td_count]);
00239 }
00240
00248 void batch_control_write(usb_transfer_batch_t *instance)
00249 {
00250 assert(instance);
00251
00252 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
00253 instance->next_step = usb_transfer_batch_call_out_and_dispose;
00254 batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
00255 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
00256 }
00257
00265 void batch_control_read(usb_transfer_batch_t *instance)
00266 {
00267 assert(instance);
00268 instance->next_step = usb_transfer_batch_call_in_and_dispose;
00269 batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
00270 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
00271 }
00272
00279 void batch_interrupt_in(usb_transfer_batch_t *instance)
00280 {
00281 assert(instance);
00282 instance->next_step = usb_transfer_batch_call_in_and_dispose;
00283 batch_data(instance);
00284 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
00285 }
00286
00293 void batch_interrupt_out(usb_transfer_batch_t *instance)
00294 {
00295 assert(instance);
00296
00297 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
00298 instance->next_step = usb_transfer_batch_call_out_and_dispose;
00299 batch_data(instance);
00300 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
00301 }
00302
00309 void batch_bulk_in(usb_transfer_batch_t *instance)
00310 {
00311 assert(instance);
00312 instance->next_step = usb_transfer_batch_call_in_and_dispose;
00313 batch_data(instance);
00314 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
00315 }
00316
00323 void batch_bulk_out(usb_transfer_batch_t *instance)
00324 {
00325 assert(instance);
00326
00327 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
00328 instance->next_step = usb_transfer_batch_call_out_and_dispose;
00329 batch_data(instance);
00330 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
00331 }
00332
00343 void batch_control(usb_transfer_batch_t *instance,
00344 usb_direction_t data_dir, usb_direction_t status_dir)
00345 {
00346 assert(instance);
00347 ohci_transfer_batch_t *data = instance->private_data;
00348 assert(data);
00349 usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
00350 data->ed->status, data->ed->td_tail, data->ed->td_head,
00351 data->ed->next);
00352 int toggle = 0;
00353
00354 td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,
00355 instance->setup_size, toggle);
00356 td_set_next(data->tds[0], data->tds[1]);
00357 usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0]->status,
00358 data->tds[0]->cbp, data->tds[0]->next, data->tds[0]->be);
00359
00360
00361 size_t td_current = 1;
00362 size_t remain_size = instance->buffer_size;
00363 char *buffer = instance->data_buffer;
00364 while (remain_size > 0) {
00365 size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
00366 OHCI_TD_MAX_TRANSFER : remain_size;
00367 toggle = 1 - toggle;
00368
00369 td_init(data->tds[td_current], data_dir, buffer,
00370 transfer_size, toggle);
00371 td_set_next(data->tds[td_current], data->tds[td_current + 1]);
00372 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
00373 data->tds[td_current]->status, data->tds[td_current]->cbp,
00374 data->tds[td_current]->next, data->tds[td_current]->be);
00375
00376 buffer += transfer_size;
00377 remain_size -= transfer_size;
00378 assert(td_current < data->td_count - 1);
00379 ++td_current;
00380 }
00381
00382
00383 assert(td_current == data->td_count - 1);
00384 td_init(data->tds[td_current], status_dir, NULL, 0, 1);
00385 td_set_next(data->tds[td_current], data->tds[td_current + 1]);
00386 usb_log_debug("Created STATUS TD: %x:%x:%x:%x.\n",
00387 data->tds[td_current]->status, data->tds[td_current]->cbp,
00388 data->tds[td_current]->next, data->tds[td_current]->be);
00389 }
00390
00398 void batch_data(usb_transfer_batch_t *instance)
00399 {
00400 assert(instance);
00401 ohci_transfer_batch_t *data = instance->private_data;
00402 assert(data);
00403 usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
00404 data->ed->status, data->ed->td_tail, data->ed->td_head,
00405 data->ed->next);
00406
00407 size_t td_current = 0;
00408 size_t remain_size = instance->buffer_size;
00409 char *buffer = instance->data_buffer;
00410 while (remain_size > 0) {
00411 const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
00412 ? OHCI_TD_MAX_TRANSFER : remain_size;
00413
00414 td_init(data->tds[td_current], instance->ep->direction,
00415 buffer, transfer_size, -1);
00416 td_set_next(data->tds[td_current], data->tds[td_current + 1]);
00417 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
00418 data->tds[td_current]->status, data->tds[td_current]->cbp,
00419 data->tds[td_current]->next, data->tds[td_current]->be);
00420
00421 buffer += transfer_size;
00422 remain_size -= transfer_size;
00423 assert(td_current < data->td_count);
00424 ++td_current;
00425 }
00426 }