Statistics
| Branch: | Tag: | Revision:

root / host / lib / transport / libusb1_zero_copy.cpp @ ad55e25a

History | View | Annotate | Download (22.9 kB)

1
//
2
// Copyright 2010 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

    
18
#include "libusb1_base.hpp"
19
#include <uhd/transport/usb_zero_copy.hpp>
20
#include <uhd/utils/assert.hpp>
21
#include <boost/asio.hpp>
22
#include <boost/format.hpp>
23
#include <iostream>
24
#include <iomanip>
25

    
26
using namespace uhd::transport;
27

    
28
const int libusb_debug_level = 0;
29
const int libusb_timeout = 0;
30

    
31
/***********************************************************************
32
 * Helper functions
33
 ***********************************************************************/
34
/*
35
 * Print the values of a libusb_transfer struct
36
 * http://libusb.sourceforge.net/api-1.0/structlibusb__transfer.html
37
 */
38
void pp_transfer(libusb_transfer *lut)
39
{
40
    std::cout << "Libusb transfer"       << std::endl;
41
    std::cout << "    flags:         0x" << std::hex << (unsigned int) lut->flags << std::endl;
42
    std::cout << "    endpoint:      0x" << std::hex << (unsigned int) lut->endpoint << std::endl;
43
    std::cout << "    type:          0x" << std::hex << (unsigned int) lut->type << std::endl;
44
    std::cout << "    timeout:       "   << std::dec << lut->timeout << std::endl;
45
    std::cout << "    status:        0x" << std::hex << lut->status << std::endl;
46
    std::cout << "    length:        "   << std::dec << lut->length << std::endl;
47
    std::cout << "    actual_length: "   << std::dec << lut->actual_length << std::endl;
48
}
49

    
50
/***********************************************************************
51
 * USB asynchronous zero_copy endpoint
52
 *   This endpoint implementation provides asynchronous I/O to libusb-1.0
53
 *   devices. Each endpoint is directional and two can be combined to
54
 *   create a bidirectional interface. It is a zero copy implementation
55
 *   with respect to libusb, however, each send and recv requires a copy
56
 *   operation from kernel to userspace; this is due to the usbfs
57
 *   interface provided by the kernel. 
58
 **********************************************************************/
59
class usb_endpoint {
60
private:
61
    libusb_device_handle *_dev_handle;
62
    libusb_context *_ctx;
63
    int  _endpoint;
64
    bool _input;
65

    
66
    size_t _transfer_size;
67
    size_t _num_transfers;
68

    
69
    // Transfer state lists (transfers are free, pending, or completed)
70
    std::list<libusb_transfer *>  _free_list;
71
    std::list<libusb_transfer *>  _pending_list;
72
    std::list<libusb_transfer *>  _completed_list;
73

    
74
    // Calls for processing asynchronous I/O 
75
    libusb_transfer *allocate_transfer(int buff_len);
76
    bool cancel(libusb_transfer *lut);
77
    bool cancel_all();
78
    bool reap_pending_list();
79
    bool reap_pending_list_timeout();
80
    bool reap_completed_list();
81

    
82
    // Transfer state manipulators 
83
    void free_list_add(libusb_transfer *lut);
84
    void pending_list_add(libusb_transfer *lut);
85
    void completed_list_add(libusb_transfer *lut);
86
    libusb_transfer *free_list_get();
87
    libusb_transfer *completed_list_get();
88
    bool pending_list_remove(libusb_transfer *lut);
89

    
90
    // Debug use
91
    void print_transfer_status(libusb_transfer *lut);
92

    
93
public:
94
    usb_endpoint(libusb_device_handle *dev_handle,
95
                 libusb_context *ctx, int endpoint, bool input,
96
                 size_t transfer_size, size_t num_transfers);
97

    
98
    ~usb_endpoint();
99

    
100
    // Exposed interface for submitting / retrieving transfer buffers
101
    bool submit(libusb_transfer *lut);
102
    libusb_transfer *get_completed_transfer();
103
    libusb_transfer *get_free_transfer();
104

    
105
    //Callback use only
106
    void callback_handle_transfer(libusb_transfer *lut);
107
};
108

    
109

    
110
/*
111
 * Callback function called when submitted transfers complete.
112
 * The endpoint upon which the transfer is part of is recovered
113
 * and the transfer moved from pending to completed state.
114
 * Callbacks occur during the reaping calls where libusb_handle_events()
115
 * is used. The callback only modifies the transfer state by moving
116
 * it from the pending to completed status list.
117
 * \param lut pointer to libusb_transfer
118
 */
