Changeset 4e38d69 in mainline for uspace/drv/uhci-hcd/uhci.c


Ignore:
Timestamp:
2011-02-11T15:05:40Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5842493
Parents:
1e64b250 (diff), 03197ffc (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merged development/ changes

Warning: this merge breaks some things (the UHCI driver hangs due to
errors introduced in previous revisions).

File:
1 edited

Legend:

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

    r1e64b250 r4e38d69  
    3333 */
    3434#include <errno.h>
     35#include <adt/list.h>
    3536
    3637#include <usb/debug.h>
     
    4243static int uhci_clean_finished(void *arg);
    4344static int uhci_debug_checker(void *arg);
     45static bool allowed_usb_packet(
     46        bool low_speed, usb_transfer_type_t, size_t size);
    4447
    4548int uhci_init(uhci_t *instance, void *regs, size_t reg_size)
     
    8487
    8588        const uintptr_t pa = (uintptr_t)addr_to_phys(instance->frame_list);
    86 
    8789        pio_write_32(&instance->registers->flbaseadd, (uint32_t)pa);
     90
     91        list_initialize(&instance->tracker_list);
     92        fibril_mutex_initialize(&instance->tracker_list_mutex);
    8893
    8994        instance->cleaner = fibril_create(uhci_clean_finished, instance);
     
    9398        fibril_add_ready(instance->debug_checker);
    9499
    95         /* Start the hc with large(64b) packet FSBR */
     100        /* Start the hc with large(64B) packet FSBR */
    96101        pio_write_16(&instance->registers->usbcmd,
    97102            UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET);
     
    147152}
    148153/*----------------------------------------------------------------------------*/
    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");
     154int 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);
    165164                return ENOTSUP;
    166165        }
    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");
     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());
    214185
    215186        return EOK;
    216187}
    217 /*---------------------------------------------------------------------------*/
     188/*----------------------------------------------------------------------------*/
    218189int uhci_clean_finished(void* arg)
    219190{
     
    223194
    224195        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) );
     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);
    241222                        }
    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;
     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);
    255237                }
    256238                async_usleep(UHCI_CLEANER_TIMEOUT);
     
    311293        return 0;
    312294}
     295/*----------------------------------------------------------------------------*/
     296bool 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}
    313312/**
    314313 * @}
Note: See TracChangeset for help on using the changeset viewer.