ckb-next  beta-v0.2.8 at branch testing
ckb-next driver for corsair devices
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator 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 645 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 682 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 479 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 188 of file usb_linux.c.

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

188  {
189  if(kb->product != P_K95_NRGB)
190  return 0;
191  struct usbdevfs_ctrltransfer transfer = { 0x40, bRequest, wValue, 0, 0, 5000, 0 };
192  int res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
193  if(res <= 0){
194  ckb_err_fn("%s\n", file, line, res ? strerror(errno) : "No data written");
195  return 1;
196  }
197  return 0;
198 }
short product
Definition: structures.h:237
#define P_K95_NRGB
Definition: usb.h:67
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 435 of file usb_linux.c.

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

Referenced by closeusb().

435  {
436  if(kb->handle){
437  usbunclaim(kb, 0);
438  close(kb->handle - 1);
439  }
440  if(kb->udev)
441  udev_device_unref(kb->udev);
442  kb->handle = 0;
443  kb->udev = 0;
444  kbsyspath[INDEX_OF(kb, keyboard)][0] = 0;
445 }
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:406
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
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 238 of file usb_linux.c.

References usbdevice::active, ckb_err, ckb_info, corsair_kbcopy(), corsair_mousecopy(), devpath, usbdevice::epcount, 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().

