ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
usb_linux.c File Reference
#include "device.h"
#include "devnode.h"
#include "input.h"
#include "notify.h"
#include "usb.h"
+ Include dependency graph for usb_linux.c:

Go to the source code of this file.

Data Structures

struct  _model
 

Macros

#define DEBUG
 all open usb devices have their system path names here in this array. More...
 
#define TEST_RESET(op)
 TEST_RESET doesa "try / catch" for resetting the usb interface. More...
 
#define N_MODELS   (sizeof(models) / sizeof(_model))
 

Functions

int os_usbsend (usbdevice *kb, const uchar *out_msg, int is_recv, const char *file, int line)
 os_usbsend sends a data packet (MSG_SIZE = 64) Bytes long More...
 
int os_usbrecv (usbdevice *kb, uchar *in_msg, const char *file, int line)
 os_usbrecv receives a max MSGSIZE long buffer from usb device More...
 
int _nk95cmd (usbdevice *kb, uchar bRequest, ushort wValue, const char *file, int line)
 _nk95cmd If we control a non RGB keyboard, set the keyboard via ioctl with usbdevfs_ctrltransfer More...
 
void os_sendindicators (usbdevice *kb)
 
void * os_inputmain (void *context)
 os_inputmain This function is run in a separate thread and will be detached from the main thread, so it needs to clean up its own resources. More...
 
static int usbunclaim (usbdevice *kb, int resetting)
 
void os_closeusb (usbdevice *kb)
 
static int usbclaim (usbdevice *kb)
 
int os_resetusb (usbdevice *kb, const char *file, int line)
 
void strtrim (char *string)
 
int os_setupusb (usbdevice *kb)
 
int usbadd (struct udev_device *dev, short vendor, short product)
 
static int usb_add_device (struct udev_device *dev)
 Add a udev device. Returns 0 if device was recognized/added. More...
 
static void usb_rm_device (struct udev_device *dev)
 usb_rm_device find the usb port to remove and close it via closeusb(). More...
 
static void udev_enum ()
 udev_enum use the udev_enumerate_add_match_subsystem() to get all you need but only that. More...
 
int usbmain ()
 
void usbkill ()
 Stop the USB system. More...
 

Variables

static char kbsyspath [9][FILENAME_MAX]
 
static struct udev * udev
 struct udef is defined in /usr/include/libudev.h More...
 
pthread_t usbthread
 
pthread_t udevthread
 
static _model models []
 

Data Structure Documentation

struct _model

Definition at line 658 of file usb_linux.c.

+ Collaboration diagram for _model:
Data Fields
const char * name
short number

Macro Definition Documentation

#define DEBUG

Definition at line 11 of file usb_linux.c.

#define N_MODELS   (sizeof(models) / sizeof(_model))

Definition at line 700 of file usb_linux.c.

Referenced by usb_add_device().

#define TEST_RESET (   op)
Value:
if(op){ \
ckb_err_fn("resetusb failed: %s\n", file, line, strerror(errno)); \
if(errno == EINTR || errno == EAGAIN) \
return -1; /* try again if status code says so */ \
return -2; /* else, remove device */ \
}
#define ckb_err_fn(fmt, file, line, args...)
Definition: includes.h:48

Definition at line 492 of file usb_linux.c.

Referenced by os_resetusb().

Function Documentation

int _nk95cmd ( usbdevice kb,
uchar  bRequest,
ushort  wValue,
const char *  file,
int  line 
)

To send control packets to a non RGB non color K95 Keyboard, use this function. Normally it is called via the nk95cmd() macro.

If it is the wrong device for which the function is called, 0 is returned and nothing done. Otherwise a usbdevfs_ctrltransfer structure is filled and an USBDEVFS_CONTROL ioctl() called.

bRequestType bRequest wValue EP size Timeout data
0x40 see table below to switch hardware-modus at Keyboard wValue device MSG_SIZE 5ms the message buffer pointer
Host to Device, Type=Vendor, Recipient=Device bRequest parameter given wValue Parameter device 0 0 data to write 5000 null

If a 0 or a negative error number is returned by the ioctl, an error message is shown depending on the errno or "No data written" if retval was 0. In either case 1 is returned to indicate the error. If the ioctl returned a value > 0, 0 is returned to indicate no error.

Currently the following combinations for bRequest and wValue are used:

Device what it might to do constant bRequest wValue
non RGB Keyboard set HW-modus on (leave the ckb driver) HWON 0x0002 0x0030
non RGB Keyboard set HW-modus off (initialize the ckb driver) HWOFF 0x0002 0x0001
non RGB Keyboard set light modus M1 in single-color keyboards NK95_M1 0x0014 0x0001
non RGB Keyboard set light modus M2 in single-color keyboards NK95_M2 0x0014 0x0002
non RGB Keyboard set light modus M3 in single-color keyboards NK95_M3 0x0014 0x0003
See Also
usb.h

Definition at line 189 of file usb_linux.c.

References ckb_err_fn, usbdevice::handle, P_K95_NRGB, and usbdevice::product.

189  {
190  if(kb->product != P_K95_NRGB)
191  return 0;
192  struct usbdevfs_ctrltransfer transfer = { 0x40, bRequest, wValue, 0, 0, 5000, 0 };
193  int res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
194  if(res <= 0){
195  ckb_err_fn("%s\n", file, line, res ? strerror(errno) : "No data written");
196  return 1;
197  }
198  return 0;
199 }
short product
Definition: structures.h:237
#define P_K95_NRGB
Definition: usb.h:79
int handle
Definition: structures.h:187
#define ckb_err_fn(fmt, file, line, args...)
Definition: includes.h:48
void os_closeusb ( usbdevice kb)

os_closeusb unclaim it, destroy the udev device and clear data structures at kb

os_closeusb is the linux specific implementation for closing an active usb port.
If a valid handle is given in the kb structure, the usb port is unclaimed (usbunclaim()).
The device in unrefenced via library function udev_device_unref().
handle, udev and the first char of kbsyspath are cleared to 0 (empty string for kbsyspath).

Definition at line 448 of file usb_linux.c.

References usbdevice::handle, INDEX_OF, kbsyspath, keyboard, usbdevice::udev, and usbunclaim().