119
static void callback(libusb_transfer *lut)
120
{
121
    usb_endpoint *endpoint = (usb_endpoint *) lut->user_data; 
122
    endpoint->callback_handle_transfer(lut);
123
}
124

    
125

    
126
/*
127
 * Accessor call to allow list access from callback space
128
 * \param pointer to libusb_transfer
129
 */
130
void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)
131
{
132
    if (!pending_list_remove(lut)) {
133
        std::cerr << "USB: pending remove failed" << std::endl;
134
        return;
135
    }
136

    
137
    completed_list_add(lut);    
138
}
139

    
140

    
141
/*
142
 * Constructor
143
 * Allocate libusb transfers and mark as free.  For IN endpoints,
144
 * submit the transfers so that they're ready to return when
145
 * data is available. 
146
 */
147
usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,
148
                          libusb_context *ctx, int endpoint, bool input,
149
                          size_t transfer_size, size_t num_transfers)
150
    : _dev_handle(dev_handle),
151
      _ctx(ctx), _endpoint(endpoint), _input(input),
152
      _transfer_size(transfer_size), _num_transfers(num_transfers)
153
{
154
    unsigned int i;
155
    for (i = 0; i < _num_transfers; i++) {
156
        free_list_add(allocate_transfer(_transfer_size));
157

    
158
        if (_input)
159
            submit(free_list_get());
160
    }
161
}
162

    
163

    
164
/*
165
 * Destructor
166
 * Make sure all the memory is freed. Cancel any pending transfers.
167
 * When all completed transfers are moved to the free list, release
168
 * the transfers. Libusb will deallocate the data buffer held by
169
 * each transfer.
170
 */
171
usb_endpoint::~usb_endpoint()
172
{
173
    cancel_all();
174

    
175
    while (!_pending_list.empty()) {
176
        if (!reap_pending_list())
177
            std::cerr << "error: destructor failed to reap" << std::endl;
178
    }
179

    
180
    while (!_completed_list.empty()) {
181
        if (!reap_completed_list())
182
            std::cerr << "error: destructor failed to reap" << std::endl;
183
    }
184

    
185
    while (!_free_list.empty()) {
186
        libusb_free_transfer(free_list_get());
187
    }
188
}
189

    
190

    
191
/*
192
 * Allocate a libusb transfer 
193
 * The allocated transfer - and buffer it contains - is repeatedly
194
 * submitted, reaped, and reused and should not be freed until shutdown.
195
 * \param buff_len size of the individual buffer held by each transfer
196
 * \return pointer to an allocated libusb_transfer
197
 */
198
libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)
199
{
200
    libusb_transfer *lut = libusb_alloc_transfer(0);
201

    
202
    unsigned char *buff = new unsigned char[buff_len];
203

    
204
    unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0));
205

    
206
    libusb_fill_bulk_transfer(lut,                // transfer
207
                              _dev_handle,        // dev_handle
208
                              endpoint,           // endpoint
209
                              buff,               // buffer
210
                              buff_len,           // length
211
                              callback,           // callback
212
                              this,               // user_data
213
                              0);                 // timeout
214
    return lut;
215
}
216

    
217

    
218
/*
219
 * Asynchonous transfer submission
220
 * Submit a libusb transfer to libusb add pending status
221
 * \param lut pointer to libusb_transfer
222
 * \return true on success or false on error 
223
 */
224
bool usb_endpoint::submit(libusb_transfer *lut)
225
{
226
    int retval;
227
    if ((retval = libusb_submit_transfer(lut)) < 0) {
228
        std::cerr << "error: libusb_submit_transfer: " << retval << std::endl;
229
        return false;
230
    }
231

    
232
    pending_list_add(lut);
233
    return true;
234
}
235

    
236

    
237
/*
238
 * Cancel a pending transfer 
239
 * Search the pending list for the transfer and cancel if found.
240
 * \param lut pointer to libusb_transfer to cancel
241
 * \return true on success or false if transfer is not found
242
 *
243
 * Note: success only indicates submission of cancelation request.
244
 * Sucessful cancelation is not known until the callback occurs.
245
 */
