Statistics
| Branch: | Tag: | Revision:

root / host / lib / transport / libusb1_zero_copy.cpp @ 86c86ede

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

    
19
#include <uhd/transport/usb_zero_copy.hpp>
20
#include <uhd/utils/assert.hpp>
21
#include <libusb-1.0/libusb.h>
22
#include <boost/asio.hpp>
23
#include <boost/format.hpp>
24
#include <iostream>
25
#include <iomanip>
26

    
27
using namespace uhd::transport;
28

    
29
static int libusb_debug_level = 3;
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
    /*
68
     * Transfer state lists (free, pending, or completed)
69
     */
70
    std::list<libusb_transfer *>  _free_list;
71
    std::list<libusb_transfer *>  _pending_list;
72
    std::list<libusb_transfer *>  _completed_list;
73

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

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

    
94
    /*
95
     * Misc
96
     */
97
    void print_transfer_status(libusb_transfer *lut);
98

    
99
public:
100
    usb_endpoint(libusb_device_handle *dev_handle,
101
                 libusb_context *ctx, int endpoint, bool input,
102
                 size_t transfer_size, size_t num_transfers);
103

    
104
    ~usb_endpoint();
105

    
106
    /*
107
     * Accessors 
108
     */
109
    int get_endpoint() const { return _endpoint; }
110
    bool get_direction() const { return _input; }
111
    libusb_device_handle *get_dev_handle() const { return _dev_handle; }
112
    libusb_context *get_ctx() const { return _ctx; }
113

    
114
    /*
115
     * Exposed interface for submitting / retrieving transfer buffers
116
     * used in zero-copy interface
117
     */
118
    bool submit(libusb_transfer *lut);
119
    libusb_transfer *get_completed_transfer();
120
    libusb_transfer *get_free_transfer();
121

    
122
    /*
123
     * Callback use only
124
     */
125
    void callback_handle_transfer(libusb_transfer *lut);
126
};
127

    
128

    
129
/*
130
 * Callback function called when submitted transfers complete.
131
 * The endpoint upon which the transfer is part of is recovered
132
 * and the transfer moved from pending to completed state.
133
 */
134
static void callback(libusb_transfer *lut)
135
{
136
    usb_endpoint *endpoint = (usb_endpoint *) lut->user_data; 
137
    endpoint->callback_handle_transfer(lut);
138
}
139

    
140

    
141
/*
142
 * Accessor call to allow list access from callback space
143
 */
144
void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)
145
{
146
    if (!pending_list_remove(lut)) {
147
        std::cerr << "USB: pending remove failed" << std::endl;
148
        return;
149
    }
150

    
151
    completed_list_add(lut);    
152
}
153

    
154

    
155
/*
156
 * Constructor
157
 *
158
 * Allocate libusb transfers. For IN endpoints, submit the transfers
159
 * so that they're ready to return when data is available. 
160
 */
161
usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,
162
                          libusb_context *ctx, int endpoint, bool input,
163
                          size_t transfer_size, size_t num_transfers)
164
    : _dev_handle(dev_handle),
165
      _ctx(ctx), _endpoint(endpoint), _input(input),
166
      _transfer_size(transfer_size), _num_transfers(num_transfers)
167
{
168
    unsigned int i;
169
    for (i = 0; i < _num_transfers; i++) {
170
        free_list_add(allocate_transfer(_transfer_size));
171

    
172
        if (_input)
173
            submit(free_list_get());
174
    }
175
}
176

    
177

    
178
/*
179
 * Destructor
180
 */
181
usb_endpoint::~usb_endpoint()
182
{
183
    cancel_all();
184

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

    
190
    while (!_completed_list.empty()) {
191
        if (!reap_completed_list())
192
            std::cerr << "error: destructor failed to reap" << std::endl;
193
    }
194

    
195
    while (!_free_list.empty()) {
196
        libusb_free_transfer(free_list_get());
197
    }
198
}
199

    
200

    
201
/*
202
 * Allocate a libusb transfer 
203
 *
204
 * The allocated transfer is continuously reused and should be freed at
205
 * shutdown.
206
 */