Referenced by closeusb().

448  {
449  if(kb->handle){
450  usbunclaim(kb, 0);
451  close(kb->handle - 1);
452  }
453  if(kb->udev)
454  udev_device_unref(kb->udev);
455  kb->handle = 0;
456  kb->udev = 0;
457  kbsyspath[INDEX_OF(kb, keyboard)][0] = 0;
458 }
static char kbsyspath[9][FILENAME_MAX]
Definition: usb_linux.c:13
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
static int usbunclaim(usbdevice *kb, int resetting)
Definition: usb_linux.c:419
struct udev_device * udev
Definition: structures.h:186
#define INDEX_OF(entry, array)
Definition: includes.h:27
int handle
Definition: structures.h:187

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void* os_inputmain ( void *  context)

os_inputmain is run in a separate thread and will be detached from the main thread, so it needs to clean up its own resources.

Todo:
This function is a collection of many tasks. It should be divided into several sub-functions for the sake of greater convenience:
  1. set up an URB (Userspace Ressource Buffer) to communicate with the USBDEVFS_* ioctl()s
  2. perform the ioctl()
  3. interpretate the information got into the URB buffer or handle error situations and retry operation or leave the endless loop
  4. inform the os about the data
  5. loop endless via 2.
  6. if endless loop has gone, deinitalize the interface, free buffers etc.
  7. return null

Here the actions in detail:

Monitor input transfers on all endpoints for non-RGB devices For RGB, monitor all but the last, as it's used for input/output

Get an usbdevfs_urb data structure and clear it via memset()

Hopefully the buffer lengths are equal for all devices with congruent types. You can find out the correctness for your device with lsusb –v or similar on macOS. Currently the following combinations are known and implemented:

device detect with macro combination endpoint # buffer-length
each none 0 8, 64 for FW v3
RGB Mouse IS_RGB && IS_MOUSE 1 10
RGB Keyboard IS_RGB && !IS_MOUSE 1 21
RGB Mouse or Keyboard IS_RGB 2 MSG_SIZE (64)
non RGB Mouse or Keyboard !IS_RGB 1 4
non RGB Mouse or Keyboard !IS_RGB 2 15

Now submit all the URBs via ioctl(USBDEVFS_SUBMITURB) with type USBDEVFS_URB_TYPE_INTERRUPT (the endpoints are defined as type interrupt). Endpoint number is 0x80..0x82 or 0x83, depending on the model.

The userSpaceFS knows the URBs now, so start monitoring input

if the ioctl returns something != 0, let's have a deeper look what happened. Broken devices or shutting down the entire system leads to closing the device and finishing this thread.

If just an EPIPE ocurred, give the device a CLEAR_HALT and resubmit the URB.

A correct REAPURB returns a Pointer to the URB which we now have a closer look into. Lock all following actions with imutex.

Process the input depending on type of device. Interprete the actual size of the URB buffer

device detect with macro combination seems to be endpoint # actual buffer-length function called
mouse (RGB and non RGB) IS_MOUSE nA 8, 10 or 11 hid_mouse_translate()
mouse (RGB and non RGB) IS_MOUSE nA MSG_SIZE (64) corsair_mousecopy()
RGB Keyboard IS_RGB && !IS_MOUSE 1 8 (BIOS Mode) hid_kb_translate()
RGB Keyboard IS_RGB && !IS_MOUSE 2 5 or 21, KB inactive! hid_kb_translate()
RGB Keyboard IS_RGB && !IS_MOUSE 3? MSG_SIZE corsair_kbcopy()
non RGB Keyboard !IS_RGB && !IS_MOUSE nA nA hid_kb_translate()

The input data is transformed and copied to the kb structure. Now give it to the OS and unlock the imutex afterwards.

Re-submit the URB for the next run.

If the endless loop is terminated, clean up by discarding the URBs via ioctl(USBDEVFS_DISCARDURB), free the URB buffers and return a null pointer as thread exit code.

Definition at line 248 of file usb_linux.c.

References usbdevice::active, ckb_err, ckb_info, corsair_kbcopy(), corsair_mousecopy(), devpath, usbdevice::epcount, usbdevice::fwversion, usbdevice::handle, hid_kb_translate(), hid_mouse_translate(), imutex, INDEX_OF, usbdevice::input, inputupdate(), IS_MOUSE, IS_RGB, keyboard, usbinput::keys, MSG_SIZE, usbdevice::product, usbinput::rel_x, usbinput::rel_y, and usbdevice::vendor.

Referenced by _setupusb().

