Statistics
| Branch: | Tag: | Revision:

root / host / lib / transport / libusb1_zero_copy.cpp @ 55da3154

History | View | Annotate | Download (23.1 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
    // Accessors 
99
    int get_endpoint() const { return _endpoint; }
100
    bool get_direction() const { return _input; }
101
    libusb_device_handle *get_dev_handle() const { return _dev_handle; }
102
    libusb_context *get_ctx() const { return _ctx; }
103

    
104
    // Exposed interface for submitting / retrieving transfer buffers
105
    bool submit(libusb_transfer *lut);
106
    libusb_transfer *get_completed_transfer();
107
    libusb_transfer *get_free_transfer();
108

    
109
    //Callback use only
110
    void callback_handle_transfer(libusb_transfer *lut);
111
};
112

    
113

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

    
129

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

    
141
    completed_list_add(lut);    
142
}
143

    
144

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

    
162
        if (_input)
163
            submit(free_list_get());
164
    }
165
}
166

    
167

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

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

    
184
    while (!_completed_list.empty()) {
185
        if (!reap_completed_list())
186
            std::cerr << "error: destructor failed to reap" << std::endl;
187
    }
188

    
189
    while (!_free_list.empty()) {
190
        libusb_free_transfer(free_list_get());
191
    }
192
}
193

    
194

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

    
206
    unsigned char *buff = new unsigned char[buff_len];
207

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

    
210
    libusb_fill_bulk_transfer(lut,                // transfer
211
                              _dev_handle,        // dev_handle
212
                              endpoint,           // endpoint
213
                              buff,               // buffer
214
                              buff_len,           // length
215
                              callback,           // callback
216
                              this,               // user_data
217
                              0);                 // timeout
218
    return lut;
219
}
220

    
221

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

    
236
    pending_list_add(lut);
237
    return true;
238
}
239

    
240

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

    
262

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

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

    
281
    return true;
282
}
283

    
284

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

    
296
    if (_completed_list.empty()) {
297
        if (!reap_pending_list_timeout())
298
            return false;
299
    }
300

    
301
    while (!_completed_list.empty()) {
302
        lut = completed_list_get();
303
        print_transfer_status(lut);
304
        free_list_add(lut);
305
    }
306

    
307
    return true;
308
}
309

    
310

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

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

    
352

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

    
364
    if ((retval = libusb_handle_events(_ctx)) < 0) {
365
        std::cerr << "error: libusb_handle_events: " << retval << std::endl;
366
        return false;
367
    }
368

    
369
    return true;
370
}
371

    
372

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

    
386
    tv.tv_sec = 0;
387
    tv.tv_usec = 100000; //100ms
388

    
389
    size_t pending_list_size = _pending_list.size();
390

    
391
    if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) {
392
        std::cerr << "error: libusb_handle_events: " << retval << std::endl;
393
        return false;
394
    }
395

    
396
    if (_pending_list.size() < pending_list_size) {
397
        return true;
398
    }
399
    else {
400
        return false;
401
    }
402
}
403

    
404

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

    
417
    return free_list_get();
418
}
419

    
420

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

    
433
    return completed_list_get();
434
}
435

    
436
/*
437
 * List operations 
438
 */
439
void usb_endpoint::free_list_add(libusb_transfer *lut)
440
{
441
    _free_list.push_back(lut);
442
}
443

    
444
void usb_endpoint::pending_list_add(libusb_transfer *lut)
445
{
446
    _pending_list.push_back(lut);
447
}
448

    
449
void usb_endpoint::completed_list_add(libusb_transfer *lut)
450
{
451
    _completed_list.push_back(lut);
452
}
453

    
454

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

    
463
    if (_free_list.size() == 0) {
464
        return NULL; 
465
    }
466
    else { 
467
        lut = _free_list.front();
468
        _free_list.pop_front();
469
        return lut;
470
    }
471
}
472

    
473

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

    
482
    if (_completed_list.empty()) {
483
        return NULL;
484
    }
485
    else { 
486
        lut = _completed_list.front();
487
        _completed_list.pop_front();
488
        return lut;
489
    }
490
}
491

    
492

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

    
511

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

    
532
    ~libusb_managed_recv_buffer_impl()
533
    {
534
       if (!_endpoint->submit(_lut))
535
           std::cerr << "USB: failed to submit IN transfer" << std::endl;
536
    }
