Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-hcd/uhci.c

    r3cc5ccda rd6f78857  
    3333 */
    3434#include <errno.h>
    35 #include <adt/list.h>
    3635
    3736#include <usb/debug.h>
     
    4342static int uhci_clean_finished(void *arg);
    4443static int uhci_debug_checker(void *arg);
    45 static bool allowed_usb_packet(
    46         bool low_speed, usb_transfer_type_t, size_t size);
    4744
    4845int uhci_init(uhci_t *instance, void *regs, size_t reg_size)
     
    8784
    8885        const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list);
     86
    8987        pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa);
    90 
    91         list_initialize(&instance->tracker_list);
    92         fibril_mutex_initialize(&instance->tracker_list_mutex);
    9388
    9489        instance->cleaner = fibril_create(uhci_clean_finished, instance);
     
    9893        fibril_add_ready(instance->debug_checker);
    9994
    100         /* Start the hc with large(64B) packet FSBR */
     95        /* Start the hc with large(64b) packet FSBR */
    10196        pio_write_16(&instance->registers->usbcmd,
    10297            UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET);
     
    152147}
    153148/*----------------------------------------------------------------------------*/
    154 int uhci_schedule(uhci_t *instance, tracker_t *tracker)
    155 {
    156         assert(instance);
    157         assert(tracker);
    158         const int low_speed = (tracker->speed == LOW_SPEED);
    159         if (!allowed_usb_packet(
    160             low_speed, tracker->transfer_type, tracker->packet_size)) {
    161                 usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n",
    162                           low_speed ? "LOW" : "FULL" , tracker->transfer_type,
    163                     tracker->packet_size);
     149int uhci_transfer(
     150  uhci_t *instance,
     151  device_t *dev,
     152  usb_target_t target,
     153  usb_transfer_type_t transfer_type,
     154        bool toggle,
     155  usb_packet_id pid,
     156        bool low_speed,
     157  void *buffer, size_t size,
     158  usbhc_iface_transfer_out_callback_t callback_out,
     159  usbhc_iface_transfer_in_callback_t callback_in,
     160  void *arg)
     161{
     162        // TODO: Add support for isochronous transfers
     163        if (transfer_type == USB_TRANSFER_ISOCHRONOUS) {
     164                usb_log_warning("ISO transfer not supported.\n");
    164165                return ENOTSUP;
    165166        }
    166         /* TODO: check available bandwith here */
    167 
    168         usb_log_debug2("Scheduler(%d) acquiring tracker list mutex.\n",
    169             fibril_get_id());
    170         fibril_mutex_lock(&instance->tracker_list_mutex);
    171         usb_log_debug2("Scheduler(%d) acquired tracker list mutex.\n",
    172             fibril_get_id());
    173 
    174         transfer_list_t *list =
    175             instance->transfers[low_speed][tracker->transfer_type];
    176         assert(list);
    177         transfer_list_add_tracker(list, tracker);
    178         list_append(&tracker->link, &instance->tracker_list);
    179 
    180         usb_log_debug2("Scheduler(%d) releasing tracker list mutex.\n",
    181             fibril_get_id());
    182         fibril_mutex_unlock(&instance->tracker_list_mutex);
    183         usb_log_debug2("Scheduler(%d) released tracker list mutex.\n",
    184             fibril_get_id());
     167
     168        if (transfer_type == USB_TRANSFER_INTERRUPT
     169          && size >= 64) {
     170                usb_log_warning("Interrupt transfer too big %zu.\n", size);
     171                return ENOTSUP;
     172        }
     173
     174        if (size >= 1024) {
     175                usb_log_warning("Transfer too big.\n");
     176                return ENOTSUP;
     177        }
     178        transfer_list_t *list = instance->transfers[low_speed][transfer_type];
     179        if (!list) {
     180                usb_log_warning("UNSUPPORTED transfer %d-%d.\n", low_speed, transfer_type);
     181                return ENOTSUP;
     182        }
     183
     184        transfer_descriptor_t *td = NULL;
     185        callback_t *job = NULL;
     186        int ret = EOK;
     187        assert(dev);
     188
     189#define CHECK_RET_TRANS_FREE_JOB_TD(message) \
     190        if (ret != EOK) { \
     191                usb_log_error(message); \
     192                if (job) { \
     193                        callback_dispose(job); \
     194                } \
     195                if (td) { free32(td); } \
     196                return ret; \
     197        } else (void) 0
     198
     199        job = callback_get(dev, buffer, size, callback_in, callback_out, arg);
     200        ret = job ? EOK : ENOMEM;
     201        CHECK_RET_TRANS_FREE_JOB_TD("Failed to allocate callback structure.\n");
     202
     203        td = transfer_descriptor_get(3, size, false, target, pid, job->new_buffer);
     204        ret = td ? EOK : ENOMEM;
     205        CHECK_RET_TRANS_FREE_JOB_TD("Failed to setup transfer descriptor.\n");
     206
     207        td->callback = job;
     208
     209
     210        usb_log_debug("Appending a new transfer to queue %s.\n", list->name);
     211
     212        ret = transfer_list_append(list, td);
     213        CHECK_RET_TRANS_FREE_JOB_TD("Failed to append transfer descriptor.\n");
    185214
    186215        return EOK;
    187216}
    188 /*----------------------------------------------------------------------------*/
     217/*---------------------------------------------------------------------------*/
    189218int uhci_clean_finished(void* arg)
    190219{
     
    194223
    195224        while(1) {
    196                 LIST_INITIALIZE(done_trackers);
    197                 /* tracker iteration */
    198 
    199                 usb_log_debug2("Cleaner(%d) acquiring tracker list mutex.\n",
    200                     fibril_get_id());
    201                 fibril_mutex_lock(&instance->tracker_list_mutex);
    202                 usb_log_debug2("Cleaner(%d) acquired tracker list mutex.\n",
    203                     fibril_get_id());
    204 
    205                 link_t *current = instance->tracker_list.next;
    206                 while (current != &instance->tracker_list)
    207                 {
    208 
    209                         link_t *next = current->next;
    210                         tracker_t *tracker = list_get_instance(current, tracker_t, link);
    211 
    212                         assert(current == &tracker->link);
    213                         assert(tracker);
    214                         assert(tracker->next_step);
    215                         assert(tracker->td);
    216 
    217                         if (!transfer_descriptor_is_active(tracker->td)) {
    218                                 usb_log_info("Found inactive tracker with status: %x:%x.\n",
    219                                     tracker->td->status, tracker->td->device);
    220                                 list_remove(current);
    221                                 list_append(current, &done_trackers);
     225                usb_log_debug("Running cleaning fibril on: %p.\n", instance);
     226                /* iterate all transfer queues */
     227                transfer_list_t *current_list = &instance->transfers_interrupt;
     228                while (current_list) {
     229                        /* Remove inactive transfers from the top of the queue
     230                         * TODO: should I reach queue head or is this enough? */
     231                        volatile transfer_descriptor_t * it =
     232                                current_list->first;
     233                        usb_log_debug("Running cleaning fibril on queue: %s (%s).\n",
     234                                current_list->name, it ? "SOMETHING" : "EMPTY");
     235
     236                        if (it) {
     237                                usb_log_debug("First in queue: %p (%x) PA:%x.\n",
     238                                        it, it->status, addr_to_phys((void*)it) );
     239                                usb_log_debug("First to send: %x\n",
     240                                        (current_list->queue_head->element) );
    222241                        }
    223                         current = next;
    224                 }
    225 
    226                 usb_log_debug2("Cleaner(%d) releasing tracker list mutex.\n",
    227                     fibril_get_id());
    228                 fibril_mutex_unlock(&instance->tracker_list_mutex);
    229                 usb_log_debug2("Cleaner(%d) released tracker list mutex.\n",
    230                     fibril_get_id());
    231 
    232                 while (!list_empty(&done_trackers)) {
    233                         tracker_t *tracker = list_get_instance(
    234                           done_trackers.next, tracker_t, link);
    235                         list_remove(&tracker->link);
    236                         tracker->next_step(tracker);
     242
     243                        while (current_list->first &&
     244                         !(current_list->first->status & TD_STATUS_ERROR_ACTIVE)) {
     245                                transfer_descriptor_t *transfer = current_list->first;
     246                                usb_log_info("Inactive transfer calling callback with status %x.\n",
     247                                  transfer->status);
     248                                current_list->first = transfer->next_va;
     249                                transfer_descriptor_dispose(transfer);
     250                        }
     251                        if (!current_list->first)
     252                                current_list->last = current_list->first;
     253
     254                        current_list = current_list->next;
    237255                }
    238256                async_usleep(UHCI_CLEANER_TIMEOUT);
     
    293311        return 0;
    294312}
    295 /*----------------------------------------------------------------------------*/
    296 bool allowed_usb_packet(
    297         bool low_speed, usb_transfer_type_t transfer, size_t size)
    298 {
    299         /* see USB specification chapter 5.5-5.8 for magic numbers used here */
    300         switch(transfer) {
    301                 case USB_TRANSFER_ISOCHRONOUS:
    302                         return (!low_speed && size < 1024);
    303                 case USB_TRANSFER_INTERRUPT:
    304                         return size <= (low_speed ? 8 : 64);
    305                 case USB_TRANSFER_CONTROL: /* device specifies its own max size */
    306                         return (size <= (low_speed ? 8 : 64));
    307                 case USB_TRANSFER_BULK: /* device specifies its own max size */
    308                         return (!low_speed && size <= 64);
    309         }
    310         return false;
    311 }
    312313/**
    313314 * @}
Note: See TracChangeset for help on using the changeset viewer.