248  {
249  usbdevice* kb = context;
250  int fd = kb->handle - 1;
251  short vendor = kb->vendor, product = kb->product;
252  int index = INDEX_OF(kb, keyboard);
253  ckb_info("Starting input thread for %s%d\n", devpath, index);
254 
259  int urbcount = IS_RGB(vendor, product) ? (kb->epcount - 1) : kb->epcount;
260  if (urbcount == 0) {
261  ckb_err("urbcount = 0, so there is nothing to claim in os_inputmain()\n");
262  return 0;
263  }
264 
266  struct usbdevfs_urb urbs[urbcount + 1];
267  memset(urbs, 0, sizeof(urbs));
268 
282  urbs[0].buffer_length = (kb->fwversion >= 0x300 ? MSG_SIZE : 8);
283  if(urbcount > 1 && IS_RGB(vendor, product)) {
284  if(IS_MOUSE(vendor, product))
285  urbs[1].buffer_length = 10;
286  else
287  urbs[1].buffer_length = 21;
288  urbs[2].buffer_length = MSG_SIZE;
289  if(urbcount != 3)
290  urbs[urbcount - 1].buffer_length = MSG_SIZE;
291  } else if(kb->fwversion < 0x300) {
292  urbs[1].buffer_length = 4;
293  urbs[2].buffer_length = 15;
294  }
295 
298  for(int i = 0; i < urbcount; i++){
299  urbs[i].type = USBDEVFS_URB_TYPE_INTERRUPT;
300  urbs[i].endpoint = 0x80 | (i + 1);
301  urbs[i].buffer = malloc(urbs[i].buffer_length);
302  ioctl(fd, USBDEVFS_SUBMITURB, urbs + i);
303  }
304 
306  while (1) {
307  struct usbdevfs_urb* urb = 0;
308 
311  if (ioctl(fd, USBDEVFS_REAPURB, &urb)) {
312  if (errno == ENODEV || errno == ENOENT || errno == ESHUTDOWN)
313  // Stop the thread if the handle closes
314  break;
315  else if(errno == EPIPE && urb){
317  ioctl(fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
318  // Re-submit the URB
319  if(urb)
320  ioctl(fd, USBDEVFS_SUBMITURB, urb);
321  urb = 0;
322  }
323  continue;
324  }
325 
329  if (urb) {
330 
342  pthread_mutex_lock(imutex(kb));
343  // EP workaround for FWv3
344  // Corsair input comes through 0x81, but case 1 in keymap.c is used for 6KRO
345  uchar urbendpoint = (kb->fwversion >= 0x300 ? 2 : (urb->endpoint & 0xF));
346  if(IS_MOUSE(vendor, product)){
347  switch(urb->actual_length){
348  case 8:
349  case 10:
350  case 11:
351  // HID mouse input
352  hid_mouse_translate(kb->input.keys, &kb->input.rel_x, &kb->input.rel_y, -urbendpoint, urb->actual_length, urb->buffer, kb->fwversion);
353  break;
354  case MSG_SIZE:
355  // Corsair mouse input
356  corsair_mousecopy(kb->input.keys, -urbendpoint, urb->buffer);
357  break;
358  }
359  } else if(IS_RGB(vendor, product)){
360  switch(urb->actual_length){
361  case 8:
362  // RGB EP 1: 6KRO (BIOS mode) input
363  hid_kb_translate(kb->input.keys, -1, urb->actual_length, urb->buffer);
364  break;
365  case 21:
366  case 5:
367  // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive
368  if(!kb->active)
369  hid_kb_translate(kb->input.keys, -2, urb->actual_length, urb->buffer);
370  break;
371  case MSG_SIZE:
372  // RGB EP 3: Corsair input
373  corsair_kbcopy(kb->input.keys, -urbendpoint, urb->buffer);
374  break;
375  }
376  } else {
377  // Non-RGB input
378  hid_kb_translate(kb->input.keys, urb->endpoint & 0xF, urb->actual_length, urb->buffer);
379  }
382  inputupdate(kb);
383  pthread_mutex_unlock(imutex(kb));
384 
386  ioctl(fd, USBDEVFS_SUBMITURB, urb);
387  urb = 0;
388  }
389  }
390 
394  ckb_info("Stopping input thread for %s%d\n", devpath, index);
395  for(int i = 0; i < urbcount; i++){
396  ioctl(fd, USBDEVFS_DISCARDURB, urbs + i);
397  free(urbs[i].buffer);
398  }
399  return 0;
400 }
#define MSG_SIZE
Definition: structures.h:176
usbinput input
Definition: structures.h:245
#define ckb_err(fmt, args...)
Definition: includes.h:49
#define IS_RGB(vendor, product)
RGB vs non-RGB test (note: non-RGB Strafe is still considered "RGB" in that it shares the same protoc...
Definition: usb.h:146
ushort fwversion
Definition: structures.h:239
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
char active
Definition: structures.h:231
int epcount
Definition: structures.h:215
void inputupdate(usbdevice *kb)
Definition: input.c:241
#define IS_MOUSE(vendor, product)
Mouse vs keyboard test.
Definition: usb.h:163
unsigned char uchar
Definition: includes.h:24
QString devpath
Definition: kbmanager.cpp:4
short rel_x
Definition: structures.h:132
void corsair_mousecopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
Definition: keymap.c:429
void hid_mouse_translate(unsigned char *kbinput, short *xaxis, short *yaxis, int endpoint, int length, const unsigned char *urbinput, ushort fwversion)
Definition: keymap.c:391
#define ckb_info(fmt, args...)
Definition: includes.h:55
short product
Definition: structures.h:237
#define INDEX_OF(entry, array)
Definition: includes.h:27
short rel_y
Definition: structures.h:132
#define imutex(kb)
Definition: device.h:22
void hid_kb_translate(unsigned char *kbinput, int endpoint, int length, const unsigned char *urbinput)
Definition: keymap.c:246
int handle
Definition: structures.h:187
void corsair_kbcopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
Definition: keymap.c:420
uchar keys[((((152+22+12)+25)+7)/8)]
Definition: structures.h:130
short vendor
Definition: structures.h:237

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int os_resetusb ( usbdevice kb,
const char *  file,
int  line 
)

os_resetusb is the os specific implementation for resetting usb

Try to reset an usb device in a linux user space driver.

  1. unclaim the device, but do not reconnect the system driver (second param resetting = true)
  2. reset the device via USBDEVFS_RESET command
  3. claim the device again. Returns 0 on success, -2 if device should be removed and -1 if reset should by tried again
Todo:
it seems that no one wants to try the reset again. But I'v seen it somewhere...

Definition at line 510 of file usb_linux.c.

References usbdevice::handle, TEST_RESET, usbclaim(), and usbunclaim().

Referenced by _resetusb().

510  {
511  TEST_RESET(usbunclaim(kb, 1));
512  TEST_RESET(ioctl(kb->handle - 1, USBDEVFS_RESET));
513  TEST_RESET(usbclaim(kb));
514  // Success!
515  return 0;
516 }
#define TEST_RESET(op)
TEST_RESET doesa "try / catch" for resetting the usb interface.
Definition: usb_linux.c:492
static int usbunclaim(usbdevice *kb, int resetting)
Definition: usb_linux.c:419
static int usbclaim(usbdevice *kb)
Definition: usb_linux.c:472
int handle
Definition: structures.h:187

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void os_sendindicators ( usbdevice kb)

os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else?)

os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else?)

Read the data from kb->ileds ans send them via ioctl() to the keyboard.

bRequestType bRequest wValue EP size Timeout data
0x21 0x09 0x0200 Interface 0 MSG_SIZE 1 Byte timeout 0,5ms the message buffer pointer
Host to Device, Type=Class, Recipient=Interface (why not endpoint?) 9 = SEND? specific 0 1 500 struct* kb->ileds