207
libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)
208
{
209
    libusb_transfer *lut = libusb_alloc_transfer(0);
210

    
211
    unsigned char *buff = new unsigned char[buff_len];
212

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

    
215
    libusb_fill_bulk_transfer(lut,                // transfer
216
                              _dev_handle,        // dev_handle
217
                              endpoint,           // endpoint
218
                              buff,               // buffer
219
                              buff_len,           // length
220
                              callback,           // callback
221
                              this,               // user_data
222
                              0);                 // timeout
223
    return lut;
224
}
225

    
226

    
227
/*
228
 * Asynchonous transfer submission
229
 *
230
 * Submit and mark transfer as pending.
231
 */
232
bool usb_endpoint::submit(libusb_transfer *lut)
233
{
234
    int retval;
235
    if ((retval = libusb_submit_transfer(lut)) < 0) {
236
        std::cerr << "error: libusb_submit_transfer: " << retval << std::endl;
237
        return false;
238
    }
239

    
240
    pending_list_add(lut);
241
    return true;
242
}
243

    
244

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

    
266

    
267
/*
268
 * Cancel all pending transfers 
269
 *
270
 * Note: success only indicates submission of cancelation request.
271
 * Sucessful cancelation is not known until the callback occurs.
272
 */
273
bool usb_endpoint::cancel_all()
274
{
275
    std::list<libusb_transfer*>::iterator iter;
276

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

    
284
    return true;
285
}
286

    
287

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

    
300
    if (_completed_list.empty()) {
301
        if (!reap_pending_list_timeout())
302
            return false;
303
    }
304

    
305
    while (!_completed_list.empty()) {
306
        lut = completed_list_get();
307
        print_transfer_status(lut);
308
        free_list_add(lut);
309
    }
310

    
311
    return true;
312
}
313

    
314

    
315
/*
316
 * Print completed transfer status error(s) 
317
 * 
318
 * return true if at least one transfer was reaped, false otherwise. 
319
 *
320
 * Check completed transfers for errors and mark as free. This is a
321
 * blocking call. 
322
 */