238  {
239  usbdevice* kb = context;
240  int fd = kb->handle - 1;
241  short vendor = kb->vendor, product = kb->product;
242  int index = INDEX_OF(kb, keyboard);
243  ckb_info("Starting input thread for %s%d\n", devpath, index);
244 
249  int urbcount = IS_RGB(vendor, product) ? (kb->epcount - 1) : kb->epcount;
250  if (urbcount == 0) {
251  ckb_err("urbcount = 0, so there is nothing to claim in os_inputmain()\n");
252  return 0;
253  }
254 
256  struct usbdevfs_urb urbs[urbcount + 1];
257  memset(urbs, 0, sizeof(urbs));
258 
272  urbs[0].buffer_length = 8;
273  if(urbcount > 1 && IS_RGB(vendor, product)) {
274  if(IS_MOUSE(vendor, product))
275  urbs[1].buffer_length = 10;
276  else
277  urbs[1].buffer_length = 21;
278  urbs[2].buffer_length = MSG_SIZE;
279  if(urbcount != 3)
280  urbs[urbcount - 1].buffer_length = MSG_SIZE;
281  } else {
282  urbs[1].buffer_length = 4;
283  urbs[2].buffer_length = 15;
284  }
285 
288  for(int i = 0; i < urbcount; i++){
289  urbs[i].type = USBDEVFS_URB_TYPE_INTERRUPT;
290  urbs[i].endpoint = 0x80 | (i + 1);
291  urbs[i].buffer = malloc(urbs[i].buffer_length);
292  ioctl(fd, USBDEVFS_SUBMITURB, urbs + i);
293  }
294 
296  while (1) {
297  struct usbdevfs_urb* urb = 0;
298 
301  if (ioctl(fd, USBDEVFS_REAPURB, &urb)) {
302  if (errno == ENODEV || errno == ENOENT || errno == ESHUTDOWN)
303  // Stop the thread if the handle closes
304  break;
305  else if(errno == EPIPE && urb){
307  ioctl(fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
308  // Re-submit the URB
309  if(urb)
310  ioctl(fd, USBDEVFS_SUBMITURB, urb);
311  urb = 0;
312  }
313  continue;
314  }
315 
319  if (urb) {
320 
332  pthread_mutex_lock(imutex(kb));
333  if(IS_MOUSE(vendor, product)){
334  switch(urb->actual_length){
335  case 8:
336  case 10:
337  case 11:
338  // HID mouse input
339  hid_mouse_translate(kb->input.keys, &kb->input.rel_x, &kb->input.rel_y, -(urb->endpoint & 0xF), urb->actual_length, urb->buffer);
340  break;
341  case MSG_SIZE:
342  // Corsair mouse input
343  corsair_mousecopy(kb->input.keys, -(urb->endpoint & 0xF), urb->buffer);
344  break;
345  }
346  } else if(IS_RGB(vendor, product)){
347  switch(urb->actual_length){
348  case 8:
349  // RGB EP 1: 6KRO (BIOS mode) input
350  hid_kb_translate(kb->input.keys, -1, urb->actual_length, urb->buffer);
351  break;
352  case 21:
353  case 5:
354  // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive
355  if(!kb->active)
356  hid_kb_translate(kb->input.keys, -2, urb->actual_length, urb->buffer);
357  break;
358  case MSG_SIZE:
359  // RGB EP 3: Corsair input
360  corsair_kbcopy(kb->input.keys, -(urb->endpoint & 0xF), urb->buffer);
361  break;
362  }
363  } else {
364  // Non-RGB input
365  hid_kb_translate(kb->input.keys, urb->endpoint & 0xF, urb->actual_length, urb->buffer);
366  }
369  inputupdate(kb);
370  pthread_mutex_unlock(imutex(kb));
371 
373  ioctl(fd, USBDEVFS_SUBMITURB, urb);
374  urb = 0;
375  }
376  }
377 
381  ckb_info("Stopping input thread for %s%d\n", devpath, index);
382  for(int i = 0; i < urbcount; i++){
383  ioctl(fd, USBDEVFS_DISCARDURB, urbs + i);
384  free(urbs[i].buffer);
385  }
386  return 0;
387 }
#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:124
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
uchar keys[((((152+3+12)+25)+7)/8)]
Definition: structures.h:130
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:141
short rel_x
Definition: structures.h:132
void hid_mouse_translate(unsigned char *kbinput, short *xaxis, short *yaxis, int endpoint, int length, const unsigned char *urbinput)
Definition: keymap.c:366
void corsair_mousecopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
Definition: keymap.c:403
const char *const devpath
Definition: devnode.c:11
#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:223
int handle
Definition: structures.h:187
void corsair_kbcopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
Definition: keymap.c:394
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 497 of file usb_linux.c.

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

Referenced by _resetusb().

497  {
498  TEST_RESET(usbunclaim(kb, 1));
499  TEST_RESET(ioctl(kb->handle - 1, USBDEVFS_RESET));
500  TEST_RESET(usbclaim(kb));
501  // Success!
502  return 0;
503 }
#define TEST_RESET(op)
TEST_RESET doesa "try / catch" for resetting the usb interface.
Definition: usb_linux.c:479
static int usbunclaim(usbdevice *kb, int resetting)
Definition: usb_linux.c:406
static int usbclaim(usbdevice *kb)
Definition: usb_linux.c:459
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 213 of file usb_linux.c.

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

Referenced by updateindicators_kb().

213  {
214  static int countForReset = 0;
215  struct usbdevfs_ctrltransfer transfer = { 0x21, 0x09, 0x0200, 0x00, 1, 500, &kb->ileds };
216  int res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
217  if(res <= 0) {
218  ckb_err("%s\n", res ? strerror(errno) : "No data written");
219  if (usb_tryreset(kb) == 0 && countForReset++ < 3) {
220  os_sendindicators(kb);
221  }
222  }
223 }
int usb_tryreset(usbdevice *kb)
Definition: usb.c:465
#define ckb_err(fmt, args...)
Definition: includes.h:49
void os_sendindicators(usbdevice *kb)
Definition: usb_linux.c:213
uchar ileds
Definition: structures.h:247
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 535 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().

535  {
538  struct udev_device* dev = kb->udev;
539  const char* name = udev_device_get_sysattr_value(dev, "product");
540  if(name)
541  strncpy(kb->name, name, KB_NAME_LEN);
542  strtrim(kb->name);
543  const char* serial = udev_device_get_sysattr_value(dev, "serial");
544  if(serial)
545  strncpy(kb->serial, serial, SERIAL_LEN);
546  strtrim(kb->serial);
549  const char* firmware = udev_device_get_sysattr_value(dev, "bcdDevice");
550  if(firmware)
551  sscanf(firmware, "%hx", &kb->fwversion);
552  else
553  kb->fwversion = 0;
554  int index = INDEX_OF(kb, keyboard);
555 
557  ckb_info("Connecting %s at %s%d\n", kb->name, devpath, index);
558 
564  const char* ep_str = udev_device_get_sysattr_value(dev, "bNumInterfaces");
565 #ifdef DEBUG
566  ckb_info("claiming interfaces. name=%s, firmware=%s; Got >>%s<< as ep_str\n", name, firmware, ep_str);
567 #endif //DEBUG
568  kb->epcount = 0;
569  if(ep_str)
570  sscanf(ep_str, "%d", &kb->epcount);
571  if(kb->epcount < 2){
572  // IF we have an RGB KB with 0 or 1 endpoints, it will be in BIOS mode.
573  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);
574  if (usb_tryreset(kb) == 0) {
575  static int retryCount = 0;
576  if (retryCount++ < 5) {
577  return os_setupusb(kb);
578  }
579  }
580  return -1;
581  // ToDo are there special versions we have to detect? If there are, that was the old code to handle it:
582  // This shouldn't happen, but if it does, assume EP count based onckb_warn what the device is supposed to have
583  // kb->epcount = (HAS_FEATURES(kb, FEAT_RGB) ? 4 : 3);
584  // ckb_warn("Unable to read endpoint count from udev, assuming %d and reading >>%s<<...\n", kb->epcount, ep_str);
585  }
586  if(usbclaim(kb)){
587  ckb_err("Failed to claim interfaces: %s\n", strerror(errno));
588  return -1;
589  }
590  return 0;
591 }
#define KB_NAME_LEN
Definition: structures.h:174
int usb_tryreset(usbdevice *kb)
Definition: usb.c:465
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:459
int epcount
Definition: structures.h:215
const char *const devpath
Definition: devnode.c:11
#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:510
char serial[34]
Definition: structures.h:235
int os_setupusb(usbdevice *kb)
Definition: usb_linux.c:535
#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 129 of file usb_linux.c.

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