The ioctl command is USBDEVFS_CONTROL.

Definition at line 214 of file usb_linux.c.

References ckb_err, usbdevice::fwversion, usbdevice::handle, usbdevice::ileds, and usb_tryreset().

Referenced by updateindicators_kb().

214  {
215  static int countForReset = 0;
216  void *ileds;
217  ushort leds;
218  if(kb->fwversion >= 0x300) {
219  leds = (kb->ileds << 8) | 0x0001;
220  ileds = &leds;
221  }
222  else {
223  ileds = &kb->ileds;
224  }
225  struct usbdevfs_ctrltransfer transfer = { 0x21, 0x09, 0x0200, 0x00, (kb->fwversion >= 0x300 ? 2 : 1), 500, ileds };
226  int res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
227  if(res <= 0) {
228  ckb_err("%s\n", res ? strerror(errno) : "No data written");
229  if (usb_tryreset(kb) == 0 && countForReset++ < 3) {
230  os_sendindicators(kb);
231  }
232  }
233 }
int usb_tryreset(usbdevice *kb)
Definition: usb.c:475
#define ckb_err(fmt, args...)
Definition: includes.h:49
ushort fwversion
Definition: structures.h:239
void os_sendindicators(usbdevice *kb)
Definition: usb_linux.c:214
uchar ileds
Definition: structures.h:247
unsigned short ushort
Definition: includes.h:25
int handle
Definition: structures.h:187

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int os_setupusb ( usbdevice kb)

os_setupusb OS-specific setup for a specific usb device.

Perform the operating system-specific opening of the interface in os_setupusb(). As a result, some parameters should be set in kb (name, serial, fwversion, epcount = number of usb endpoints), and all endpoints should be claimed with usbclaim(). Claiming is the only point where os_setupusb() can produce an error (-1).

  • Copy device description and serial
  • Copy firmware version (needed to determine USB protocol)
  • Do some output about connecting interfaces
  • Claim the USB interfaces
Todo:
in these modules a pullrequest is outstanding

< Try to reset the device and recall the function

< Don't do this endless in recursion

< os_setupusb() has a return value (used as boolean)

Definition at line 548 of file usb_linux.c.

References ckb_err, ckb_info, devpath, usbdevice::epcount, usbdevice::fwversion, INDEX_OF, KB_NAME_LEN, keyboard, usbdevice::name, usbdevice::serial, SERIAL_LEN, strtrim(), usbdevice::udev, usb_tryreset(), and usbclaim().

Referenced by _setupusb().

548  {
551  struct udev_device* dev = kb->udev;
552  const char* name = udev_device_get_sysattr_value(dev, "product");
553  if(name)
554  strncpy(kb->name, name, KB_NAME_LEN);
555  strtrim(kb->name);
556  const char* serial = udev_device_get_sysattr_value(dev, "serial");
557  if(serial)
558  strncpy(kb->serial, serial, SERIAL_LEN);
559  strtrim(kb->serial);
562  const char* firmware = udev_device_get_sysattr_value(dev, "bcdDevice");
563  if(firmware)
564  sscanf(firmware, "%hx", &kb->fwversion);
565  else
566  kb->fwversion = 0;
567  int index = INDEX_OF(kb, keyboard);
568 
570  ckb_info("Connecting %s at %s%d\n", kb->name, devpath, index);
571 
577  const char* ep_str = udev_device_get_sysattr_value(dev, "bNumInterfaces");
578 #ifdef DEBUG
579  ckb_info("claiming interfaces. name=%s, firmware=%s; ep_str=%s\n", name, firmware, ep_str);
580 #endif //DEBUG
581  kb->epcount = 0;
582  if(ep_str)
583  sscanf(ep_str, "%d", &kb->epcount);
584  if(kb->epcount < 2){
585  // IF we have an RGB KB with 0 or 1 endpoints, it will be in BIOS mode.
586  ckb_err("Unable to read endpoint count from udev, assuming %d and reading >>%s<< or device is in BIOS mode\n", kb->epcount, ep_str);
587  if (usb_tryreset(kb) == 0) {
588  static int retryCount = 0;
589  if (retryCount++ < 5) {
590  return os_setupusb(kb);
591  }
592  }
593  return -1;
594  // ToDo are there special versions we have to detect? If there are, that was the old code to handle it:
595  // This shouldn't happen, but if it does, assume EP count based onckb_warn what the device is supposed to have
596  // kb->epcount = (HAS_FEATURES(kb, FEAT_RGB) ? 4 : 3);
597  // ckb_warn("Unable to read endpoint count from udev, assuming %d and reading >>%s<<...\n", kb->epcount, ep_str);
598  }
599  if(usbclaim(kb)){
600  ckb_err("Failed to claim interfaces: %s\n", strerror(errno));
601  return -1;
602  }
603  return 0;
604 }
#define KB_NAME_LEN
Definition: structures.h:174
int usb_tryreset(usbdevice *kb)
Definition: usb.c:475
char name[40+1]
Definition: structures.h:233
#define ckb_err(fmt, args...)
Definition: includes.h:49
ushort fwversion
Definition: structures.h:239
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
struct udev_device * udev
Definition: structures.h:186
static int usbclaim(usbdevice *kb)
Definition: usb_linux.c:472
int epcount
Definition: structures.h:215
QString devpath
Definition: kbmanager.cpp:4
#define ckb_info(fmt, args...)
Definition: includes.h:55
#define INDEX_OF(entry, array)
Definition: includes.h:27
void strtrim(char *string)
Definition: usb_linux.c:523
char serial[34]
Definition: structures.h:235
int os_setupusb(usbdevice *kb)
Definition: usb_linux.c:548
#define SERIAL_LEN
Definition: structures.h:175

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int os_usbrecv ( usbdevice kb,
uchar in_msg,
const char *  file,
int  line 
)

os_usbrecv does what its name says:

The comment at the beginning of the procedure causes the suspicion that the firmware versionspecific distinction is missing for receiving from usb endpoint 3 or 4. The commented code contains only the reception from EP4, but this may be wrong for a software version 2.0 or higher (see the code for os-usbsend ()).


