Statistics
| Branch: | Tag: | Revision:

root / host / lib / transport / libusb1_zero_copy.cpp @ 76365acd

History | View | Annotate | Download (22.8 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
 * Print to stdout the values of a libusb_transfer struct
35
 ***********************************************************************/
36
void pp_transfer(libusb_transfer *lut)
37
{
38
    std::cout << "Libusb transfer"       << std::endl;
39
    std::cout << "    flags:         0x" << std::hex << (unsigned int) lut->flags << std::endl;
40
    std::cout << "    endpoint:      0x" << std::hex << (unsigned int) lut->endpoint << std::endl;
41
    std::cout << "    type:          0x" << std::hex << (unsigned int) lut->type << std::endl;
42
    std::cout << "    timeout:       "   << std::dec << lut->timeout << std::endl;
43
    std::cout << "    status:        0x" << std::hex << lut->status << std::endl;
44
    std::cout << "    length:        "   << std::dec << lut->length << std::endl;
45
    std::cout << "    actual_length: "   << std::dec << lut->actual_length << std::endl;
46
}
47

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

    
64
    size_t _transfer_size;
65
    size_t _num_transfers;
66

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

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

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

    
88
    // Debug use
89
    void print_transfer_status(libusb_transfer *lut);
90

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

    
96
    ~usb_endpoint();
97

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

    
103
    //Callback use only
104
    void callback_handle_transfer(libusb_transfer *lut);
105
};
106

    
107

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

    
123

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

    
135
    completed_list_add(lut);    
136
}
137

    
138

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

    
156
        if (_input)
157
            submit(free_list_get());
158
    }
159
}
160

    
161

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

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

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

    
183
    while (!_free_list.empty()) {
184
        libusb_free_transfer(free_list_get());
185
    }
186
}
187

    
188

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

    
200
    unsigned char *buff = new unsigned char[buff_len];
201

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

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

    
215

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

    
230
    pending_list_add(lut);
231
    return true;
232
}
233

    
234

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

    
256

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

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

    
275
    return true;
276
}
277

    
278

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

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

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

    
301
    return true;
302
}
303

    
304

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

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

    
346

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

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

    
363
    return true;
364
}
365

    
366

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

    
380
    tv.tv_sec = 0;
381
    tv.tv_usec = 100000; //100ms
382

    
383
    size_t pending_list_size = _pending_list.size();
384

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

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

    
398

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

    
411
    return free_list_get();
412
}
413

    
414

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

    
427
    return completed_list_get();
428
}
429

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

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

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

    
448

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

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

    
467

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

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

    
486

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

    
505

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

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

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

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

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

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

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

    
581
        _lut->length = num_bytes;
582
        _lut->actual_length = 0;
583

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

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

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

    
605

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

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

    
621
    size_t _recv_buff_size;
622
    size_t _send_buff_size;
623
    size_t _num_frames;
624

    
625
public:
626
    typedef boost::shared_ptr<libusb_zero_copy_impl> sptr;
627

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

    
636
    managed_recv_buffer::sptr get_recv_buff(void);
637
    managed_send_buffer::sptr get_send_buff(void);
638

    
639
    size_t get_num_recv_frames(void) const { return _num_frames; }
640
    size_t get_num_send_frames(void) const { return _num_frames; }
641
};
642

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

    
662
    UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL));
663

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

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

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

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

    
692

    
693
libusb_zero_copy_impl::~libusb_zero_copy_impl()
694
{
695
    delete _rx_ep;
696
    delete _tx_ep; 
697

    
698
    libusb_close(_rx_dev_handle);
699
    libusb_close(_tx_dev_handle);
700

    
701
    libusb_exit(_rx_ctx);
702
    libusb_exit(_tx_ctx);
703
}
704

    
705

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

    
725

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

    
746

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

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

    
764

    
765