246
bool usb_endpoint::cancel(libusb_transfer *lut)
247
{
248
    std::list<libusb_transfer*>::iterator iter;
249
    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
250
        if (*iter == lut) { 
251
            libusb_cancel_transfer(lut); 
252
            return true;
253
        }
254
    }
255
    return false;
256
}
257

    
258

    
259
/*
260
 * Cancel all pending transfers 
261
 * \return bool true if cancelation request is submitted
262
 *
263
 * Note: success only indicates submission of cancelation request.
264
 * Sucessful cancelation is not known until the callback occurs.
265
 */
266
bool usb_endpoint::cancel_all()
267
{
268
    std::list<libusb_transfer*>::iterator iter;
269

    
270
    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
271
        if (libusb_cancel_transfer(*iter) < 0) {
272
            std::cerr << "error: libusb_cancal_transfer() failed" << std::endl;
273
            return false;
274
        }
275
    }
276

    
277
    return true;
278
}
279

    
280

    
281
/*
282
 * Reap completed transfers
283
 * return true if at least one transfer was reaped, false otherwise. 
284
 * Check completed transfers for errors and mark as free. This is a
285
 * blocking call. 
286
 * \return bool true if a libusb transfer is reaped, false otherwise
287
 */
288
bool usb_endpoint::reap_completed_list()
289
{
290
    libusb_transfer *lut;
291

    
292
    if (_completed_list.empty()) {
293
        if (!reap_pending_list_timeout())
294
            return false;
295
    }
296

    
297
    while (!_completed_list.empty()) {
298
        lut = completed_list_get();
299
        print_transfer_status(lut);
300
        free_list_add(lut);
301
    }
302

    
303
    return true;
304
}
305

    
306

    
307
/*
308
 * Print status errors of a completed transfer
309
 * \param lut pointer to an libusb_transfer
310
 */
311
void usb_endpoint::print_transfer_status(libusb_transfer *lut)
312
{
313
    switch (lut->status) {
314
    case LIBUSB_TRANSFER_COMPLETED:
315
        if (lut->actual_length < lut->length) {
316
            std::cerr << "USB: transfer completed with short write,"
317
                      << " length = " << lut->length
318
                      << " actual = " << lut->actual_length << std::endl;
319
        }
320

    
321
        if ((lut->actual_length < 0) || (lut->length < 0)) {
322
            std::cerr << "USB: transfer completed with invalid response"
323
                      << std::endl;
324
        }
325
        break;
326
    case LIBUSB_TRANSFER_CANCELLED:
327
        break;
328
    case LIBUSB_TRANSFER_NO_DEVICE:
329
        std::cerr << "USB: device was disconnected" << std::endl;
330
        break;
331
    case LIBUSB_TRANSFER_OVERFLOW:
332
        std::cerr << "USB: device sent more data than requested" << std::endl;
333
        break;
334
    case LIBUSB_TRANSFER_TIMED_OUT:
335
        std::cerr << "USB: transfer timed out" << std::endl;
336
        break;
337
    case LIBUSB_TRANSFER_STALL:
338
        std::cerr << "USB: halt condition detected (stalled)" << std::endl;
339
        break;
340
    case LIBUSB_TRANSFER_ERROR:
341
        std::cerr << "USB: transfer failed" << std::endl;
342
        break;
343
    default:
344
        std::cerr << "USB: received unknown transfer status" << std::endl;
345
    }
346
}
347

    
348

    
349
/*
350
 * Reap pending transfers without timeout 
351
 * This is a blocking call. Reaping submitted transfers is
352
 * handled by libusb and the assigned callback function.
353
 * Block until at least one transfer is reaped.
354
 * \return true true if a transfer was reaped or false otherwise
355
 */
356
bool usb_endpoint::reap_pending_list()
357
{
358
    int retval;
359

    
360
    if ((retval = libusb_handle_events(_ctx)) < 0) {
361
        std::cerr << "error: libusb_handle_events: " << retval << std::endl;
362
        return false;
363
    }
364

    
365
    return true;
366
}
367

    
368

    
369
/*
370
 * Reap pending transfers with timeout 
371
 * This call blocks until a transfer is reaped or timeout.
372
 * Reaping submitted transfers is handled by libusb and the
373
 * assigned callback function. Block until at least one
374
 * transfer is reaped or timeout occurs.
375
 * \return true if a transfer was reaped or false otherwise
376
 */