So all the receiving is done via an ioctl() like in os_usbsend. The ioctl() is given a struct usbdevfs_ctrltransfer, in which the relevant parameters are entered:

bRequestType bRequest wValue EP size Timeout data
0xA1 0x01 0x0200 endpoint to be addressed from epcount - 1 MSG_SIZE 5ms the message buffer pointer
Device to Host, Type=Class, Recipient=Interface 1 = RECEIVE? specific Interface # 64 5000 in_msg

The ioctl() returns the number of bytes received. Here is the usual check again:

  • If the return value is -1 AND the error is a timeout (ETIMEOUT), os_usbrecv() will return -1 to indicate that it is probably a recoverable problem and a retry is recommended.
  • For another negative value or other error identifier OR 0 bytes are received, 0 is returned as an identifier for a heavy error.
  • In all other cases, the function returns the number of bytes received.

If this is not the entire blocksize (MSG_SIZE bytes), an error message is issued on the standard error channel [warning "Read YY bytes (expected 64)"].

Definition at line 130 of file usb_linux.c.

References ckb_err_fn, ckb_warn_fn, usbdevice::epcount, usbdevice::handle, and MSG_SIZE.

Referenced by _usbrecv().

130  {
131  int res;
132  // This is what CUE does, but it doesn't seem to work on linux.
133  /*if(kb->fwversion >= 0x130){
134  struct usbdevfs_bulktransfer transfer = {0};
135  transfer.ep = 0x84;
136  transfer.len = MSG_SIZE;
137  transfer.timeout = 5000;
138  transfer.data = in_msg;
139  res = ioctl(kb->handle - 1, USBDEVFS_BULK, &transfer);
140  } else {*/
141  struct usbdevfs_ctrltransfer transfer = { 0xa1, 0x01, 0x0300, kb->epcount - 1, MSG_SIZE, 5000, in_msg };
142  res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
143  //}
144  if(res <= 0){
145  ckb_err_fn("%s\n", file, line, res ? strerror(errno) : "No data read");
146  if(res == -1 && errno == ETIMEDOUT)
147  return -1;
148  else
149  return 0;
150  } else if(res != MSG_SIZE)
151  ckb_warn_fn("Read %d bytes (expected %d)\n", file, line, res, MSG_SIZE);
152 #ifdef DEBUG_USB_RECV
153  char converted[MSG_SIZE*3 + 1];
154  for(int i=0;i<MSG_SIZE;i++)
155  sprintf(&converted[i*3], "%02x ", in_msg[i]);
156  ckb_warn_fn("Recv %s\n", file, line, converted);
157 #endif
158  return res;
159 }
#define MSG_SIZE
Definition: structures.h:176
int epcount
Definition: structures.h:215
#define ckb_warn_fn(fmt, file, line, args...)
Definition: includes.h:51
int handle
Definition: structures.h:187
#define ckb_err_fn(fmt, file, line, args...)
Definition: includes.h:48

+ Here is the caller graph for this function:

int os_usbsend ( usbdevice kb,
const uchar out_msg,
int  is_recv,
const char *  file,
int  line 
)

os_usbsend has two functions:

  • if is_recv == false, it tries to send a given MSG_SIZE buffer via the usb interface given with kb.
  • otherwise a request is sent via the usb device to initiate the receiving of a message from the remote device.

The functionality for sending distinguishes two cases, depending on the version number of the firmware of the connected device:
If the firmware is less or equal 1.2, the transmission is done via an ioctl(). The ioctl() is given a struct usbdevfs_ctrltransfer, in which the relevant parameters are entered:

bRequestType bRequest wValue EP size Timeout data
0x21 0x09 0x0200 endpoint / IF to be addressed from epcount-1 MSG_SIZE 5000 (=5ms) the message buffer pointer
Host to Device, Type=Class, Recipient=Interface 9 = Send data? specific last or pre-last device # 64 5000 out_msg


The ioctl command is USBDEVFS_CONTROL.

The same constellation is used if the device is requested to send its data (is_recv = true).

For a more recent firmware and is_recv = false, the ioctl command USBDEVFS_CONTROL is not used (this tells the bus to enter the control mode), but the bulk method is used: USBDEVFS_BULK. This is astonishing, because all of the endpoints are type Interrupt, not bulk.

Anyhow, forthis purpose a different structure is used for the ioctl() (struct usbdevfs_bulktransfer) and this is also initialized differently:
The length and timeout parameters are given the same values as above. The formal parameter out_msg is also passed as a buffer pointer. For the endpoints, the firmware version is differentiated again:
For a firmware version between 1.3 and <2.0 endpoint 4 is used, otherwise (it can only be >=2.0) endpoint 3 is used.

Todo:
Since the handling of endpoints has already led to problems elsewhere, this implementation is extremely hardware-dependent and critical!
Eg. the new keyboard K95PLATINUMRGB has a version number significantly less than 2.0 - will it run with this implementation?

The ioctl() - no matter what type - returns the number of bytes sent. Now comes the usual check:

  • If the return value is -1 AND the error is a timeout (ETIMEOUT), os_usbsend() will return -1 to indicate that it is probably a recoverable problem and a retry is recommended.
  • For another negative value or other error identifier OR 0 bytes sent, 0 is returned as a heavy error identifier.
  • In all other cases, the function returns the number of bytes sent.

If this is not the entire blocksize (MSG_SIZE bytes), an error message is issued on the standard error channel [warning "Wrote YY bytes (expected 64)"].

If DEBUG_USB_SEND is set during compilation, the number of bytes sent and their representation are logged to the error channel.

Definition at line 68 of file usb_linux.c.

References ckb_err_fn, ckb_warn_fn, usbdevice::epcount, usbdevice::fwversion, usbdevice::handle, IS_V2_OVERRIDE, and MSG_SIZE.

Referenced by _usbrecv(), and _usbsend().