323
void usb_endpoint::print_transfer_status(libusb_transfer *lut)
324
{
325
    switch (lut->status) {
326
    case LIBUSB_TRANSFER_COMPLETED:
327
        if (lut->actual_length < lut->length) {
328
            std::cerr << "USB: transfer completed with short write,"
329
                      << " length = " << lut->length
330
                      << " actual = " << lut->actual_length << std::endl;
331
        }
332

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

    
360

    
361
/*
362
 * Reap pending transfers 
363
 *
364
 * Return true if at least one transfer was reaped, false otherwise. This is
365
 * a blocking call.
366
 *
367
 * Reaping submitted transfers is handled by libusb and the assigned callback
368
 * function. Block until at least one transfer is reaped.
369
 */
370
bool usb_endpoint::reap_pending_list()
371
{
372
    int retval;
373

    
374
    if ((retval = libusb_handle_events(_ctx)) < 0) {
375
        std::cerr << "error: libusb_handle_events: " << retval << std::endl;
376
        return false;
377
    }
378

    
379
    return true;
380
}
381

    
382

    
383
/*
384
 * Reap pending transfers with timeout 
385
 *
386
 * Return true if at least one transfer was reaped, false otherwise. This call
387
 * blocks until a transfer is reaped or timeout.
388
 *
389
 * Reaping submitted transfers is handled by libusb and the assigned callback
390
 * function. Block until at least one transfer is reaped or timeout occurs.
391
 */
392
bool usb_endpoint::reap_pending_list_timeout()
393
{
394
    int retval;
395
    timeval tv;
396

    
397
    tv.tv_sec = 0;
398
    tv.tv_usec = 100000; //100ms
399

    
400
    size_t pending_list_size = _pending_list.size();
401

    
402
    if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) {
403
        std::cerr << "error: libusb_handle_events: " << retval << std::endl;
404
        return false;
405
    }
406

    
407
    if (_pending_list.size() < pending_list_size) {
408
        return true;
409
    }
410
    else {
411
        return false;
412
    }
413
}
414

    
415

    
416
/*
417
 * Returns a free transfer with empty data bufer for OUT requests 
418
 */
419
libusb_transfer *usb_endpoint::get_free_transfer()
420
{
421
    if (_free_list.empty()) {
422
        if (!reap_completed_list())
423
            return NULL; 
424
    }
425

    
426
    return free_list_get();
427
}
428

    
429

    
430
/*
431
 * Returns a transfer containing data for IN requests
432
 */
433
libusb_transfer *usb_endpoint::get_completed_transfer()
434
{
435
    if (_completed_list.empty()) {
436
        if (!reap_pending_list_timeout())
437
            return NULL; 
438
    }
439

    
440
    return completed_list_get();
441
}
442

    
443
/*
444
 * List operations 
445
 */
446
void usb_endpoint::free_list_add(libusb_transfer *lut)
447
{
448
    _free_list.push_back(lut);
449
}
450

    
451
void usb_endpoint::pending_list_add(libusb_transfer *lut)
452
{
453
    _pending_list.push_back(lut);
454
}
455

    
456
void usb_endpoint::completed_list_add(libusb_transfer *lut)
457
{
458
    _completed_list.push_back(lut);
459
}
460

    
461

    
462
/*
463
 * Free and completed lists don't have ordered content 
464
 *
465
 * Pop transfers from the front as needed
466
 */
467
libusb_transfer *usb_endpoint::free_list_get()
468
{
469
    libusb_transfer *lut;
470

    
471
    if (_free_list.size() == 0) {
472
        return NULL; 
473
    }
474
    else { 
475
        lut = _free_list.front();
476
        _free_list.pop_front();
477
        return lut;
478
    }
479
}
480

    
481

    
482
/*
483
 * Free and completed lists don't have ordered content 
484
 *
485
 * Pop transfers from the front as needed
486
 */
487
libusb_transfer *usb_endpoint::completed_list_get()
488
{
489
    libusb_transfer *lut;
490

    
491
    if (_completed_list.empty()) {
492
        return NULL;
493
    }
494
    else { 
495
        lut = _completed_list.front();
496
        _completed_list.pop_front();
497
        return lut;
498
    }
499
}
500

    
501

    
502
/*
503
 * Search and remove transfer from pending list
504
 *
505
 * Assuming that the callbacks occur in order, the front element
506
 * should yield the correct transfer. If not, then something else
507
 * is going on. If no transfers match, then something went wrong.
508
 */
509
bool usb_endpoint::pending_list_remove(libusb_transfer *lut)
510
{
511
    std::list<libusb_transfer*>::iterator iter;
512
    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
513
        if (*iter == lut) { 
514
            _pending_list.erase(iter);
515
            return true;
516
        }
517
    }
518
    return false;
519
}
520

    
521

    
522
/***********************************************************************
523
 * Managed buffers 
524
 **********************************************************************/
525
class libusb_managed_recv_buffer_impl : public managed_recv_buffer {
526
public:
527
    libusb_managed_recv_buffer_impl(libusb_transfer *lut,
528
                                    usb_endpoint *endpoint)
529
        : _buff(lut->buffer, lut->length)
530
    {
531
        _lut = lut;
532
        _endpoint = endpoint;
533
    }
534

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

    
541
private:
542
    const boost::asio::const_buffer &get() const
543
    {
544
        return _buff; 
545
    }
546

    
547
    libusb_transfer *_lut;
548
    usb_endpoint *_endpoint;
549
    const boost::asio::const_buffer _buff;
550
};
551

    
552

    
553
class libusb_managed_send_buffer_impl : public managed_send_buffer {
554
public:
555
    libusb_managed_send_buffer_impl(libusb_transfer *lut,
556
                                    usb_endpoint *endpoint,
557
                                    size_t buff_size)
558
        : _buff(lut->buffer, buff_size)
559
    {
560
        _lut = lut;
561
        _endpoint = endpoint;
562
    }
563

    
564
    ~libusb_managed_send_buffer_impl()
565
    {
566
        /* NOP */
567
    }
568

    
569
    ssize_t commit(size_t num_bytes)
570
    {
571
        _lut->length = num_bytes;
572
        _lut->actual_length = 0;
573

    
574
        if (_endpoint->submit(_lut))
575
            return num_bytes;
576
        else
577
            return 0;
578
    }
579

    
580
private:
581
    const boost::asio::mutable_buffer &get() const
582
    {
583
        return _buff; 
584
    }
585

    
586
    libusb_transfer *_lut;
587
    usb_endpoint *_endpoint;
588
    const boost::asio::mutable_buffer _buff;
589
};
590

    
591

    
592
/***********************************************************************
593
 * USB zero_copy device class
594
 **********************************************************************/