377
bool usb_endpoint::reap_pending_list_timeout()
378
{
379
    int retval;
380
    timeval tv;
381

    
382
    tv.tv_sec = 0;
383
    tv.tv_usec = 100000; //100ms
384

    
385
    size_t pending_list_size = _pending_list.size();
386

    
387
    if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) {
388
        std::cerr << "error: libusb_handle_events: " << retval << std::endl;
389
        return false;
390
    }
391

    
392
    if (_pending_list.size() < pending_list_size) {
393
        return true;
394
    }
395
    else {
396
        return false;
397
    }
398
}
399

    
400

    
401
/*
402
 * Get a free transfer
403
 * The transfer has an empty data bufer for OUT requests 
404
 * \return pointer to a libusb_transfer
405
 */
406
libusb_transfer *usb_endpoint::get_free_transfer()
407
{
408
    if (_free_list.empty()) {
409
        if (!reap_completed_list())
410
            return NULL; 
411
    }
412

    
413
    return free_list_get();
414
}
415

    
416

    
417
/*
418
 * Get a completed transfer 
419
 * The transfer has a full data buffer for IN requests
420
 * \return pointer to libusb_transfer
421
 */
422
libusb_transfer *usb_endpoint::get_completed_transfer()
423
{
424
    if (_completed_list.empty()) {
425
        if (!reap_pending_list_timeout())
426
            return NULL; 
427
    }
428

    
429
    return completed_list_get();
430
}
431

    
432
/*
433
 * List operations 
434
 */
435
void usb_endpoint::free_list_add(libusb_transfer *lut)
436
{
437
    _free_list.push_back(lut);
438
}
439

    
440
void usb_endpoint::pending_list_add(libusb_transfer *lut)
441
{
442
    _pending_list.push_back(lut);
443
}
444

    
445
void usb_endpoint::completed_list_add(libusb_transfer *lut)
446
{
447
    _completed_list.push_back(lut);
448
}
449

    
450

    
451
/*
452
 * Free and completed lists don't have ordered content 
453
 * Pop transfers from the front as needed
454
 */
455
libusb_transfer *usb_endpoint::free_list_get()
456
{
457
    libusb_transfer *lut;
458

    
459
    if (_free_list.size() == 0) {
460
        return NULL; 
461
    }
462
    else { 
463
        lut = _free_list.front();
464
        _free_list.pop_front();
465
        return lut;
466
    }
467
}
468

    
469

    
470
/*
471
 * Free and completed lists don't have ordered content 
472
 * Pop transfers from the front as needed
473
 */
474
libusb_transfer *usb_endpoint::completed_list_get()
475
{
476
    libusb_transfer *lut;
477

    
478
    if (_completed_list.empty()) {
479
        return NULL;
480
    }
481
    else { 
482
        lut = _completed_list.front();
483
        _completed_list.pop_front();
484
        return lut;
485
    }
486
}
487

    
488

    
489
/*
490
 * Search and remove transfer from pending list
491
 * Assuming that the callbacks occur in order, the front element
492
 * should yield the correct transfer. If not, then something else
493
 * is going on. If no transfers match, then something went wrong.
494
 */
495
bool usb_endpoint::pending_list_remove(libusb_transfer *lut)
496
{
497
    std::list<libusb_transfer*>::iterator iter;
498
    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
499
        if (*iter == lut) { 
500
            _pending_list.erase(iter);
501
            return true;
502
        }
503
    }
504
    return false;
505
}
506

    
507

    
508
/***********************************************************************
509
 * Managed buffers 
510
 **********************************************************************/
511
/*
512
 * Libusb managed receive buffer
513
 * Construct a recv buffer from a libusb transfer. The memory held by
514
 * the libusb transfer is exposed through the managed buffer interface.
515
 * Upon destruction, the transfer and buffer are resubmitted to the
516
 * endpoint for further use. 
517
 */
