Ignore:
File:
1 edited

Legend:

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

    rd6f78857 rf241b05b  
    4242static int uhci_clean_finished(void *arg);
    4343static int uhci_debug_checker(void *arg);
     44static bool allowed_usb_packet(
     45        bool low_speed, usb_transfer_type_t, size_t size);
    4446
    4547int uhci_init(uhci_t *instance, void *regs, size_t reg_size)
     
    8486
    8587        const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list);
    86 
    8788        pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa);
     89
     90        list_initialize(&instance->tracker_list);
    8891
    8992        instance->cleaner = fibril_create(uhci_clean_finished, instance);
     
    9396        fibril_add_ready(instance->debug_checker);
    9497
    95         /* Start the hc with large(64b) packet FSBR */
     98        /* Start the hc with large(64B) packet FSBR */
    9699        pio_write_16(&instance->registers->usbcmd,
    97100            UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET);
     
    147150}
    148151/*----------------------------------------------------------------------------*/
    149 int 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");
     152int uhci_schedule(uhci_t *instance, tracker_t *tracker)
     153{
     154        assert(instance);
     155        assert(tracker);
     156        const int low_speed = (tracker->speed == LOW_SPEED);
     157        if (!allowed_usb_packet(
     158            low_speed, tracker->transfer_type, tracker->packet_size)) {
     159                usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n",
     160                          low_speed ? "LOW" : "FULL" , tracker->transfer_type,
     161                    tracker->packet_size);
    165162                return ENOTSUP;
    166163        }
    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");
    214 
    215         return EOK;
    216 }
    217 /*---------------------------------------------------------------------------*/
     164        /* TODO: check available bandwith here */
     165
     166        transfer_list_t *list =
     167            instance->transfers[low_speed][tracker->transfer_type];
     168        assert(list);
     169        transfer_list_add_tracker(list, tracker);
     170        list_append(&tracker->link, &instance->tracker_list);
     171
     172        return EOK;
     173}
     174/*----------------------------------------------------------------------------*/
    218175int uhci_clean_finished(void* arg)
    219176{
     
    223180
    224181        while(1) {
    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) );
     182                /* tracker iteration */
     183                link_t *current = instance->tracker_list.next;
     184                while (current != &instance->tracker_list)
     185                {
     186                        link_t *next = current->next;
     187                        tracker_t *tracker = list_get_instance(current, tracker_t, link);
     188
     189                        assert(current == &tracker->link);
     190                        assert(tracker);
     191                        assert(tracker->next_step);
     192                        assert(tracker->td);
     193
     194                        if (!transfer_descriptor_is_active(tracker->td)) {
     195                                usb_log_info("Found inactive tracker with status: %x.\n",
     196                                    tracker->td->status);
     197                                list_remove(current);
     198                                tracker->next_step(tracker);
    241199                        }
    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;
     200                        current = next;
    255201                }
    256202                async_usleep(UHCI_CLEANER_TIMEOUT);
     
    311257        return 0;
    312258}
     259/*----------------------------------------------------------------------------*/
     260bool allowed_usb_packet(
     261        bool low_speed, usb_transfer_type_t transfer, size_t size)
     262{
     263        /* see USB specification chapter 5.5-5.8 for magic numbers used here */
     264        switch(transfer) {
     265                case USB_TRANSFER_ISOCHRONOUS:
     266                        return (!low_speed && size < 1024);
     267                case USB_TRANSFER_INTERRUPT:
     268                        return size <= (low_speed ? 8 : 64);
     269                case USB_TRANSFER_CONTROL: /* device specifies its own max size */
     270                        return (size <= (low_speed ? 8 : 64));
     271                case USB_TRANSFER_BULK: /* device specifies its own max size */
     272                        return (!low_speed && size <= 64);
     273        }
     274        return false;
     275}
    313276/**
    314277 * @}
Note: See TracChangeset for help on using the changeset viewer.