68  {
69  int res;
70  if ((kb->fwversion >= 0x120 || IS_V2_OVERRIDE(kb)) && !is_recv){
71  struct usbdevfs_bulktransfer transfer = {0};
72  // FW 2.XX uses 0x03, FW 3.XX uses 0x02
73  transfer.ep = (kb->fwversion >= 0x130 && kb->fwversion < 0x200) ? 4 : (kb->fwversion >= 0x300 ? 2 : 3);
74  transfer.len = MSG_SIZE;
75  transfer.timeout = 5000;
76  transfer.data = (void*)out_msg;
77  res = ioctl(kb->handle - 1, USBDEVFS_BULK, &transfer);
78  } else {
79  struct usbdevfs_ctrltransfer transfer = { 0x21, 0x09, 0x0200, kb->epcount - 1, MSG_SIZE, 5000, (void*)out_msg };
80  res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
81  }
82 
83  if (res <= 0){
84  ckb_err_fn(" %s, res = 0x%x\n", file, line, res ? strerror(errno) : "No data written", res);
85  if(res == -1 && errno == ETIMEDOUT)
86  return -1;
87  else
88  return 0;
89  } else if (res != MSG_SIZE)
90  ckb_warn_fn("Wrote %d bytes (expected %d)\n", file, line, res, MSG_SIZE);
91 #ifdef DEBUG_USB_SEND
92  char converted[MSG_SIZE*3 + 1];
93  for(int i=0;i<MSG_SIZE;i++)
94  sprintf(&converted[i*3], "%02x ", out_msg[i]);
95  ckb_warn_fn("Sent %s\n", file, line, converted);
96 #endif
97  return res;
98 }
#define MSG_SIZE
Definition: structures.h:176
ushort fwversion
Definition: structures.h:239
int epcount
Definition: structures.h:215
#define ckb_warn_fn(fmt, file, line, args...)
Definition: includes.h:51
int handle
Definition: structures.h:187
#define ckb_err_fn(fmt, file, line, args...)
Definition: includes.h:48
#define IS_V2_OVERRIDE(kb)
Used when a device has a firmware with a low version number that uses the new protocol.
Definition: usb.h:172

+ Here is the caller graph for this function:

void strtrim ( char *  string)

strtrim trims a string by removing leading and trailing spaces.

Parameters
string

Definition at line 523 of file usb_linux.c.

Referenced by os_setupusb().

523  {
524  // Find last non-space
525  char* last = string;
526  for(char* c = string; *c != 0; c++){
527  if(!isspace(*c))
528  last = c;
529  }
530  last[1] = 0;
531  // Find first non-space
532  char* first = string;
533  for(; *first != 0; first++){
534  if(!isspace(*first))
535  break;
536  }
537  if(first != string)
538  memmove(string, first, last - first);
539 }

+ Here is the caller graph for this function:

static void udev_enum ( )
static

Reduce the hits of the enumeration by limiting to usb as technology and corsair as idVendor. Then filter with udev_enumerate_scan_devices () all hits.

The following call to udev_enumerate_get_list_entry() fetches the entire hitlist as udev_list_entry *.
Use udev_list_entry_foreach() to iterate through the hit set.
If both the device name exists (udev_list_entry_get_name) and the subsequent creation of a new udev_device (udev_device_new_from_syspath) is ok, the new device is added to the list with usb_add_device().

If the latter does not work, the new device is released again (udev_device_unref ()).
After the last iteration, the enumerator is released with udev_enumerate_unref ().

Definition at line 765 of file usb_linux.c.

References usb_add_device(), and V_CORSAIR_STR.

Referenced by usbmain().

765  {
766  struct udev_enumerate* enumerator = udev_enumerate_new(udev);
767  udev_enumerate_add_match_subsystem(enumerator, "usb");
768  udev_enumerate_add_match_sysattr(enumerator, "idVendor", V_CORSAIR_STR);
769  udev_enumerate_scan_devices(enumerator);
770  struct udev_list_entry* devices, *dev_list_entry;
771  devices = udev_enumerate_get_list_entry(enumerator);
772 
773  udev_list_entry_foreach(dev_list_entry, devices){
774  const char* path = udev_list_entry_get_name(dev_list_entry);
775  if(!path)
776  continue;
777  struct udev_device* dev = udev_device_new_from_syspath(udev, path);
778  if(!dev)
779  continue;
780  // If the device matches a recognized device ID, open it
781  if(usb_add_device(dev))
782  // Release device if not
783  udev_device_unref(dev);
784  }
785  udev_enumerate_unref(enumerator);
786 }
#define V_CORSAIR_STR
Definition: usb.h:43
static int usb_add_device(struct udev_device *dev)
Add a udev device. Returns 0 if device was recognized/added.
Definition: usb_linux.c:713
static struct udev * udev
struct udef is defined in /usr/include/libudev.h
Definition: usb_linux.c:652

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int usb_add_device ( struct udev_device *  dev)
static

If the device id can be found, call usbadd() with the appropriate parameters.

Parameters
devthe functions usb_*_device get a struct udev* with the neccessary hardware-related information.
Returns
the retval of usbadd() or 1 if either vendor is not corsair or product is not mentioned in model[].

First get the idVendor via udev_device_get_sysattr_value(). If this is equal to the ID-string of corsair ("1b1c"), get the idProduct on the same way.
If we can find the model name in the model array, call usbadd() with the model number.

Todo:
So why the hell not a transformation between the string and the short presentation? Lets check if the string representation is used elsewhere.

Definition at line 713 of file usb_linux.c.

References N_MODELS, usbadd(), V_CORSAIR, and V_CORSAIR_STR.

Referenced by udev_enum(), and usbmain().

713  {
714  const char* vendor = udev_device_get_sysattr_value(dev, "idVendor");
715  if(vendor && !strcmp(vendor, V_CORSAIR_STR)){
716  const char* product = udev_device_get_sysattr_value(dev, "idProduct");
717  if(product){
718  for(_model* model = models; model < models + N_MODELS; model++){
719  if(!strcmp(product, model->name)){
720  return usbadd(dev, V_CORSAIR, model->number);
721  }
722  }
723  }
724  }
725  return 1;
726 }
int usbadd(struct udev_device *dev, short vendor, short product)
Definition: usb_linux.c:606
#define N_MODELS
Definition: usb_linux.c:700
static _model models[]
Definition: usb_linux.c:668
#define V_CORSAIR_STR
Definition: usb.h:43
#define V_CORSAIR
For the following Defines please see "Detailed Description".
Definition: usb.h:42

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void usb_rm_device ( struct udev_device *  dev)
static
Parameters
devthe functions usb_*_device get a struct udev* with the neccessary hardware-related information.