518
class libusb_managed_recv_buffer_impl : public managed_recv_buffer {
519
public:
520
    libusb_managed_recv_buffer_impl(libusb_transfer *lut,
521
                                    usb_endpoint *endpoint)
522
        : _buff(lut->buffer, lut->length)
523
    {
524
        _lut = lut;
525
        _endpoint = endpoint;
526
    }
527

    
528
    ~libusb_managed_recv_buffer_impl()
529
    {
530
       if (!_endpoint->submit(_lut))
531
           std::cerr << "USB: failed to submit IN transfer" << std::endl;
532
    }
533

    
534
private:
535
    const boost::asio::const_buffer &get() const
536
    {
537
        return _buff; 
538
    }
539

    
540
    libusb_transfer *_lut;
541
    usb_endpoint *_endpoint;
542
    const boost::asio::const_buffer _buff;
543
};
544

    
545
/*
546
 * Libusb managed send buffer
547
 * Construct a send buffer from a libusb transfer. The memory held by
548
 * the libusb transfer is exposed through the managed buffer interface.
549
 * Committing the buffer will set the data length and submit the buffer
550
 * to the endpoint. Submitting a buffer multiple times or destroying
551
 * the buffer before committing is an error. For the latter, the transfer
552
 * is returned to the endpoint with no data for reuse.
553
 */
554
class libusb_managed_send_buffer_impl : public managed_send_buffer {
555
public:
556
    libusb_managed_send_buffer_impl(libusb_transfer *lut,
557
                                    usb_endpoint *endpoint,
558
                                    size_t buff_size)
559
        : _buff(lut->buffer, buff_size), _committed(false)
560
    {
561
        _lut = lut;
562
        _endpoint = endpoint;
563
    }
564

    
565
    ~libusb_managed_send_buffer_impl()
566
    {
567
        if (!_committed) {
568
            _lut->length = 0;
569
            _lut->actual_length = 0;
570
            _endpoint->submit(_lut);
571
        }
572
    }
573

    
574
    ssize_t commit(size_t num_bytes)
575
    {
576
        if (_committed) {
577
            std::cerr << "UHD: send buffer already committed" << std::endl;
578
            return 0;
579
        }
580
        
581
        UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff));
582

    
583
        _lut->length = num_bytes;
584
        _lut->actual_length = 0;
585

    
586
        if (_endpoint->submit(_lut)) {
587
            _committed = true;
588
            return num_bytes;
589
        }
590
        else {
591
            return 0;
592
        }
593
    }
594

    
595
private:
596
    const boost::asio::mutable_buffer &get() const
597
    {
598
        return _buff; 
599
    }
600

    
601
    libusb_transfer *_lut;
602
    usb_endpoint *_endpoint;
603
    const boost::asio::mutable_buffer _buff;
604
    bool _committed;
605
};
606

    
607

    
608
/***********************************************************************
609
 * USB zero_copy device class
610
 **********************************************************************/
611
class libusb_zero_copy_impl : public usb_zero_copy
612
{
613
private:
614
    usb_endpoint          *_rx_ep;
615
    usb_endpoint          *_tx_ep;
616

    
617
    // Maintain libusb values
618
    libusb_context       *_rx_ctx;
619
    libusb_context       *_tx_ctx;
620
    libusb_device_handle *_rx_dev_handle;
621
    libusb_device_handle *_tx_dev_handle;
622

    
623
    size_t _recv_buff_size;
624
    size_t _send_buff_size;
625
    size_t _num_frames;
626

    
627
public:
628
    typedef boost::shared_ptr<libusb_zero_copy_impl> sptr;
629

    
630
    libusb_zero_copy_impl(usb_device_handle::sptr handle,
631
                          unsigned int rx_endpoint,
632
                          unsigned int tx_endpoint,
633
                          size_t recv_buff_size,
634
                          size_t send_buff_size);
635
    
636
    ~libusb_zero_copy_impl();
637

    
638
    managed_recv_buffer::sptr get_recv_buff(void);
639
    managed_send_buffer::sptr get_send_buff(void);
640

    
641
    size_t get_num_recv_frames(void) const { return _num_frames; }
642
    size_t get_num_send_frames(void) const { return _num_frames; }
643
};
644

    
645
/*
646
 * Constructor
647
 * Initializes libusb, opens devices, and sets up interfaces for I/O.
648
 * Finally, creates endpoints for asynchronous I/O. 
649
 */
650
libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle,
651
                                             unsigned int rx_endpoint,
