OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.61/] [tools/] [src/] [librlink/] [RlinkPortCuff.cpp] - Blame information for rev 40

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 22 wfjm
// $Id: RlinkPortCuff.cpp 524 2013-06-30 19:10:30Z mueller $
2 17 wfjm
//
3
// Copyright 2012-2013 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16 22 wfjm
// 2013-05-17   521   1.1.1  use Rtools::String2Long
17 19 wfjm
// 2013-02-23   492   1.1    use RparseUrl
18
// 2013-02-10   485   1.0.3  add static const defs
19
// 2013-02-03   481   1.0.2  use Rexception
20 17 wfjm
// 2013-01-02   467   1.0.1  get cleanup code right; add USBErrorName()
21
// 2012-12-26   465   1.0    Initial version
22
// ---------------------------------------------------------------------------
23
 
24
/*!
25
  \file
26 22 wfjm
  \version $Id: RlinkPortCuff.cpp 524 2013-06-30 19:10:30Z mueller $
27 17 wfjm
  \brief   Implemenation of RlinkPortCuff.
28
*/
29
 
30
#include <errno.h>
31
#include <unistd.h>
32
#include <sys/time.h>
33
#include <time.h>
34
#include <stdio.h>
35 19 wfjm
#include <string.h>
36 17 wfjm
 
37 19 wfjm
#include <iostream>
38
#include <sstream>
39 17 wfjm
 
40
#include "RlinkPortCuff.hpp"
41
 
42 19 wfjm
#include "librtools/Rexception.hpp"
43 22 wfjm
#include "librtools/Rtools.hpp"
44 19 wfjm
 
45 17 wfjm
using namespace std;
46
 
47
/*!
48
  \class Retro::RlinkPortCuff
49 19 wfjm
  \brief FIXME_docs
50 17 wfjm
*/
51
 