595
class libusb_zero_copy_impl : public usb_zero_copy
596
{
597
private:
598
    usb_endpoint          *_rx_ep;
599
    usb_endpoint          *_tx_ep;
600

    
601
    /*
602
     * Libusb handles
603
     */
604
    libusb_context       *_rx_ctx;
605
    libusb_context       *_tx_ctx;
606
    libusb_device_handle *_rx_dev_handle;
607
    libusb_device_handle *_tx_dev_handle;
608

    
609
    int _rx_endpoint;
610
    int _tx_endpoint;
611

    
612
    size_t _recv_buff_size;
613
    size_t _send_buff_size;
614
    size_t _num_frames;
615

    
616
    bool open_device(uhd::usb_descriptor_t descriptor);
617
    bool open_interface(libusb_device_handle *dev_handle, int interface);
618
    bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor);
619

    
620
    std::string get_serial(libusb_device *dev);
621

    
622
public:
623
    typedef boost::shared_ptr<libusb_zero_copy_impl> sptr;
624

    
625
    /*
626
     * Structors
627
     */
628
    libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor,
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
libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor,
645
                                             unsigned int rx_endpoint,
646
                                             unsigned int tx_endpoint,
647
                                             size_t buff_size,
648
                                             size_t block_size)
649
 : _rx_ctx(NULL), _tx_ctx(NULL), _rx_dev_handle(NULL), _tx_dev_handle(NULL),
650
   _recv_buff_size(block_size), _send_buff_size(block_size),
651
   _num_frames(buff_size / block_size)
652
{
653
    if (libusb_init(&_rx_ctx) < 0)
654
        std::cerr << "error: libusb_init" << std::endl;
655

    
656
    if (libusb_init(&_tx_ctx) < 0)
657
        std::cerr << "error: libusb_init" << std::endl;
658

    
659
    libusb_set_debug(_rx_ctx, libusb_debug_level);
660
    libusb_set_debug(_tx_ctx, libusb_debug_level);
661

    
662
    open_device(descriptor);
663

    
664
    open_interface(_rx_dev_handle, 2);
665
    open_interface(_tx_dev_handle, 1);
666

    
667
    _rx_ep = new usb_endpoint(_rx_dev_handle,
668
                              _rx_ctx,
669
                              rx_endpoint,
670
                              true,
671
                              _recv_buff_size,
672
                              _num_frames); 
673

    
674
    _tx_ep = new usb_endpoint(_tx_dev_handle,
675
                              _tx_ctx,
676
                              tx_endpoint,
677
                              false,
678
                              _send_buff_size,
679
                              _num_frames);
680
}
681

    
682

    
683
libusb_zero_copy_impl::~libusb_zero_copy_impl()
684
{
685
    delete _rx_ep;
686
    delete _tx_ep; 
687

    
688
    libusb_close(_rx_dev_handle);
689
    libusb_close(_tx_dev_handle);
690

    
691
    libusb_exit(_rx_ctx);
692
    libusb_exit(_tx_ctx);
693
}
694

    
695

    
696
bool libusb_zero_copy_impl::open_device(uhd::usb_descriptor_t descriptor)
697
{
698
    libusb_device **rx_list;
699
    libusb_device **tx_list;
700

    
701
    bool rx_found = false;
702
    bool tx_found = false;
703

    
704
    ssize_t rx_cnt = libusb_get_device_list(_rx_ctx, &rx_list);
705
    ssize_t tx_cnt = libusb_get_device_list(_tx_ctx, &tx_list);
706

    
707
    if ((rx_cnt < 0) | (tx_cnt < 0) | (rx_cnt != tx_cnt))
708
        return false;
709

    
710
    //find and open the receive device
711
    for (ssize_t i = 0; i < rx_cnt; i++) {
712
        libusb_device *dev = rx_list[i];
713

    
714
        if (compare_device(dev, descriptor)) {
715
            libusb_open(dev, &_rx_dev_handle);
716
            rx_found = true;
717
            break;
718
        }
719
    }
720

    
721
    //find and open the transmit device
722
    for (ssize_t i = 0; i < tx_cnt; i++) {
723
        libusb_device *dev = tx_list[i];
724

    
725
        if (compare_device(dev, descriptor)) {
726
            libusb_open(dev, &_tx_dev_handle);
727
            tx_found = true;
728
        }
729
    }
730

    
731
    libusb_free_device_list(rx_list, 0);
732
    libusb_free_device_list(tx_list, 0);
733

    
734
    if (tx_found && rx_found)
735
        return true;
736
    else
737
        return false;
738
}
739

    
740
bool libusb_zero_copy_impl::compare_device(libusb_device *dev,
741
                                        uhd::usb_descriptor_t descriptor)