Referenced by _usbrecv().

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

Referenced by _usbrecv(), and _usbsend().

68  {
69  int res;
70  if (kb->fwversion >= 0x120 && !is_recv) {
71  struct usbdevfs_bulktransfer transfer = {0};
72  transfer.ep = (kb->fwversion >= 0x130 && kb->fwversion < 0x200) ? 4 : 3;
73  transfer.len = MSG_SIZE;
74  transfer.timeout = 5000;
75  transfer.data = (void*)out_msg;
76  res = ioctl(kb->handle - 1, USBDEVFS_BULK, &transfer);
77  } else {
78  struct usbdevfs_ctrltransfer transfer = { 0x21, 0x09, 0x0200, kb->epcount - 1, MSG_SIZE, 5000, (void*)out_msg };
79  res = ioctl(kb->handle - 1, USBDEVFS_CONTROL, &transfer);
80  }
81 
82  if (res <= 0){
83  ckb_err_fn(" %s, res = 0x%x\n", file, line, res ? strerror(errno) : "No data written", res);
84  if(res == -1 && errno == ETIMEDOUT)
85  return -1;
86  else
87  return 0;
88  } else if (res != MSG_SIZE)
89  ckb_warn_fn("Wrote %d bytes (expected %d)\n", file, line, res, MSG_SIZE);
90 #ifdef DEBUG_USB
91  char converted[MSG_SIZE*3 + 1];
92  for(int i=0;i<MSG_SIZE;i++)
93  sprintf(&converted[i*3], "%02x ", out_msg[i]);
94  ckb_warn_fn("Sent %s\n", file, line, converted);
95 #endif
96  return res;
97 }
#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

+ 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 510 of file usb_linux.c.

Referenced by os_setupusb().

510  {
511  // Find last non-space
512  char* last = string;
513  for(char* c = string; *c != 0; c++){
514  if(!isspace(*c))
515  last = c;
516  }
517  last[1] = 0;
518  // Find first non-space
519  char* first = string;
520  for(; *first != 0; first++){
521  if(!isspace(*first))
522  break;
523  }
524  if(first != string)
525  memmove(string, first, last - first);
526 }

+ 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 747 of file usb_linux.c.

References usb_add_device(), and V_CORSAIR_STR.

Referenced by usbmain().

747  {
748  struct udev_enumerate* enumerator = udev_enumerate_new(udev);
749  udev_enumerate_add_match_subsystem(enumerator, "usb");
750  udev_enumerate_add_match_sysattr(enumerator, "idVendor", V_CORSAIR_STR);
751  udev_enumerate_scan_devices(enumerator);
752  struct udev_list_entry* devices, *dev_list_entry;
753  devices = udev_enumerate_get_list_entry(enumerator);
754 
755  udev_list_entry_foreach(dev_list_entry, devices){
756  const char* path = udev_list_entry_get_name(dev_list_entry);
757  if(!path)
758  continue;
759  struct udev_device* dev = udev_device_new_from_syspath(udev, path);
760  if(!dev)
761  continue;
762  // If the device matches a recognized device ID, open it
763  if(usb_add_device(dev))
764  // Release device if not
765  udev_device_unref(dev);
766  }
767  udev_enumerate_unref(enumerator);
768 }
#define V_CORSAIR_STR
Definition: usb.h:39
static int usb_add_device(struct udev_device *dev)
Add a udev device. Returns 0 if device was recognized/added.
Definition: usb_linux.c:695
static struct udev * udev
struct udef is defined in /usr/include/libudev.h
Definition: usb_linux.c:639