652
                                             unsigned int tx_endpoint,
653
                                             size_t buff_size,
654
                                             size_t block_size)
655
 : _rx_ctx(NULL), _tx_ctx(NULL), _rx_dev_handle(NULL), _tx_dev_handle(NULL),
656
   _recv_buff_size(block_size), _send_buff_size(block_size),
657
   _num_frames(buff_size / block_size)
658
{
659
    // Initialize libusb with separate contexts to allow
660
    // thread safe operation of transmit and receive 
661
    libusb::init(&_rx_ctx, libusb_debug_level);
662
    libusb::init(&_tx_ctx, libusb_debug_level);
663

    
664
    UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL));
665

    
666
    // Find and open the libusb_device corresponding to the
667
    // given handle and return the libusb_device_handle
668
    // that can be used for I/O purposes.
669
    _rx_dev_handle = libusb::open_device(_rx_ctx, handle);
670
    _tx_dev_handle = libusb::open_device(_tx_ctx, handle);
671

    
672
    // Open USB interfaces for tx/rx using magic values.
673
    // IN interface:      2
674
    // OUT interface:     1
675
    // Control interface: 0
676
    libusb::open_interface(_rx_dev_handle, 2);
677
    libusb::open_interface(_tx_dev_handle, 1);
678

    
679
    _rx_ep = new usb_endpoint(_rx_dev_handle,  // libusb device_handle
680
                              _rx_ctx,         // libusb context
681
                              rx_endpoint,     // USB endpoint number
682
                              true,            // IN endpoint
683
                              _recv_buff_size, // buffer size per transfer 
684
                              _num_frames);    // number of libusb transfers
685

    
686
    _tx_ep = new usb_endpoint(_tx_dev_handle,  // libusb device_handle
687
                              _tx_ctx,         // libusb context
688
                              tx_endpoint,     // USB endpoint number
689
                              false,           // OUT endpoint
690
                              _send_buff_size, // buffer size per transfer
691
                              _num_frames);    // number of libusb transfers
692
}
693

    
694

    
695
libusb_zero_copy_impl::~libusb_zero_copy_impl()
696
{
697
    delete _rx_ep;
698
    delete _tx_ep; 
699

    
700
    libusb_close(_rx_dev_handle);
701
    libusb_close(_tx_dev_handle);
702

    
703
    libusb_exit(_rx_ctx);
704
    libusb_exit(_tx_ctx);
705
}
706

    
707

    
708
/*
709
 * Construct a managed receive buffer from a completed libusb transfer
710
 * (happy with buffer full of data) obtained from the receive endpoint.
711
 * Return empty pointer if no transfer is available (timeout or error).
712
 * \return pointer to a managed receive buffer 
713
 */
714
managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()
715
{
716
    libusb_transfer *lut = _rx_ep->get_completed_transfer();
717
    if (lut == NULL) {
718
        return managed_recv_buffer::sptr();
719
    }
720
    else {
721
        return managed_recv_buffer::sptr(
722
            new libusb_managed_recv_buffer_impl(lut,
723
                                                _rx_ep));
724
    }
725
}
726

    
727

    
728
/*
729
 * Construct a managed send buffer from a free libusb transfer (with
730
 * empty buffer). Return empty pointer of no transfer is available
731
 * (timeout or error).
732
 * \return pointer to a managed send buffer 
733
 */
734
managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff()
735
{
736
    libusb_transfer *lut = _tx_ep->get_free_transfer();
737
    if (lut == NULL) {
738
        return managed_send_buffer::sptr();
739
    }
740
    else {
741
        return managed_send_buffer::sptr(
742
            new libusb_managed_send_buffer_impl(lut,
743
                                                _tx_ep,
744
                                                _send_buff_size));
745
    }
746
}
747

    
748

    
749
/***********************************************************************
750
 * USB zero_copy make functions
751
 **********************************************************************/
752
usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle,
753
                                        unsigned int rx_endpoint,
754
                                        unsigned int tx_endpoint,
755
                                        size_t buff_size,
756
                                        size_t block_size)
757

    
758
{
759
    return sptr(new libusb_zero_copy_impl(handle,
760
                                          rx_endpoint,
761
                                          tx_endpoint,
762
                                          buff_size, 
763
                                          block_size));
764
}
765

    
766

    
767