52 19 wfjm
// all method definitions in namespace Retro
53
namespace Retro {
54
 
55 17 wfjm
//------------------------------------------+-----------------------------------
56 19 wfjm
// constants definitions
57
 
58
const size_t RlinkPortCuff::kUSBBufferSize;
59
const int    RlinkPortCuff::kUSBWriteEP;
60
const int    RlinkPortCuff::kUSBReadEP;
61
const size_t RlinkPortCuff::kUSBReadQueue;
62
 
63
//------------------------------------------+-----------------------------------
64 17 wfjm
//! Default constructor
65
 
66
RlinkPortCuff::RlinkPortCuff()
67
  : RlinkPort(),
68
    fFdReadDriver(-1),
69
    fFdWriteDriver(-1),
70
    fpUsbContext(0),
71
    fpUsbDevList(0),
72
    fUsbDevCount(0),
73
    fpUsbDevHdl(0),
74
    fLoopState(kLoopStateStopped)
75
{
76
  fStats.Define(kStatNPollAddCB,    "kStatNPollAddCB",    "USB poll add cb");
77
  fStats.Define(kStatNPollRemoveCB, "kStatNPollRemoveCB", "USB poll remove cb");
78
  fStats.Define(kStatNUSBWrite,     "kStatNUSBWrite",     "USB write done");
79
  fStats.Define(kStatNUSBRead,      "kStatNUSBRead",      "USB read done");
80
}
81
 
82
//------------------------------------------+-----------------------------------
83
//! Destructor
84
 
85
RlinkPortCuff::~RlinkPortCuff()
86
{
87
  if (IsOpen()) RlinkPortCuff::Close();
88
}
89
 
90
//------------------------------------------+-----------------------------------
91 19 wfjm
//! FIXME_docs
92 17 wfjm
 
93
bool RlinkPortCuff::Open(const std::string& url, RerrMsg& emsg)
94
{
95
  int irc;
96
 
97
  if (IsOpen()) Close();
98
 
99 19 wfjm
  if (!fUrl.Set(url, "|trace|", emsg)) return false;
100 17 wfjm
 
101
  // initialize USB context
102
  irc = libusb_init(&fpUsbContext);
103
  if (irc != 0) {
104
    emsg.Init("RlinkPortCuff::Open()",
105
              string("libusb_init() failed: ") +
106
              string(USBErrorName(irc)));
107
    Cleanup();
108
    return false;
109
  }
110
  // setup libusb level debug
111
  libusb_set_debug(fpUsbContext, 3);        // info->stdout, warn+err->stderr
112
 
113
  // check for internal timeout handling support
114
  if (libusb_pollfds_handle_timeouts(fpUsbContext) == 0) {
115
    emsg.Init("RlinkPortCuff::Open()",
116
              string("libusb_pollfds_handle_timeouts == 0 : "
117
                     "this program will not run on this legacy system"));
118
    Cleanup();
119
    return false;
120
  }
121
 
122
  // get USB device list
123
  fUsbDevCount = libusb_get_device_list(fpUsbContext, &fpUsbDevList);
124
 
125
  // determine USB path name
126 19 wfjm
  if (fUrl.Path().length() == 0) {
127
    char* env_vid = ::getenv("RETRO_FX2_VID");
128
    char* env_pid = ::getenv("RETRO_FX2_PID");
129
    if (env_vid && ::strlen(env_vid) == 4 &&
130
        env_pid && ::strlen(env_pid) == 4) {
131 21 wfjm
      fUrl.SetPath(string(env_vid) + ":" + string(env_pid));
132 17 wfjm
    } else {
133
      emsg.Init("RlinkPortCuff::Open()",
134 21 wfjm
                "RETRO_FX2_VID/PID not or ill defined");
135 17 wfjm
      Cleanup();
136
      return false;
137
    }
138
  }
139
 
140
  // connect to USB device
141
  libusb_device* mydev = 0;
142
  // path syntax: /bus/dev
143 19 wfjm
  if (fUrl.Path().length()==8 && fUrl.Path()[0]=='/' && fUrl.Path()[4]=='/') {
144
    string busnam = fUrl.Path().substr(1,3);
145
    string devnam = fUrl.Path().substr(5,3);
146 22 wfjm
    unsigned long busnum;
147
    unsigned long devnum;
148
    if (!Rtools::String2Long(busnam, busnum, emsg) ||
149
        !Rtools::String2Long(devnam, devnum, emsg)) {
150
      Cleanup();
151
      return false;
152
    }
153 17 wfjm
    for (ssize_t idev=0; idev<fUsbDevCount; idev++) {
154
      libusb_device* udev = fpUsbDevList[idev];
155
      if (libusb_get_bus_number(udev) == busnum &&
156
          libusb_get_device_address(udev) == devnum) {
157
        mydev = udev;
158
      }
159
    }
160
  // path syntax: vend:prod
161 19 wfjm
  } else if (fUrl.Path().length()==9 && fUrl.Path()[4]==':') {
162
    string vennam = fUrl.Path().substr(0,4);
163
    string pronam = fUrl.Path().substr(5,4);
164 22 wfjm
    unsigned long vennum;
165
    unsigned long pronum;
166
    if (!Rtools::String2Long(vennam, vennum, emsg, 16) ||
167
        !Rtools::String2Long(pronam, pronum, emsg, 16)) {
168
      Cleanup();
169
      return false;
170
    }
171 17 wfjm
    for (ssize_t idev=0; idev<fUsbDevCount; idev++) {
172
      libusb_device* udev = fpUsbDevList[idev];
173
      libusb_device_descriptor devdsc;
174
      libusb_get_device_descriptor(udev, &devdsc);
175
      if (devdsc.idVendor==vennum && devdsc.idProduct==pronum) {
176
        mydev = udev;
177
      }
178
    }
179
  } else {
180
    emsg.Init("RlinkPortCuff::Open()",
181 19 wfjm
              string("invalid usb path '") + fUrl.Path() +
182 17 wfjm
              "', not '/bus/dev' or 'vend:prod'");
183
    Cleanup();
184
    return false;
185
  }
186 22 wfjm
 
187 17 wfjm
  if (mydev == 0) {
188
    emsg.Init("RlinkPortCuff::Open()",
189 19 wfjm
              string("no usb device '") + fUrl.Path() + "', found'");
190 17 wfjm
    Cleanup();
191
    return false;
192
  }
193
 
194
  irc = libusb_open(mydev, &fpUsbDevHdl);
195
  if (irc) {
196
    fpUsbDevHdl = 0;
197
    emsg.Init("RlinkPortCuff::Open()",
198 19 wfjm
              string("opening usb device '") + fUrl.Path() + "', failed: " +
199 17 wfjm
              string(USBErrorName(irc)));
200
    Cleanup();
201
    return false;
202
  }
203 19 wfjm
  if (TraceOn()) cout << "libusb_open ok for '" << fUrl.Path() << "'" << endl;
204 17 wfjm
 
205
  // claim USB device
206
  irc = libusb_claim_interface(fpUsbDevHdl, 0);
207
  if (irc) {
208
    emsg.Init("RlinkPortCuff::Open()",
209 19 wfjm
              string("failed to claim '") + fUrl.Path() + "': " +
210 17 wfjm
              string(USBErrorName(irc)));
211
    Cleanup();
212
    return false;
213
  }
214
 
215
  // setup write pipe
216
  if (!OpenPipe(fFdWriteDriver, fFdWrite, emsg)) {
217
    Cleanup();
218
    return false;
219
  }
220
  // setup read pipe
221
  if (!OpenPipe(fFdRead, fFdReadDriver, emsg)) {
222
    Cleanup();
223
    return false;
224
  }
225
 
226
  // setup pollfd list
227
  fPollFds.clear();
228
 
229
  // 1. write pipe allert (is always 1st in list)
230
  PollfdAdd(fFdWriteDriver, POLLIN);
231
 
232
  // 2. libusb callbacks
233
  const libusb_pollfd** plist = libusb_get_pollfds(fpUsbContext);
234
  for (const libusb_pollfd** p = plist; *p !=0; p++) {
235
    PollfdAdd((*p)->fd, (*p)->events);
236
  }
237 19 wfjm
  ::free(plist);
238 17 wfjm
  libusb_set_pollfd_notifiers(fpUsbContext, ThunkPollfdAdd,
239
                              ThunkPollfdRemove, this);
240
 
241
  fDriverThread =  boost::thread(boost::bind(&RlinkPortCuff::Driver, this));
242
 
243
  fIsOpen  = true;
244
 
245
  return true;
246
}
247
 
248
//------------------------------------------+-----------------------------------
249 19 wfjm
//! FIXME_docs
250 17 wfjm
 
251
void RlinkPortCuff::Close()
252
{
253
  if (!IsOpen()) return;
254
 
255
  if (TraceOn()) cout << "Close() started" << endl;
256
  Cleanup();
257
  RlinkPort::Close();
258
 
259
  if (TraceOn()) cout << "Close() ended" << endl;
260
  return;
261
}
262
 
263
//------------------------------------------+-----------------------------------
264 19 wfjm
//! FIXME_docs
265 17 wfjm
 
266
void RlinkPortCuff::Cleanup()
267
{
268
  // close write pipe from user side -> causes event in driver and driver stop
269
  CloseFd(fFdWrite);
270
 
271
  // wait till driver thread terminates
272
  // use timed join, throw in case driver doesn't stop
273
  if (fDriverThread.get_id() != boost::thread::id()) {
274
    if (!fDriverThread.timed_join(boost::posix_time::milliseconds(500))) {
275 19 wfjm
      throw Rexception("RlinkPortCuff::Cleanup()",
276
                       "driver thread failed to stop");
277 17 wfjm
    }
278
  }
279
 
280
  // cleanup pipes
281
  CloseFd(fFdRead);
282
  CloseFd(fFdReadDriver);
283
  CloseFd(fFdWriteDriver);
284
 
285
  // cleanup USB context
286
  if (fpUsbContext) {
287
    if (fpUsbDevHdl) {
288
      libusb_release_interface(fpUsbDevHdl, 0);
289
      libusb_close(fpUsbDevHdl);
290
      fpUsbDevHdl = 0;
291
    }
292
    if (fpUsbDevList) {
293
      libusb_free_device_list(fpUsbDevList, 1);
294
      fpUsbDevList = 0;
295
    }
296
    libusb_set_pollfd_notifiers(fpUsbContext, NULL, NULL, NULL);
297
    libusb_exit(fpUsbContext);
298
    fpUsbContext = 0;
299
  }
300
 
301
  fPollFds.clear();
302
 
303
  return;
304
}
305
 
306
//------------------------------------------+-----------------------------------
307 19 wfjm
//! FIXME_docs
308 17 wfjm
 
309
bool RlinkPortCuff::OpenPipe(int& fdread, int& fdwrite, RerrMsg& emsg)
310
{
311
  int irc;
312
  int pipefd[2];
313
 
314 19 wfjm
  irc = ::pipe(pipefd);
315 17 wfjm
  if (irc < 0) {
316 21 wfjm
    emsg.InitErrno("RlinkPortCuff::OpenPipe()", "pipe() failed: ", errno);
317 17 wfjm
    return false;
318
  }
319
 
320
  fdread  = pipefd[0];
321
  fdwrite = pipefd[1];
322
 
323
  return true;
324
}
325
 
326
//------------------------------------------+-----------------------------------
327 19 wfjm
//! FIXME_docs
328 17 wfjm
 
329
// executed in separate boost thread !!
330
void RlinkPortCuff::Driver()
331
{
332
  try {
333
 
334
    // setup USB read-ahead queue
335
    for (size_t nr=0; nr<kUSBReadQueue; nr++) {
336
      libusb_transfer* t = libusb_alloc_transfer(0);
337
 
338
      t->dev_handle = fpUsbDevHdl;
339
      t->flags      = LIBUSB_TRANSFER_FREE_BUFFER;
340
      t->endpoint   = (unsigned char) (kUSBReadEP|0x80);
341
      t->type       = LIBUSB_TRANSFER_TYPE_BULK;
342
      t->timeout    = 0;
343
      t->status     = LIBUSB_TRANSFER_COMPLETED;
344 22 wfjm
      t->buffer     = (unsigned char*) ::malloc(kUSBBufferSize);
345 17 wfjm
      t->length     = kUSBBufferSize;
346
      t->actual_length = 0;
347
      t->callback   = ThunkUSBReadDone;
348
      t->user_data  = this;
349
 
350
      int irc = libusb_submit_transfer(t);
351
      if (irc) BadUSBCall("RlinkPortCuff::Driver()",
352
                        "libusb_submit_transfer()", irc);
353
      fReadQueuePending.push_back(t);
354
    }
355
 
356
    // event loop
357
    if (TraceOn()) cout << "event loop started" << endl;
358
    fLoopState = kLoopStateRunning;
359
    while(fLoopState == kLoopStateRunning) {
360 22 wfjm
      int irc = ::poll(fPollFds.data(), fPollFds.size(), 1000);
361 17 wfjm
      if (irc==-1 && errno==EINTR) continue;
362
      if (irc!=0 && TraceOn()) {
363
        cout << "poll() -> " << irc << " :";
364
        for (size_t i=0; i<fPollFds.size(); i++)
365
          if (fPollFds[i].revents) cout << " (" << fPollFds[i].fd << ","
366
                                        << fPollFds[i].events << ","
367
                                        << fPollFds[i].revents << ")";
368
        cout << endl;
369
      }
370
 
371
      if (irc < 0) BadSysCall("RlinkPortCuff::Driver()", "poll()", irc);
372
 
373
      if (fPollFds[0].revents & POLLHUP) {        // write pipe close event
374
        fLoopState = kLoopStateStopping;
375
      } else if (fPollFds[0].revents & POLLIN) {  // write pipe data event
376
        DriverEventWritePipe();
377
      } else {                              // assume USB timeout events
378
        DriverEventUSB();
379
      }
380
    }
381
 
382
    if (TraceOn()) cout << "event loop ended, cleanup started" << endl;
383
 
384
    for (size_t i=0; i<fWriteQueuePending.size(); i++) {
385
      libusb_cancel_transfer(fWriteQueuePending[i]);
386
    }
387
    for (size_t i=0; i<fReadQueuePending.size(); i++) {
388
      libusb_cancel_transfer(fReadQueuePending[i]);
389
    }
390
 
391
    while(fLoopState == kLoopStateStopping &&
392
          fWriteQueuePending.size() + fReadQueuePending.size() > 0) {
393 22 wfjm
      int irc = ::poll(fPollFds.data()+1, fPollFds.size()-1, 1000);
394 17 wfjm
      if (irc==-1 && errno==EINTR) continue;
395
      if (irc==0) break;
396
      if (irc < 0) BadSysCall("RlinkPortCuff::Driver()", "poll()", irc);
397
      DriverEventUSB();
398
    }
399
    if (fWriteQueuePending.size() + fReadQueuePending.size())
400 19 wfjm
      throw Rexception("RlinkPortCuff::Driver()", "cleanup timeout");
401 17 wfjm
 
402
    fLoopState = kLoopStateStopped;
403
    if (TraceOn()) cout << "cleanup ended" << endl;
404
 
405
  } catch (exception& e) {
406
    cout << "exception caught in RlinkPortCuff::Driver(): '" << e.what()
407
         << "'" << endl;
408
    // close read pipe at driver end -> that causes main thread to respond
409 22 wfjm
    ::close(fFdReadDriver);
410 17 wfjm
    fFdReadDriver = -1;
411
  }
412
 
413
  return;
414
}
415
 
416
//------------------------------------------+-----------------------------------
417 19 wfjm
//! FIXME_docs
418 17 wfjm
 
419
void RlinkPortCuff::DriverEventWritePipe()
420
{
421
  libusb_transfer* t = NewWriteTransfer();
422
 
423 22 wfjm
  ssize_t ircs = ::read(fFdWriteDriver, t->buffer, kUSBBufferSize);
424 17 wfjm
  if (TraceOn()) cout << "write pipe read() -> " << ircs << endl;
425
  if (ircs < 0) BadSysCall("RlinkPortCuff::DriverEventWritePipe()",
426
                           "read()", ircs);
427
 
428
  // pipe closed... end driver event loop
429
  if (ircs == 0) {
430
    fLoopState = kLoopStateStopping;
431
    return;
432
  }
433
 
434
  t->length = (int) ircs;
435
  int irc = libusb_submit_transfer(t);
436
  if (irc) BadUSBCall("RlinkPortCuff::DriverEventWritePipe()",
437
                      "libusb_submit_transfer()", irc);
438
  fWriteQueuePending.push_back(t);
439
 
440
  return;
441
}
442
 
443
//------------------------------------------+-----------------------------------
444 19 wfjm
//! FIXME_docs
445 17 wfjm
 
446
void RlinkPortCuff::DriverEventUSB()
447
{
448
  struct timeval tv;
449
  tv.tv_sec  = 0;
450
  tv.tv_usec = 0;
451
  int irc = libusb_handle_events_timeout(fpUsbContext, &tv);
452
  //setting the timeval pointer to NULL should work, but doesn't (in 1.0.6)
453
  //rc = libusb_handle_events_timeout(pUsbContext, 0);
454
  if (irc) BadUSBCall("RlinkPortCuff::DriverEventUSB()",
455
                      "libusb_handle_events_timeout()", irc);
456
  return;
457
}
458
 
459
//------------------------------------------+-----------------------------------
460 19 wfjm
//! FIXME_docs
461 17 wfjm
 
462
libusb_transfer* RlinkPortCuff::NewWriteTransfer()
463
{
464
  libusb_transfer* t = 0;
465
  if (!fWriteQueueFree.empty()) {
466
    t = fWriteQueueFree.front();
467
    fWriteQueueFree.pop_front();
468
  } else {
469
    t = libusb_alloc_transfer(0);
470
    t->dev_handle = fpUsbDevHdl;
471
    t->flags      = LIBUSB_TRANSFER_FREE_BUFFER;
472
    t->endpoint   = (unsigned char) (kUSBWriteEP);
473
    t->type       = LIBUSB_TRANSFER_TYPE_BULK;
474
    t->timeout    = 1000;
475 22 wfjm
    t->buffer     = (unsigned char*) ::malloc(kUSBBufferSize);
476 17 wfjm
    t->callback   = ThunkUSBWriteDone;
477
    t->user_data  = this;
478
  }
479
 
480
  t->status        = LIBUSB_TRANSFER_COMPLETED;
481
  t->length        = 0;
482
  t->actual_length = 0;
483
 
484
  return t;
485
}
486
 
487
//------------------------------------------+-----------------------------------
488 19 wfjm
//! FIXME_docs
489 17 wfjm
 
490
bool RlinkPortCuff::TraceOn()
491
{
492 19 wfjm
  if (!fUrl.FindOpt("trace")) return false;
493 17 wfjm
  struct timeval tv;
494
  struct timezone tz;
495
  struct tm tmval;
496
 
497 19 wfjm
  ::gettimeofday(&tv, &tz);
498
  ::localtime_r(&tv.tv_sec, &tmval);
499 17 wfjm
  char buf[20];
500 19 wfjm
  ::snprintf(buf, 20, "%02d:%02d:%02d.%06d: ",
501
             tmval.tm_hour, tmval.tm_min, tmval.tm_sec, (int) tv.tv_usec);
502 17 wfjm
  cout << buf;
503
  return true;
504
}
505
 
506
//------------------------------------------+-----------------------------------
507 19 wfjm
//! FIXME_docs
508 17 wfjm
 
509
void RlinkPortCuff::BadSysCall(const char* meth, const char* text, int rc)
510
{
511 19 wfjm
  stringstream ss;
512
  ss << rc;
513 21 wfjm
  throw Rexception(meth, string(text) + " failed with rc=" + ss.str(),
514 19 wfjm
                   errno);
515 17 wfjm
}
516
 
517
//------------------------------------------+-----------------------------------
518 19 wfjm
//! FIXME_docs
519 17 wfjm
 
520
void RlinkPortCuff::BadUSBCall(const char* meth, const char* text, int rc)
521
{
522 19 wfjm
  stringstream ss;
523
  ss << rc;
524 21 wfjm
  throw Rexception(meth, string(text) + " failed with rc=" + ss.str() +
525
                   " : " + string(USBErrorName(rc)));
526 17 wfjm
}
527
 
528
//------------------------------------------+-----------------------------------
529 19 wfjm
//! FIXME_docs
530 17 wfjm
 
531
void RlinkPortCuff::CheckUSBTransfer(const char* meth, libusb_transfer *t)
532
{
533
  const char* etext = 0;
534
 
535
  if (t->status == LIBUSB_TRANSFER_ERROR)     etext = "ERROR";
536
  if (t->status == LIBUSB_TRANSFER_STALL)     etext = "STALL";
537
  if (t->status == LIBUSB_TRANSFER_NO_DEVICE) etext = "NO_DEVICE";
538
  if (t->status == LIBUSB_TRANSFER_OVERFLOW)  etext = "OVERFLOW";
539
 
540
  if (etext == 0) return;
541
 
542
  char buf[1024];
543 19 wfjm
  ::snprintf(buf, 1024, "%s : transfer failure on ep=%d: %s",
544
             meth, (int)(t->endpoint&(~0x80)), etext);
545
  throw Rexception(meth, buf);
546 17 wfjm
}
547
 
548
//------------------------------------------+-----------------------------------
549 19 wfjm
//! FIXME_docs
550 17 wfjm
 
551
const char* RlinkPortCuff::USBErrorName(int rc)
552
{
553
  // Code taken verbatim from libusb-1.0.9.tar.bz2 function libusb_error_name
554
  // The libusb_error_name() function was added rather late in V1.0.9.
555
  // To allow usage with V1.0.8 and earlier this function is include here
556
 
557
  switch (rc) {
558
  case LIBUSB_SUCCESS:
559
    return "LIBUSB_SUCCESS";
560
  case LIBUSB_ERROR_IO:
561
    return "LIBUSB_ERROR_IO";
562
  case LIBUSB_ERROR_INVALID_PARAM:
563
    return "LIBUSB_ERROR_INVALID_PARAM";
564
  case LIBUSB_ERROR_ACCESS:
565
    return "LIBUSB_ERROR_ACCESS";
566
  case LIBUSB_ERROR_NO_DEVICE:
567
    return "LIBUSB_ERROR_NO_DEVICE";
568
  case LIBUSB_ERROR_NOT_FOUND:
569
    return "LIBUSB_ERROR_NOT_FOUND";
570
  case LIBUSB_ERROR_BUSY:
571
    return "LIBUSB_ERROR_BUSY";
572
  case LIBUSB_ERROR_TIMEOUT:
573
    return "LIBUSB_ERROR_TIMEOUT";
574
  case LIBUSB_ERROR_OVERFLOW:
575
    return "LIBUSB_ERROR_OVERFLOW";
576
  case LIBUSB_ERROR_PIPE:
577
    return "LIBUSB_ERROR_PIPE";
578
  case LIBUSB_ERROR_INTERRUPTED:
579
    return "LIBUSB_ERROR_INTERRUPTED";
580
  case LIBUSB_ERROR_NO_MEM:
581
    return "LIBUSB_ERROR_NO_MEM";
582
  case LIBUSB_ERROR_NOT_SUPPORTED:
583
    return "LIBUSB_ERROR_NOT_SUPPORTED";
584
  case LIBUSB_ERROR_OTHER:
585
    return "LIBUSB_ERROR_OTHER";
586
  }
587
  return "**UNKNOWN**";
588
}
589
 
590
//------------------------------------------+-----------------------------------
591 19 wfjm
//! FIXME_docs
592 17 wfjm
 
593
void RlinkPortCuff::PollfdAdd(int fd, short events)
594
{
595
  fStats.Inc(kStatNPollAddCB);
596
  pollfd pfd;
597
  pfd.fd      = fd;
598
  pfd.events  = events;
599
  pfd.revents = 0;
600
  fPollFds.push_back(pfd);
601
  return;
602
}
603
 
604
//------------------------------------------+-----------------------------------
605 19 wfjm
//! FIXME_docs
606 17 wfjm
 
607
void RlinkPortCuff::PollfdRemove(int fd)
608
{
609
  fStats.Inc(kStatNPollRemoveCB);
610
  for (size_t i=0; i<fPollFds.size(); ) {
611
    if (fPollFds[i].fd == fd) {
612
      fPollFds.erase(fPollFds.begin()+i);
613
    } else {
614
      i++;
615
    }
616
  }
617
  return;
618
}
619
 
620
//------------------------------------------+-----------------------------------
621 19 wfjm
//! FIXME_docs
622 17 wfjm
 
623
void RlinkPortCuff::USBWriteDone(libusb_transfer* t)
624
{
625
  if (TraceOn()) cout << "USB write done -> " << t->actual_length << endl;
626
 
627
  if (fWriteQueuePending.size() && t == fWriteQueuePending.front())
628
    fWriteQueuePending.pop_front();
629
  else
630 19 wfjm
    throw Rexception("RlinkPortCuff::USBWriteDone()",
631
                     "BugCheck: fWriteQueuePending disordered");
632 17 wfjm
 
633
  if (fLoopState == kLoopStateRunning) {
634
    CheckUSBTransfer("RlinkPortCuff::USBWriteDone()", t);
635
    fStats.Inc(kStatNUSBWrite);
636
    fWriteQueueFree.push_back(t);
637
 
638
  } else {
639
    libusb_free_transfer(t);
640
  }
641
  return;
642
}
643
 
644
//------------------------------------------+-----------------------------------
645 19 wfjm
//! FIXME_docs
646 17 wfjm
 
647
void RlinkPortCuff::USBReadDone(libusb_transfer* t)
648
{
649
  if (TraceOn()) cout << "USB read done -> " << t->actual_length << endl;
650
 
651
  if (fReadQueuePending.size() && t == fReadQueuePending.front())
652
    fReadQueuePending.pop_front();
653
  else
654 19 wfjm
    throw Rexception("RlinkPortCuff::USBReadDone()",
655
                     "BugCheck: fReadQueuePending disordered");
656 17 wfjm
 
657
  if (fLoopState == kLoopStateRunning) {
658
    CheckUSBTransfer("RlinkPortCuff::USBReadDone()", t);
659
    fStats.Inc(kStatNUSBRead);
660
    if (t->actual_length>0) {
661 22 wfjm
      ssize_t ircs = ::write(fFdReadDriver, t->buffer,
662
                             (size_t) t->actual_length);
663 17 wfjm
      if (ircs < 0) BadSysCall("RlinkPortCuff::USBReadDone()",
664
                               "write()", ircs);
665
    }
666
 
667
    t->status        = LIBUSB_TRANSFER_COMPLETED;
668
    t->actual_length = 0;
669
    int irc = libusb_submit_transfer(t);
670
    if (irc) BadUSBCall("RlinkPortCuff::USBReadDone()",
671
                        "libusb_submit_transfer()", irc);
672
    fReadQueuePending.push_back(t);
673
 
674
  } else {
675
    libusb_free_transfer(t);
676
  }
677
 
678
  return;
679
}
680
 
681
//------------------------------------------+-----------------------------------
682 19 wfjm
//! FIXME_docs
683 17 wfjm
 
684
void RlinkPortCuff::ThunkPollfdAdd(int fd, short events, void* udata)
685
{
686
  RlinkPortCuff* pcntx = (RlinkPortCuff*) udata;
687
  pcntx->PollfdAdd(fd, events);
688
  return;
689
}
690
 
691
//------------------------------------------+-----------------------------------
692 19 wfjm
//! FIXME_docs
693 17 wfjm
 
694
void RlinkPortCuff::ThunkPollfdRemove(int fd, void* udata)
695
{
696
  RlinkPortCuff* pcntx = (RlinkPortCuff*) udata;
697
  pcntx->PollfdRemove(fd);
698
  return;
699
}
700
 
701
//------------------------------------------+-----------------------------------
702 19 wfjm
//! FIXME_docs
703 17 wfjm
 
704
void RlinkPortCuff::ThunkUSBWriteDone(libusb_transfer* t)
705
{
706
  RlinkPortCuff* pcntx = (RlinkPortCuff*) t->user_data;
707
  pcntx->USBWriteDone(t);
708
  return;
709
}
710
 
711
//------------------------------------------+-----------------------------------
712 19 wfjm
//! FIXME_docs
713 17 wfjm
 
714
void RlinkPortCuff::ThunkUSBReadDone(libusb_transfer* t)
715
{
716
  RlinkPortCuff* pcntx = (RlinkPortCuff*) t->user_data;
717
  pcntx->USBReadDone(t);
718
  return;
719
}
720
 
721 19 wfjm
} // end namespace Retro

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.