First try to find the system path of the device given in parameter dev. The index where the name is found is the same index we need to address the global keyboard array. That array holds all usbdevices.
Searching for the correct name in kbsyspath-array and closing the usb via closeusb() are protected by lock..unlock of the corresponding devmutex arraymember.

Definition at line 738 of file usb_linux.c.

References closeusb(), DEV_MAX, devmutex, kbsyspath, and keyboard.

Referenced by usbmain().

738  {
739  // Device removed. Look for it in our list of keyboards
740  const char* syspath = udev_device_get_syspath(dev);
741  if(!syspath || syspath[0] == 0)
742  return;
743  for(int i = 1; i < DEV_MAX; i++){
744  pthread_mutex_lock(devmutex + i);
745  if(!strcmp(syspath, kbsyspath[i]))
746  closeusb(keyboard + i);
747  pthread_mutex_unlock(devmutex + i);
748  }
749 }
static char kbsyspath[9][FILENAME_MAX]
Definition: usb_linux.c:13
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
pthread_mutex_t devmutex[9]
Mutex for handling the usbdevice structure.
Definition: device.c:12
int closeusb(usbdevice *kb)
Definition: usb.c:687
#define DEV_MAX
Definition: device.h:8

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int usbadd ( struct udev_device *  dev,
short  vendor,
short  product 
)

Definition at line 606 of file usb_linux.c.

References ckb_err, ckb_info, DEV_MAX, dmutex, usbdevice::handle, IS_CONNECTED, kbsyspath, keyboard, usbdevice::product, setupusb(), usbdevice::udev, and usbdevice::vendor.

Referenced by usb_add_device().

606  {
607  const char* path = udev_device_get_devnode(dev);
608  const char* syspath = udev_device_get_syspath(dev);
609  if(!path || !syspath || path[0] == 0 || syspath[0] == 0){
610  ckb_err("Failed to get device path\n");
611  return -1;
612  }
613 #ifdef DEBUG
614  ckb_info(">>>vendor = 0x%x, product = 0x%x, path = %s, syspath = %s\n", vendor, product, path, syspath);
615 #endif // DEDBUG
616  // Find a free USB slot
617  for(int index = 1; index < DEV_MAX; index++){
618  usbdevice* kb = keyboard + index;
619  if(pthread_mutex_trylock(dmutex(kb))){
620  // If the mutex is locked then the device is obviously in use, so keep going
621  if(!strcmp(syspath, kbsyspath[index])){
622  // Make sure this existing keyboard doesn't have the same syspath (this shouldn't happen)
623  return 0;
624  }
625  continue;
626  }
627  if(!IS_CONNECTED(kb)){
628  // Open the sysfs device
629  kb->handle = open(path, O_RDWR) + 1;
630  if(kb->handle <= 0){
631  ckb_err("Failed to open USB device: %s\n", strerror(errno));
632  kb->handle = 0;
633  pthread_mutex_unlock(dmutex(kb));
634  return -1;
635  } else {
636  // Set up device
637  kb->udev = dev;
638  kb->vendor = vendor;
639  kb->product = product;
640  strncpy(kbsyspath[index], syspath, FILENAME_MAX);
641  // Mutex remains locked
642  setupusb(kb);
643  return 0;
644  }
645  }
646  pthread_mutex_unlock(dmutex(kb));
647  }
648  ckb_err("No free devices\n");
649  return -1;
650 }
static char kbsyspath[9][FILENAME_MAX]
Definition: usb_linux.c:13
void setupusb(usbdevice *kb)
Definition: usb.c:396
#define IS_CONNECTED(kb)
Definition: device.h:12
#define ckb_err(fmt, args...)
Definition: includes.h:49
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
struct udev_device * udev
Definition: structures.h:186
#define ckb_info(fmt, args...)
Definition: includes.h:55
short product
Definition: structures.h:237
int handle
Definition: structures.h:187
#define DEV_MAX
Definition: device.h:8
#define dmutex(kb)
Definition: device.h:18
short vendor
Definition: structures.h:237

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int usbclaim ( usbdevice kb)
static

usbclaim does claiming all EPs for the usb device gicen by kb.

Parameters
kbTHE usbdevice*
Returns
0 on success, -1 otherwise.

Claim all endpoints for a given device (remeber the decrementing of the file descriptor) via ioctl(USBDEVFS_DISCONNECT) and ioctl(USBDEVFS_CLAIMINTERFACE).

Error handling is done for the ioctl(USBDEVFS_CLAIMINTERFACE) only. If this fails, now an error message is thrown and -1 is returned. Function is called in usb_linux.c only, so it is declared as static now.

Definition at line 472 of file usb_linux.c.

References ckb_err, ckb_info, usbdevice::epcount, and usbdevice::handle.

Referenced by os_resetusb(), and os_setupusb().

472  {
473  int count = kb->epcount;
474 #ifdef DEBUG
475  ckb_info("claiming %d endpoints\n", count);
476 #endif // DEBUG
477 
478  for(int i = 0; i < count; i++){
479  struct usbdevfs_ioctl ctl = { i, USBDEVFS_DISCONNECT, 0 };
480  ioctl(kb->handle - 1, USBDEVFS_IOCTL, &ctl);
481  if(ioctl(kb->handle - 1, USBDEVFS_CLAIMINTERFACE, &i)) {
482  ckb_err("Failed to claim interface %d: %s\n", i, strerror(errno));
483  return -1;
484  }
485  }
486  return 0;
487 }
#define ckb_err(fmt, args...)
Definition: includes.h:49
int epcount
Definition: structures.h:215
#define ckb_info(fmt, args...)
Definition: includes.h:55
int handle
Definition: structures.h:187

+ Here is the caller graph for this function:

void usbkill ( )

Definition at line 853 of file usb_linux.c.

Referenced by quitWithLock().