+ 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 695 of file usb_linux.c.

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

Referenced by udev_enum(), and usbmain().

695  {
696  const char* vendor = udev_device_get_sysattr_value(dev, "idVendor");
697  if(vendor && !strcmp(vendor, V_CORSAIR_STR)){
698  const char* product = udev_device_get_sysattr_value(dev, "idProduct");
699  if(product){
700  for(_model* model = models; model < models + N_MODELS; model++){
701  if(!strcmp(product, model->name)){
702  return usbadd(dev, V_CORSAIR, model->number);
703  }
704  }
705  }
706  }
707  return 1;
708 }
int usbadd(struct udev_device *dev, short vendor, short product)
Definition: usb_linux.c:593
#define N_MODELS
Definition: usb_linux.c:682
static _model models[]
Definition: usb_linux.c:655
#define V_CORSAIR_STR
Definition: usb.h:39
#define V_CORSAIR
For the following Defines please see "Detailed Description".
Definition: usb.h:38

+ 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 720 of file usb_linux.c.

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

Referenced by usbmain().

720  {
721  // Device removed. Look for it in our list of keyboards
722  const char* syspath = udev_device_get_syspath(dev);
723  if(!syspath || syspath[0] == 0)
724  return;
725  for(int i = 1; i < DEV_MAX; i++){
726  pthread_mutex_lock(devmutex + i);
727  if(!strcmp(syspath, kbsyspath[i]))
728  closeusb(keyboard + i);
729  pthread_mutex_unlock(devmutex + i);
730  }
731 }
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:677
#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 593 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().

593  {
594  const char* path = udev_device_get_devnode(dev);
595  const char* syspath = udev_device_get_syspath(dev);
596  if(!path || !syspath || path[0] == 0 || syspath[0] == 0){
597  ckb_err("Failed to get device path\n");
598  return -1;
599  }
600 #ifdef DEBUG
601  ckb_info(">>>vendor = 0x%x, product = 0x%x, path = %s, syspath = %s\n", vendor, product, path, syspath);
602 #endif // DEDBUG
603  // Find a free USB slot
604  for(int index = 1; index < DEV_MAX; index++){
605  usbdevice* kb = keyboard + index;
606  if(pthread_mutex_trylock(dmutex(kb))){
607  // If the mutex is locked then the device is obviously in use, so keep going
608  if(!strcmp(syspath, kbsyspath[index])){
609  // Make sure this existing keyboard doesn't have the same syspath (this shouldn't happen)
610  return 0;
611  }
612  continue;
613  }
614  if(!IS_CONNECTED(kb)){
615  // Open the sysfs device
616  kb->handle = open(path, O_RDWR) + 1;
617  if(kb->handle <= 0){
618  ckb_err("Failed to open USB device: %s\n", strerror(errno));
619  kb->handle = 0;
620  pthread_mutex_unlock(dmutex(kb));
621  return -1;
622  } else {
623  // Set up device
624  kb->udev = dev;
625  kb->vendor = vendor;
626  kb->product = product;
627  strncpy(kbsyspath[index], syspath, FILENAME_MAX);
628  // Mutex remains locked
629  setupusb(kb);
630  return 0;
631  }
632  }
633  pthread_mutex_unlock(dmutex(kb));
634  }
635  ckb_err("No free devices\n");
636  return -1;
637 }
static char kbsyspath[9][FILENAME_MAX]
Definition: usb_linux.c:13
void setupusb(usbdevice *kb)
Definition: usb.c:386
#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 459 of file usb_linux.c.

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

Referenced by os_resetusb(), and os_setupusb().

459  {
460  int count = kb->epcount;
461 #ifdef DEBUG
462  ckb_info("claiming %d endpoints\n", count);
463 #endif // DEBUG
464 
465  for(int i = 0; i < count; i++){
466  struct usbdevfs_ioctl ctl = { i, USBDEVFS_DISCONNECT, 0 };
467  ioctl(kb->handle - 1, USBDEVFS_IOCTL, &ctl);
468  if(ioctl(kb->handle - 1, USBDEVFS_CLAIMINTERFACE, &i)) {
469  ckb_err("Failed to claim interface %d: %s\n", i, strerror(errno));
470  return -1;
471  }
472  }
473  return 0;
474 }
#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 835 of file usb_linux.c.

Referenced by quitWithLock().