742
{
743
    std::string serial         = descriptor.serial;
744
    boost::uint16_t vendor_id  = descriptor.vendor_id;
745
    boost::uint16_t product_id = descriptor.product_id;
746
    boost::uint8_t device_addr = descriptor.device_addr;
747

    
748
    libusb_device_descriptor desc;
749
    libusb_get_device_descriptor(dev, &desc);
750

    
751
    if (serial.compare(get_serial(dev)))
752
        return false;
753
    if (vendor_id != desc.idVendor)
754
        return false;
755
    if (product_id != desc.idProduct)
756
        return false;
757
    if (device_addr != libusb_get_device_address(dev))
758
        return false;
759

    
760
    return true;
761
}
762

    
763
bool libusb_zero_copy_impl::open_interface(libusb_device_handle *dev_handle,
764
                                           int interface)
765
{
766
    int ret = libusb_claim_interface(dev_handle, interface);
767
    if (ret < 0) {
768
        std::cerr << "error: libusb_claim_interface() " << ret << std::endl;
769
        return false;
770
    }
771
    else {
772
        return true;
773
    }
774
}
775

    
776
std::string libusb_zero_copy_impl::get_serial(libusb_device *dev)
777
{
778
    unsigned char buff[32];
779

    
780
    libusb_device_descriptor desc;
781
    if (libusb_get_device_descriptor(dev, &desc) < 0) {
782
        std::cerr << "error: libusb_get_device_descriptor()" << std::endl;
783
        return "";
784
    }
785

    
786
    if (desc.iSerialNumber == 0)
787
        return "";
788

    
789
    //open the device because we have to
790
    libusb_device_handle *dev_handle;
791
    if (libusb_open(dev, &dev_handle) < 0) {
792
        return "";
793
    }
794

    
795
    if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber,
796
                                           buff, sizeof(buff)) < 0) {
797
        std::cerr << "error: libusb_get_string_descriptor_ascii()" << std::endl;
798
        return "";
799
    }
800

    
801
    libusb_close(dev_handle);
802

    
803
    return (char*) buff;
804
}
805

    
806

    
807
managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()
808
{
809
    libusb_transfer *lut = _rx_ep->get_completed_transfer();
810
    if (lut == NULL) {
811
        return managed_recv_buffer::sptr();
812
    }
813
    else {
814
        return managed_recv_buffer::sptr(
815
            new libusb_managed_recv_buffer_impl(lut,
816
                                                _rx_ep));
817
    }
818
}
819

    
820

    
821
managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff()
822
{
823
    libusb_transfer *lut = _tx_ep->get_free_transfer();
824
    if (lut == NULL) {
825
        return managed_send_buffer::sptr();
826
    }
827
    else {
828
        return managed_send_buffer::sptr(
829
            new libusb_managed_send_buffer_impl(lut,
830
                                                _tx_ep,
831
                                                _send_buff_size));
832
    }
833
}
834

    
835

    
836
/***********************************************************************
837
 * USB zero_copy make functions
838
 **********************************************************************/
839
usb_zero_copy::sptr usb_zero_copy::make(uhd::usb_descriptor_t descriptor,
840
                                        unsigned int rx_endpoint,
841
                                        unsigned int tx_endpoint,
842
                                        size_t buff_size,
843
                                        size_t block_size)
844

    
845
{
846
    return sptr(new libusb_zero_copy_impl(descriptor,
847
                                          rx_endpoint,
848
                                          tx_endpoint,
849
                                          buff_size, 
850
                                          block_size));
851
}
852

    
853

    
854