Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/transfers.c

    re454d9c r3038d51  
    126126}
    127127
     128static int calculate_trb_count(xhci_transfer_t *transfer)
     129{
     130        const size_t size = transfer->batch.buffer_size;
     131        return (size + PAGE_SIZE - 1 )/ PAGE_SIZE;
     132}
     133
     134static void trb_set_buffer(xhci_transfer_t *transfer, xhci_trb_t *trb,
     135        size_t i, size_t total, size_t *remaining)
     136{
     137        const uintptr_t ptr = dma_buffer_phys(&transfer->hc_buffer,
     138                transfer->hc_buffer.virt + i * PAGE_SIZE);
     139
     140        trb->parameter = host2xhci(64, ptr);
     141        TRB_CTRL_SET_TD_SIZE(*trb, max(31, total - i - 1));
     142        if (*remaining > PAGE_SIZE) {
     143                TRB_CTRL_SET_XFER_LEN(*trb, PAGE_SIZE);
     144                *remaining -= PAGE_SIZE;
     145        }
     146        else {
     147                TRB_CTRL_SET_XFER_LEN(*trb, *remaining);
     148                *remaining = 0;
     149        }
     150}
     151
    128152static int schedule_control(xhci_hc_t* hc, xhci_transfer_t* transfer)
    129153{
     
    133157        usb_device_request_setup_packet_t* setup = &batch->setup.packet;
    134158
    135         xhci_trb_t trbs[3];
    136         int trbs_used = 0;
    137 
    138         xhci_trb_t *trb_setup = trbs + trbs_used++;
     159        size_t buffer_count = 0;
     160        if (setup->length > 0) {
     161                buffer_count = calculate_trb_count(transfer);
     162        }
     163
     164        xhci_trb_t trbs[buffer_count + 2];
     165
     166        xhci_trb_t *trb_setup = trbs;
    139167        xhci_trb_clean(trb_setup);
    140168
     
    155183
    156184        /* Data stage */
    157         xhci_trb_t *trb_data = NULL;
    158185        if (setup->length > 0) {
    159                 trb_data = trbs + trbs_used++;
    160                 xhci_trb_clean(trb_data);
    161 
    162                 trb_data->parameter = host2xhci(64, transfer->hc_buffer.phys);
    163 
    164                 // data size (sent for OUT, or buffer size)
    165                 TRB_CTRL_SET_XFER_LEN(*trb_data, batch->buffer_size);
    166                 // FIXME: TD size 4.11.2.4
    167                 TRB_CTRL_SET_TD_SIZE(*trb_data, 1);
    168 
    169                 // Some more fields here, no idea what they mean
    170                 TRB_CTRL_SET_TRB_TYPE(*trb_data, XHCI_TRB_TYPE_DATA_STAGE);
    171 
    172186                int stage_dir = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type)
    173187                                        ? STAGE_IN : STAGE_OUT;
    174                 TRB_CTRL_SET_DIR(*trb_data, stage_dir);
     188                size_t remaining = transfer->batch.buffer_size;
     189
     190                for (size_t i = 0; i < buffer_count; ++i) {
     191                        xhci_trb_clean(&trbs[i + 1]);
     192                        trb_set_buffer(transfer, &trbs[i + 1], i, buffer_count, &remaining);
     193
     194                        TRB_CTRL_SET_DIR(trbs[i + 1], stage_dir);
     195                        TRB_CTRL_SET_TRB_TYPE(trbs[i + 1], XHCI_TRB_TYPE_DATA_STAGE);
     196
     197                        if (i == buffer_count - 1) break;
     198
     199                        /* Set the chain bit as this is not the last TRB */
     200                        TRB_CTRL_SET_CHAIN(trbs[i], 1);
     201                }
    175202        }
    176203
    177204        /* Status stage */
    178         xhci_trb_t *trb_status = trbs + trbs_used++;
     205        xhci_trb_t *trb_status = trbs + buffer_count + 1;
    179206        xhci_trb_clean(trb_status);
    180207
     
    192219
    193220        return xhci_trb_ring_enqueue_multiple(get_ring(transfer), trbs,
    194             trbs_used, &transfer->interrupt_trb_phys);
     221            buffer_count + 2, &transfer->interrupt_trb_phys);
    195222}
    196223
    197224static int schedule_bulk(xhci_hc_t* hc, xhci_transfer_t *transfer)
    198225{
    199         xhci_trb_t trb;
    200         xhci_trb_clean(&trb);
    201         trb.parameter = host2xhci(64, transfer->hc_buffer.phys);
    202 
    203         // data size (sent for OUT, or buffer size)
    204         TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    205 
    206226        /* The stream-enabled endpoints need to chain ED trb */
    207227        xhci_endpoint_t *ep = xhci_endpoint_get(transfer->batch.ep);
    208228        if (!ep->primary_stream_data_size) {
    209                 // FIXME: TD size 4.11.2.4
    210                 TRB_CTRL_SET_TD_SIZE(trb, 1);
    211 
    212                 // we want an interrupt after this td is done
    213                 TRB_CTRL_SET_IOC(trb, 1);
    214                 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
     229                const size_t buffer_count = calculate_trb_count(transfer);
     230                xhci_trb_t trbs[buffer_count];
     231                size_t remaining = transfer->batch.buffer_size;
     232
     233                for (size_t i = 0; i < buffer_count; ++i) {
     234                        xhci_trb_clean(&trbs[i]);
     235                        trb_set_buffer(transfer, &trbs[i], i, buffer_count, &remaining);
     236                        TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL);
     237
     238                        if (i == buffer_count - 1) break;
     239
     240                        /* Set the chain bit as this is not the last TRB */
     241                        TRB_CTRL_SET_CHAIN(trbs[i], 1);
     242                }
     243                /* Set the interrupt bit for last TRB */
     244                TRB_CTRL_SET_IOC(trbs[buffer_count - 1], 1);
    215245
    216246                xhci_trb_ring_t* ring = get_ring(transfer);
    217                 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     247                return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count,
     248                        &transfer->interrupt_trb_phys);
    218249        }
    219250        else {
    220                 TRB_CTRL_SET_TD_SIZE(trb, 2);
    221                 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
    222                 TRB_CTRL_SET_CHAIN(trb, 1);
    223                 TRB_CTRL_SET_ENT(trb, 1);
    224 
    225251                xhci_trb_ring_t* ring = get_ring(transfer);
    226252                if (!ring) {
     
    228254                }
    229255
    230                 int err = xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
    231 
    232                 if (err) {
    233                         return err;
    234                 }
    235 
    236                 xhci_trb_clean(&trb);
    237                 trb.parameter = host2xhci(64, (uintptr_t) transfer);
    238                 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_EVENT_DATA);
    239                 TRB_CTRL_SET_IOC(trb, 1);
    240 
    241                 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     256                const size_t buffer_count = calculate_trb_count(transfer);
     257                xhci_trb_t trbs[buffer_count + 1];
     258                size_t remaining = transfer->batch.buffer_size;
     259
     260                for (size_t i = 0; i < buffer_count; ++i) {
     261                        xhci_trb_clean(&trbs[i]);
     262                        trb_set_buffer(transfer, &trbs[i], i, buffer_count + 1, &remaining);
     263                        TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL);
     264                        TRB_CTRL_SET_CHAIN(trbs[i], 1);
     265                }
     266                TRB_CTRL_SET_ENT(trbs[buffer_count - 1], 1);
     267
     268                xhci_trb_clean(&trbs[buffer_count]);
     269                trbs[buffer_count].parameter = host2xhci(64, (uintptr_t) transfer);
     270                TRB_CTRL_SET_TRB_TYPE(trbs[buffer_count], XHCI_TRB_TYPE_EVENT_DATA);
     271                TRB_CTRL_SET_IOC(trbs[buffer_count], 1);
     272
     273                return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count + 1,
     274                        &transfer->interrupt_trb_phys);
    242275        }
    243276}
     
    245278static int schedule_interrupt(xhci_hc_t* hc, xhci_transfer_t* transfer)
    246279{
    247         xhci_trb_t trb;
    248         xhci_trb_clean(&trb);
    249         trb.parameter = host2xhci(64, transfer->hc_buffer.phys);
    250 
    251         // data size (sent for OUT, or buffer size)
    252         TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    253         // FIXME: TD size 4.11.2.4
    254         TRB_CTRL_SET_TD_SIZE(trb, 1);
    255 
    256         // we want an interrupt after this td is done
    257         TRB_CTRL_SET_IOC(trb, 1);
    258 
    259         TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
     280        const size_t buffer_count = calculate_trb_count(transfer);
     281        xhci_trb_t trbs[buffer_count];
     282        size_t remaining = transfer->batch.buffer_size;
     283
     284        for (size_t i = 0; i < buffer_count; ++i) {
     285                xhci_trb_clean(&trbs[i]);
     286                trb_set_buffer(transfer, &trbs[i], i, buffer_count, &remaining);
     287                TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL);
     288
     289                if (i == buffer_count - 1) break;
     290
     291                /* Set the chain bit as this is not the last TRB */
     292                TRB_CTRL_SET_CHAIN(trbs[i], 1);
     293        }
     294        /* Set the interrupt bit for last TRB */
     295        TRB_CTRL_SET_IOC(trbs[buffer_count - 1], 1);
    260296
    261297        xhci_trb_ring_t* ring = get_ring(transfer);
    262 
    263         return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     298        return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count,
     299                &transfer->interrupt_trb_phys);
    264300}
    265301
Note: See TracChangeset for help on using the changeset viewer.