Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ohci/ohci_batch.c

    r790318e r549ff23  
    5252        if (!ohci_batch)
    5353                return;
    54         unsigned i = 0;
    5554        if (ohci_batch->tds) {
    56                 for (; i< ohci_batch->td_count; ++i) {
     55                for (unsigned i = 0; i < ohci_batch->td_count; ++i) {
    5756                        if (i != ohci_batch->leave_td)
    5857                                free32(ohci_batch->tds[i]);
     
    6059                free(ohci_batch->tds);
    6160        }
    62         usb_transfer_batch_dispose(ohci_batch->usb_batch);
     61        usb_transfer_batch_destroy(ohci_batch->usb_batch);
    6362        free32(ohci_batch->device_buffer);
    6463        free(ohci_batch);
     
    107106        ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td;
    108107        ohci_batch->leave_td = 0;
    109         unsigned i = 1;
    110         for (; i <= ohci_batch->td_count; ++i) {
     108
     109        for (unsigned i = 1; i <= ohci_batch->td_count; ++i) {
    111110                ohci_batch->tds[i] = malloc32(sizeof(td_t));
    112111                CHECK_NULL_DISPOSE_RET(ohci_batch->tds[i],
     
    160159        usb_log_debug("Batch %p checking %zu td(s) for completion.\n",
    161160            ohci_batch->usb_batch, ohci_batch->td_count);
    162         usb_log_debug2("ED: %x:%x:%x:%x.\n",
     161        usb_log_debug2("ED: %08x:%08x:%08x:%08x.\n",
    163162            ohci_batch->ed->status, ohci_batch->ed->td_head,
    164163            ohci_batch->ed->td_tail, ohci_batch->ed->next);
    165164
    166         size_t i = 0;
    167         for (; i < ohci_batch->td_count; ++i) {
     165        if (!ed_inactive(ohci_batch->ed) && ed_transfer_pending(ohci_batch->ed))
     166                return false;
     167
     168        /* Now we may be sure that either the ED is inactive because of errors
     169         * or all transfer descriptors completed successfully */
     170
     171        /* Assume all data got through */
     172        ohci_batch->usb_batch->transfered_size =
     173            ohci_batch->usb_batch->buffer_size;
     174
     175        /* Assume we will leave the last(unused) TD behind */
     176        ohci_batch->leave_td = ohci_batch->td_count;
     177
     178        /* Check all TDs */
     179        for (size_t i = 0; i < ohci_batch->td_count; ++i) {
    168180                assert(ohci_batch->tds[i] != NULL);
    169                 usb_log_debug("TD %zu: %x:%x:%x:%x.\n", i,
     181                usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.\n", i,
    170182                    ohci_batch->tds[i]->status, ohci_batch->tds[i]->cbp,
    171183                    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
    172                 if (!td_is_finished(ohci_batch->tds[i])) {
    173                         return false;
    174                 }
     184
     185                /* If the TD got all its data through, it will report 0 bytes
     186                 * remain, the sole exception is INPUT with data rounding flag
     187                 * (short), i.e. every INPUT. Nice thing is that short packets
     188                 * will correctly report remaining data, thus making
     189                 * this computation correct (short packets need to be produced
     190                 * by the last TD)
     191                 * NOTE: This also works for CONTROL transfer as
     192                 * the first TD will return 0 remain.
     193                 * NOTE: Short packets don't break the assumption that
     194                 * we leave the very last(unused) TD behind.
     195                 */
     196                ohci_batch->usb_batch->transfered_size
     197                    -= td_remain_size(ohci_batch->tds[i]);
     198
    175199                ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
    176200                if (ohci_batch->usb_batch->error != EOK) {
    177                         usb_log_debug("Batch %p found error TD(%zu):%x.\n",
     201                        usb_log_debug("Batch %p found error TD(%zu):%08x.\n",
    178202                            ohci_batch->usb_batch, i,
    179203                            ohci_batch->tds[i]->status);
    180                         /* Make sure TD queue is empty (one TD),
    181                          * ED should be marked as halted */
    182                         ohci_batch->ed->td_tail =
    183                             (ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK);
    184                         ++i;
     204
     205                        /* ED should be stopped because of errors */
     206                        assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0);
     207
     208                        /* Now we have a problem: we don't know what TD
     209                         * the head pointer points to, the retiring rules
     210                         * described in specs say it should be the one after
     211                         * the failed one so set the tail pointer accordingly.
     212                         * It will be the one TD we leave behind.
     213                         */
     214                        ohci_batch->leave_td = i + 1;
     215
     216                        /* Check TD assumption */
     217                        const uint32_t pa = addr_to_phys(
     218                            ohci_batch->tds[ohci_batch->leave_td]);
     219                        assert((ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK)
     220                            == pa);
     221
     222                        ed_set_tail_td(ohci_batch->ed,
     223                            ohci_batch->tds[ohci_batch->leave_td]);
     224
     225                        /* Clear possible ED HALT */
     226                        ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
    185227                        break;
    186228                }
    187229        }
    188 
    189         assert(i <= ohci_batch->td_count);
    190         ohci_batch->leave_td = i;
    191 
     230        assert(ohci_batch->usb_batch->transfered_size <=
     231            ohci_batch->usb_batch->buffer_size);
     232
     233        /* Store the remaining TD */
    192234        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
    193235        assert(ohci_ep);
    194236        ohci_ep->td = ohci_batch->tds[ohci_batch->leave_td];
    195         assert(i > 0);
    196         ohci_batch->usb_batch->transfered_size =
    197             ohci_batch->usb_batch->buffer_size;
    198         for (--i;i < ohci_batch->td_count; ++i)
    199                 ohci_batch->usb_batch->transfered_size
    200                     -= td_remain_size(ohci_batch->tds[i]);
    201 
    202         /* Clear possible ED HALT */
    203         ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
    204         /* just make sure that we are leaving the right TD behind */
     237
     238        /* Make sure that we are leaving the right TD behind */
    205239        const uint32_t pa = addr_to_phys(ohci_ep->td);
    206240        assert(pa == (ohci_batch->ed->td_head & ED_TDHEAD_PTR_MASK));
     
    217251{
    218252        assert(ohci_batch);
    219         ed_set_end_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
     253        ed_set_tail_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
    220254}
    221255/*----------------------------------------------------------------------------*/
     
    234268        assert(ohci_batch->usb_batch);
    235269        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    236         usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", ohci_batch->ed,
     270        usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
    237271            ohci_batch->ed->status, ohci_batch->ed->td_tail,
    238272            ohci_batch->ed->td_head, ohci_batch->ed->next);
     
    247281        const usb_direction_t status_dir = reverse_dir[dir];
    248282
    249         /* setup stage */
    250         td_init(ohci_batch->tds[0], USB_DIRECTION_BOTH, buffer,
    251                 ohci_batch->usb_batch->setup_size, toggle);
    252         td_set_next(ohci_batch->tds[0], ohci_batch->tds[1]);
    253         usb_log_debug("Created CONTROL SETUP TD: %x:%x:%x:%x.\n",
     283        /* Setup stage */
     284        td_init(
     285            ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
     286            buffer, ohci_batch->usb_batch->setup_size, toggle);
     287        usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
    254288            ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
    255289            ohci_batch->tds[0]->next, ohci_batch->tds[0]->be);
    256290        buffer += ohci_batch->usb_batch->setup_size;
    257291
    258         /* data stage */
     292        /* Data stage */
    259293        size_t td_current = 1;
    260294        size_t remain_size = ohci_batch->usb_batch->buffer_size;
     
    265299                toggle = 1 - toggle;
    266300
    267                 td_init(ohci_batch->tds[td_current], data_dir, buffer,
    268                     transfer_size, toggle);
    269                 td_set_next(ohci_batch->tds[td_current],
    270                     ohci_batch->tds[td_current + 1]);
    271                 usb_log_debug("Created CONTROL DATA TD: %x:%x:%x:%x.\n",
     301                td_init(ohci_batch->tds[td_current],
     302                    ohci_batch->tds[td_current + 1],
     303                    data_dir, buffer, transfer_size, toggle);
     304                usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.\n",
    272305                    ohci_batch->tds[td_current]->status,
    273306                    ohci_batch->tds[td_current]->cbp,
     
    281314        }
    282315
    283         /* status stage */
     316        /* Status stage */
    284317        assert(td_current == ohci_batch->td_count - 1);
    285         td_init(ohci_batch->tds[td_current], status_dir, NULL, 0, 1);
    286         td_set_next(ohci_batch->tds[td_current],
    287             ohci_batch->tds[td_current + 1]);
    288         usb_log_debug("Created CONTROL STATUS TD: %x:%x:%x:%x.\n",
     318        td_init(ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
     319            status_dir, NULL, 0, 1);
     320        usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.\n",
    289321            ohci_batch->tds[td_current]->status,
    290322            ohci_batch->tds[td_current]->cbp,
     
    312344        assert(ohci_batch->usb_batch);
    313345        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    314         usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", ohci_batch->ed,
     346        usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
    315347            ohci_batch->ed->status, ohci_batch->ed->td_tail,
    316348            ohci_batch->ed->td_head, ohci_batch->ed->next);
     
    323355                    ? OHCI_TD_MAX_TRANSFER : remain_size;
    324356
    325                 td_init(ohci_batch->tds[td_current], dir, buffer,
    326                     transfer_size, -1);
    327                 td_set_next(ohci_batch->tds[td_current],
    328                     ohci_batch->tds[td_current + 1]);
    329 
    330                 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
     357                td_init(
     358                    ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
     359                    dir, buffer, transfer_size, -1);
     360
     361                usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.\n",
    331362                    ohci_batch->tds[td_current]->status,
    332363                    ohci_batch->tds[td_current]->cbp,
Note: See TracChangeset for help on using the changeset viewer.