835  {
836  udev_unref(udev);
837  udev = 0;
838 }
static struct udev * udev
struct udef is defined in /usr/include/libudev.h
Definition: usb_linux.c:639

+ 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 775 of file usb_linux.c.

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

Referenced by main().

775  {
780  // Load the uinput module (if it's not loaded already)
781  if(system("modprobe uinput") != 0)
782  ckb_warn("Failed to load uinput module\n");
783 
787  if(!(udev = udev_new())) {
788  ckb_fatal("Failed to initialize udev in usbmain(), usb_linux.c\n");
789  return -1;
790  }
791 
794  udev_enum();
795 
798  // Done scanning. Enter a loop to poll for device updates
799  struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
800  udev_monitor_filter_add_match_subsystem_devtype(monitor, "usb", 0);
801  udev_monitor_enable_receiving(monitor);
802  // Get an fd for the monitor
803  int fd = udev_monitor_get_fd(monitor);
804  fd_set fds;
805  while(udev){
806  FD_ZERO(&fds);
807  FD_SET(fd, &fds);
808  // Block until an event is read
809  if(select(fd + 1, &fds, 0, 0, 0) > 0 && FD_ISSET(fd, &fds)){
810  struct udev_device* dev = udev_monitor_receive_device(monitor);
811  if(!dev)
812  continue;
813  const char* action = udev_device_get_action(dev);
814  if(!action){
815  udev_device_unref(dev);
816  continue;
817  }
818  // Add/remove device
819  if(!strcmp(action, "add")){
820  int res = usb_add_device(dev);
821  if(res == 0)
822  continue;
823  // If the device matched but the handle wasn't opened correctly, re-enumerate (this sometimes solves the problem)
824  if(res == -1)
825  udev_enum();
826  } else if(!strcmp(action, "remove"))
827  usb_rm_device(dev);
828  udev_device_unref(dev);
829  }
830  }
831  udev_monitor_unref(monitor);
832  return 0;
833 }
#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:720
#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:747
static int usb_add_device(struct udev_device *dev)
Add a udev device. Returns 0 if device was recognized/added.
Definition: usb_linux.c:695
static struct udev * udev
struct udef is defined in /usr/include/libudev.h
Definition: usb_linux.c:639

+ 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 406 of file usb_linux.c.

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

Referenced by os_closeusb(), and os_resetusb().

406  {
407  int handle = kb->handle - 1;
408  int count = kb->epcount;
409  for (int i = 0; i < count; i++) {
410  ioctl(handle, USBDEVFS_RELEASEINTERFACE, &i);
411  }
412  // 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.
413  // Reconnecting any of the others causes trouble.
414  if (!resetting) {
415  struct usbdevfs_ioctl ctl = { 0, USBDEVFS_CONNECT, 0 };
416  ioctl(handle, USBDEVFS_IOCTL, &ctl);
417  ctl.ifno = 1;
418  ioctl(handle, USBDEVFS_IOCTL, &ctl);
419  // Also reconnect iface #2 (HID) for non-RGB keyboards
420  if(!HAS_FEATURES(kb, FEAT_RGB)){
421  ctl.ifno = 2;
422  ioctl(handle, USBDEVFS_IOCTL, &ctl);
423  }
424  }
425  return 0;
426 }
#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
Initial value:
= {
{ "1b17" , 0x1b17 },
{ "1b07" , 0x1b07 },
{ "1b37" , 0x1b37 },
{ "1b39" , 0x1b39 },
{ "1b13" , 0x1b13 },
{ "1b09" , 0x1b09 },
{ "1b33" , 0x1b33 },
{ "1b36" , 0x1b36 },
{ "1b38" , 0x1b38 },
{ "1b3a" , 0x1b3a },
{ "1b11" , 0x1b11 },
{ "1b08" , 0x1b08 },
{ "1b2d" , 0x1b2d },
{ "1b20" , 0x1b20 },
{ "1b15" , 0x1b15 },
{ "1b12" , 0x1b12 },
{ "1b2e" , 0x1b2e },
{ "1b14" , 0x1b14 },
{ "1b19" , 0x1b19 },
{ "1b2f" , 0x1b2f },
{ "1b1e" , 0x1b1e },
{ "1b3e" , 0x1b3e },
{ "1b32" , 0x1b32 }
}
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 655 of file usb_linux.c.

struct udev* udev
static

Definition at line 639 of file usb_linux.c.

pthread_t udevthread

Definition at line 642 of file usb_linux.c.

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

Definition at line 642 of file usb_linux.c.