537

    
538
private:
539
    const boost::asio::const_buffer &get() const
540
    {
541
        return _buff; 
542
    }
543

    
544
    libusb_transfer *_lut;
545
    usb_endpoint *_endpoint;
546
    const boost::asio::const_buffer _buff;
547
};
548

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

    
569
    ~libusb_managed_send_buffer_impl()
570
    {
571
        if (!_committed) {
572
            _lut->length = 0;
573
            _lut->actual_length = 0;
574
            _endpoint->submit(_lut);
575
        }
576
    }
577

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

    
587
        _lut->length = num_bytes;
588
        _lut->actual_length = 0;
589

    
590
        if (_endpoint->submit(_lut)) {
591
            _committed = true;
592
            return num_bytes;
593
        }
594
        else {
595
            return 0;
596
        }
597
    }
598

    
599
private:
600
    const boost::asio::mutable_buffer &get() const
601
    {
602
        return _buff; 
603
    }
604

    
605
    libusb_transfer *_lut;
606
    usb_endpoint *_endpoint;
607
    const boost::asio::mutable_buffer _buff;
608
    bool _committed;
609
};
610

    
611

    
612
/***********************************************************************
613
 * USB zero_copy device class
614
 **********************************************************************/
615
class libusb_zero_copy_impl : public usb_zero_copy
616
{
617
private:
618
    usb_endpoint          *_rx_ep;
619
    usb_endpoint          *_tx_ep;
620

    
621
    // Maintain libusb values
622
    libusb_context       *_rx_ctx;
623
    libusb_context       *_tx_ctx;
624
    libusb_device_handle *_rx_dev_handle;
625
    libusb_device_handle *_tx_dev_handle;
626

    
627
    size_t _recv_buff_size;
628
    size_t _send_buff_size;
629
    size_t _num_frames;
630

    
631
public:
632
    typedef boost::shared_ptr<libusb_zero_copy_impl> sptr;
633

    
634
    libusb_zero_copy_impl(usb_device_handle::sptr handle,
635
                          unsigned int rx_endpoint,
636
                          unsigned int tx_endpoint,
637
                          size_t recv_buff_size,
638
                          size_t send_buff_size);
639
    
640
    ~libusb_zero_copy_impl();
641

    
642
    managed_recv_buffer::sptr get_recv_buff(void);
643
    managed_send_buffer::sptr get_send_buff(void);
644

    
645
    size_t get_num_recv_frames(void) const { return _num_frames; }
646
    size_t get_num_send_frames(void) const { return _num_frames; }
647
};
648

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

    
668
    UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL));
669

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

    
676
    // Open USB interfaces for tx/rx using magic values.
677
    // IN interface:      2
678
    // OUT interface:     1
679
    // Control interface: 0
680
    libusb::open_interface(_rx_dev_handle, 2);
681
    libusb::open_interface(_tx_dev_handle, 1);
682

    
683
    _rx_ep = new usb_endpoint(_rx_dev_handle,  // libusb device_handle
684
                              _rx_ctx,         // libusb context
685
                              rx_endpoint,     // USB endpoint number
686
                              true,            // IN endpoint
687
                              _recv_buff_size, // buffer size per transfer 
688
                              _num_frames);    // number of libusb transfers
689

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

    
698

    
699
libusb_zero_copy_impl::~libusb_zero_copy_impl()
700
{
701
    delete _rx_ep;
702
    delete _tx_ep; 
703

    
704
    libusb_close(_rx_dev_handle);
705
    libusb_close(_tx_dev_handle);
706

    
707
    libusb_exit(_rx_ctx);
708
    libusb_exit(_tx_ctx);
709
}
710

    
711

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

    
731

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

    
752

    
753
/***********************************************************************
754
 * USB zero_copy make functions
755
 **********************************************************************/
756
usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle,
757
                                        unsigned int rx_endpoint,
758
                                        unsigned int tx_endpoint,
759
                                        size_t buff_size,
760
                                        size_t block_size)
761

    
762
{
763
    return sptr(new libusb_zero_copy_impl(handle,
764
                                          rx_endpoint,
765
                                          tx_endpoint,
766
                                          buff_size, 
767
                                          block_size));
768
}
769

    
770

    
771