853  {
854  udev_unref(udev);
855  udev = 0;
856 }
static struct udev * udev
struct udef is defined in /usr/include/libudev.h
Definition: usb_linux.c:652

+ Here is the caller graph for this function:

int usbmain ( )

Start the USB main loop. Returns program exit code when finished.

usbmain is called by main() after setting up all other stuff.

Returns
0 normally or -1 if fatal error occurs (up to now only if no new devices are available)

First check whether the uinput module is loaded by the kernel.

Todo:
Why isn't missing of uinput a fatal error?

Create the udev object with udev_new() (is a function from libudev.h) terminate -1 if error

Enumerate all currently connected devices

Todo:
lae. here the work has to go on...

Definition at line 793 of file usb_linux.c.

References ckb_fatal, ckb_warn, udev_enum(), usb_add_device(), and usb_rm_device().

Referenced by main().

793  {
798  // Load the uinput module (if it's not loaded already)
799  if(system("modprobe uinput") != 0)
800  ckb_warn("Failed to load uinput module\n");
801 
805  if(!(udev = udev_new())) {
806  ckb_fatal("Failed to initialize udev in usbmain(), usb_linux.c\n");
807  return -1;
808  }
809 
812  udev_enum();
813 
816  // Done scanning. Enter a loop to poll for device updates
817  struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
818  udev_monitor_filter_add_match_subsystem_devtype(monitor, "usb", 0);
819  udev_monitor_enable_receiving(monitor);
820  // Get an fd for the monitor
821  int fd = udev_monitor_get_fd(monitor);
822  fd_set fds;
823  while(udev){
824  FD_ZERO(&fds);
825  FD_SET(fd, &fds);
826  // Block until an event is read
827  if(select(fd + 1, &fds, 0, 0, 0) > 0 && FD_ISSET(fd, &fds)){
828  struct udev_device* dev = udev_monitor_receive_device(monitor);
829  if(!dev)
830  continue;
831  const char* action = udev_device_get_action(dev);
832  if(!action){
833  udev_device_unref(dev);
834  continue;
835  }
836  // Add/remove device
837  if(!strcmp(action, "add")){
838  int res = usb_add_device(dev);
839  if(res == 0)
840  continue;
841  // If the device matched but the handle wasn't opened correctly, re-enumerate (this sometimes solves the problem)
842  if(res == -1)
843  udev_enum();
844  } else if(!strcmp(action, "remove"))
845  usb_rm_device(dev);
846  udev_device_unref(dev);
847  }
848  }
849  udev_monitor_unref(monitor);
850  return 0;
851 }
#define ckb_fatal(fmt, args...)
Definition: includes.h:46
static void usb_rm_device(struct udev_device *dev)
usb_rm_device find the usb port to remove and close it via closeusb().
Definition: usb_linux.c:738
#define ckb_warn(fmt, args...)
Definition: includes.h:52
static void udev_enum()
udev_enum use the udev_enumerate_add_match_subsystem() to get all you need but only that...
Definition: usb_linux.c:765
static int usb_add_device(struct udev_device *dev)
Add a udev device. Returns 0 if device was recognized/added.
Definition: usb_linux.c:713
static struct udev * udev
struct udef is defined in /usr/include/libudev.h
Definition: usb_linux.c:652

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int usbunclaim ( usbdevice kb,
int  resetting 
)
static

usbunclaim do an unclaiming of the usb device gicen by kb.

Parameters
kbTHE usbdevice*
resettingboolean flag: If resseting is true, the caller will perform a bus reset command after unclaiming the device.
Returns
always 0.

Unclaim all endpoints for a given device (remeber the decrementing of the file descriptor) via ioctl(USBDEVFS_DISCARDURB).

Afterwards - if ressetting is false - do a USBDEVFS_CONNECT for EP 0 and 1. If it is a non RGB device, connect EP 2 also. The comment mentions RGB keyboards only, but as I understand the code, this is valid also for RGB mice.

There is no error handling yet. Function is called in usb_linux.c only, so it is declared as static now.

Definition at line 419 of file usb_linux.c.

References usbdevice::epcount, FEAT_RGB, usbdevice::handle, and HAS_FEATURES.

Referenced by os_closeusb(), and os_resetusb().

419  {
420  int handle = kb->handle - 1;
421  int count = kb->epcount;
422  for (int i = 0; i < count; i++) {
423  ioctl(handle, USBDEVFS_RELEASEINTERFACE, &i);
424  }
425  // For RGB keyboards, the kernel driver should only be reconnected to interfaces 0 and 1 (HID), and only if we're not about to do a USB reset.
426  // Reconnecting any of the others causes trouble.
427  if (!resetting) {
428  struct usbdevfs_ioctl ctl = { 0, USBDEVFS_CONNECT, 0 };
429  ioctl(handle, USBDEVFS_IOCTL, &ctl);
430  ctl.ifno = 1;
431  ioctl(handle, USBDEVFS_IOCTL, &ctl);
432  // Also reconnect iface #2 (HID) for non-RGB keyboards
433  if(!HAS_FEATURES(kb, FEAT_RGB)){
434  ctl.ifno = 2;
435  ioctl(handle, USBDEVFS_IOCTL, &ctl);
436  }
437  }
438  return 0;
439 }
#define FEAT_RGB
Definition: structures.h:136
int epcount
Definition: structures.h:215
int handle
Definition: structures.h:187
#define HAS_FEATURES(kb, feat)
Definition: structures.h:157

+ Here is the caller graph for this function:

Variable Documentation

char kbsyspath[9][FILENAME_MAX]
static

Definition at line 13 of file usb_linux.c.

Referenced by os_closeusb(), usb_rm_device(), and usbadd().

_model models[]
static
Attention
when adding new hardware this file hat to be changed too.

In this structure array models[] for each device the name (the device id as string in hex without leading 0x) and its usb device id as short must be entered in this array.

Definition at line 668 of file usb_linux.c.

struct udev* udev
static

Definition at line 652 of file usb_linux.c.

pthread_t udevthread

Definition at line 655 of file usb_linux.c.

pthread_t usbthread
Todo:
These two thread vasriables seem to be unused: usbtread, udevthread

Definition at line 655 of file usb_linux.c.