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.h File Reference

Definitions for using USB interface. More...

#include "includes.h"
#include "keymap.h"
+ Include dependency graph for usb.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define V_CORSAIR   0x1b1c
 For the following Defines please see "Detailed Description". More...
 
#define V_CORSAIR_STR   "1b1c"
 
#define P_K63_NRGB   0x1b40
 
#define P_K63_NRGB_STR   "1b40"
 
#define IS_K63(kb)   ((kb)->vendor == V_CORSAIR && (kb)->product == P_K63_NRGB)
 
#define P_K65   0x1b17
 
#define P_K65_STR   "1b17"
 
#define P_K65_NRGB   0x1b07
 
#define P_K65_NRGB_STR   "1b07"
 
#define P_K65_LUX   0x1b37
 
#define P_K65_LUX_STR   "1b37"
 
#define P_K65_RFIRE   0x1b39
 
#define P_K65_RFIRE_STR   "1b39"
 
#define IS_K65(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K65 || (kb)->product == P_K65_NRGB || (kb)->product == P_K65_LUX || (kb)->product == P_K65_RFIRE))
 
#define P_K68   0x1b3f
 
#define P_K68_STR   "1b3f"
 
#define IS_K68(kb)   ((kb)->vendor == V_CORSAIR && (kb)->product == P_K68)
 
#define P_K70   0x1b13
 
#define P_K70_STR   "1b13"
 
#define P_K70_NRGB   0x1b09
 
#define P_K70_NRGB_STR   "1b09"
 
#define P_K70_LUX   0x1b33
 
#define P_K70_LUX_STR   "1b33"
 
#define P_K70_LUX_NRGB   0x1b36
 
#define P_K70_LUX_NRGB_STR   "1b36"
 
#define P_K70_RFIRE   0x1b38
 
#define P_K70_RFIRE_STR   "1b38"
 
#define P_K70_RFIRE_NRGB   0x1b3a
 
#define P_K70_RFIRE_NRGB_STR   "1b3a"
 
#define IS_K70(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K70 || (kb)->product == P_K70_NRGB || (kb)->product == P_K70_RFIRE || (kb)->product == P_K70_RFIRE_NRGB || (kb)->product == P_K70_LUX || (kb)->product == P_K70_LUX_NRGB))
 
#define P_K95   0x1b11
 
#define P_K95_STR   "1b11"
 
#define P_K95_NRGB   0x1b08
 
#define P_K95_NRGB_STR   "1b08"
 
#define P_K95_PLATINUM   0x1b2d
 
#define P_K95_PLATINUM_STR   "1b2d"
 
#define IS_K95(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K95 || (kb)->product == P_K95_NRGB || (kb)->product == P_K95_PLATINUM))
 
#define P_STRAFE   0x1b20
 
#define P_STRAFE_STR   "1b20"
 
#define P_STRAFE_NRGB   0x1b15
 
#define P_STRAFE_NRGB_STR   "1b15"
 
#define P_STRAFE_NRGB_2   0x1b44
 
#define P_STRAFE_NRGB_2_STR   "1b44"
 
#define IS_STRAFE(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_STRAFE || (kb)->product == P_STRAFE_NRGB || (kb)->product == P_STRAFE_NRGB_2))
 
#define P_M65   0x1b12
 
#define P_M65_STR   "1b12"
 
#define P_M65_PRO   0x1b2e
 
#define P_M65_PRO_STR   "1b2e"
 
#define IS_M65(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_M65 || (kb)->product == P_M65_PRO))
 
#define P_SABRE_O   0x1b14 /* optical */
 
#define P_SABRE_O_STR   "1b14"
 
#define P_SABRE_L   0x1b19 /* laser */
 
#define P_SABRE_L_STR   "1b19"
 
#define P_SABRE_N   0x1b2f /* new? */
 
#define P_SABRE_N_STR   "1b2f"
 
#define P_SABRE_O2   0x1b32 /* Observed on a CH-9000111-EU model SABRE */
 
#define P_SABRE_O2_STR   "1b32"
 
#define IS_SABRE(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_SABRE_O || (kb)->product == P_SABRE_L || (kb)->product == P_SABRE_N || (kb)->product == P_SABRE_O2))
 
#define P_SCIMITAR   0x1b1e
 
#define P_SCIMITAR_STR   "1b1e"
 
#define P_SCIMITAR_PRO   0x1b3e
 
#define P_SCIMITAR_PRO_STR   "1b3e"
 
#define IS_SCIMITAR(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_SCIMITAR || (kb)->product == P_SCIMITAR_PRO))
 
#define P_HARPOON   0x1b3c
 
#define P_HARPOON_STR   "1b3c"
 
#define IS_HARPOON(kb)   ((kb)->vendor == V_CORSAIR && (kb)->product == P_HARPOON)
 
#define P_GLAIVE   0x1b34
 
#define P_GLAIVE_STR   "1b34"
 
#define IS_GLAIVE(kb)   ((kb)->vendor == V_CORSAIR && (kb)->product == P_GLAIVE)
 
#define IS_RGB(vendor, product)   ((vendor) == (V_CORSAIR) && (product) != (P_K65_NRGB) && (product) != (P_K70_NRGB) && (product) != (P_K95_NRGB))
 RGB vs non-RGB test (note: non-RGB Strafe is still considered "RGB" in that it shares the same protocol. The difference is denoted with the "monochrome" feature). More...
 
#define IS_MONOCHROME(vendor, product)   ((vendor) == (V_CORSAIR) && ((product) == (P_K68) || (product) == (P_STRAFE_NRGB) || (product) == (P_STRAFE_NRGB_2)))
 The difference between non RGB and monochrome is, that monochrome has lights, but just in one color. nonRGB has no lights. Change this if new monochrome devices are added. More...
 
#define IS_RGB_DEV(kb)   IS_RGB((kb)->vendor, (kb)->product)
 For calling with a usbdevice*, vendor and product are extracted and IS_RGB() is returned. More...
 
#define IS_MONOCHROME_DEV(kb)   IS_MONOCHROME((kb)->vendor, (kb)->product)
 For calling with a usbdevice*, vendor and product are extracted and IS_MONOCHROME() is returned. More...
 
#define IS_FULLRANGE(kb)   (IS_RGB((kb)->vendor, (kb)->product) && (kb)->product != P_K65 && (kb)->product != P_K70 && (kb)->product != P_K95)
 Full color range (16.8M) vs partial color range (512) More...
 
#define IS_MOUSE(vendor, product)   ((vendor) == (V_CORSAIR) && ((product) == (P_M65) || (product) == (P_M65_PRO) || (product) == (P_SABRE_O) || (product) == (P_SABRE_L) || (product) == (P_SABRE_N) || (product) == (P_SCIMITAR) || (product) == (P_SCIMITAR_PRO) || (product) == (P_SABRE_O2) || (product) == (P_GLAIVE) || (product) == (P_HARPOON)))
 Mouse vs keyboard test. More...
 
#define IS_MOUSE_DEV(kb)   IS_MOUSE((kb)->vendor, (kb)->product)
 For calling with a usbdevice*, vendor and product are extracted and IS_MOUSE() is returned. More...
 
#define IS_PLATINUM(kb)   ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K95_PLATINUM))
 Used to apply quirks and features to the PLATINUM devices. More...
 
#define IS_V2_OVERRIDE(kb)   (IS_PLATINUM(kb) || IS_K63(kb) || IS_K68(kb) || IS_HARPOON(kb) || IS_GLAIVE(kb) || (kb)->product == P_STRAFE_NRGB_2)
 Used when a device has a firmware with a low version number that uses the new protocol. More...
 
#define DELAY_SHORT(kb)   clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = ((int) (kb->usbdelay)) * 1000000}, NULL)
 USB delays for when the keyboards get picky about timing That was the original comment, but it is used anytime. More...
 
#define DELAY_MEDIUM(kb)   clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = ((int) (kb->usbdelay)) * 10000000}, NULL)
 the medium delay is used after sending a command before waiting for the answer. More...
 
#define DELAY_LONG(kb)   clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 100000000}, NULL)
 The longest delay takes place where something went wrong (eg when resetting the device) More...
 
#define USB_DELAY_DEFAULT   5
 This constant is used to initialize kb->usbdelay. It is used in many places (see macros above) but often also overwritten to the fixed value of 10. Pure Hacker code. More...
 
#define resetusb(kb)   _resetusb(kb, __FILE_NOPATH__, __LINE__)
 resetusb() is just a macro to call _resetusb() with debuggin constants (file, lineno) More...
 
#define usbsend(kb, messages, count)   _usbsend(kb, messages, count, __FILE_NOPATH__, __LINE__)
 usbsend macro is used to wrap _usbsend() with debugging information (file and lineno) More...
 
#define usbrecv(kb, out_msg, in_msg)   _usbrecv(kb, out_msg, in_msg, __FILE_NOPATH__, __LINE__)
 usbrecv macro is used to wrap _usbrecv() with debugging information (file and lineno) More...
 
#define nk95cmd(kb, command)   _nk95cmd(kb, (command) >> 16 & 0xFF, (command) & 0xFFFF, __FILE_NOPATH__, __LINE__)
 nk95cmd() macro is used to wrap _nk95cmd() with debugging information (file and lineno). the command structure is different:
Just the bits 23..16 are used as bits 7..0 for bRequest
Bits 15..0 are used as wValue More...
 
#define NK95_HWOFF   0x020030
 Hardware-specific commands for the K95 nonRGB,. More...
 
#define NK95_HWON   0x020001
 Hardware playback on. More...
 
#define NK95_M1   0x140001
 Switch to mode 1. More...
 
#define NK95_M2   0x140002
 Switch to mode 2. More...
 
#define NK95_M3   0x140003
 Switch to mode 3. More...
 

Functions

const char * vendor_str (short vendor)
 uncomment to see USB packets sent to the device More...
 
const char * product_str (short product)
 product_str returns a condensed view on what type of device we have. More...
 
int usbmain ()
 Start the USB main loop. Returns program exit code when finished. More...
 
void usbkill ()
 Stop the USB system. More...
 
void setupusb (usbdevice *kb)
 setupusb starts a thread with kb as parameter and _setupusb() as entrypoint. More...
 
int os_setupusb (usbdevice *kb)
 os_setupusb OS-specific setup for a specific usb device. More...
 
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. More...
 
int revertusb (usbdevice *kb)
 revertusb sets a given device to inactive (hardware controlled) mode if not a fw-ugrade is indicated More...
 
int closeusb (usbdevice *kb)
 closeusb Close a USB device and remove device entry. More...
 
void os_closeusb (usbdevice *kb)
 os_closeusb unclaim it, destroy the udev device and clear data structures at kb More...
 
int _resetusb (usbdevice *kb, const char *file, int line)
 _resetusb Reset a USB device. More...
 
int os_resetusb (usbdevice *kb, const char *file, int line)
 os_resetusb is the os specific implementation for resetting usb More...
 
int _usbsend (usbdevice *kb, const uchar *messages, int count, const char *file, int line)
 _usbsend send a logical message completely to the given device More...
 
int _usbrecv (usbdevice *kb, const uchar *out_msg, uchar *in_msg, const char *file, int line)
 _usbrecv Request data from a USB device by first sending an output packet and then reading the response. More...
 
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...
 
void os_sendindicators (usbdevice *kb)
 os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else?) 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...
 
int usb_tryreset (usbdevice *kb)
 usb_tryreset does what the name means: Try to reset the usb via resetusb() More...
 

Detailed Description

Vendor/product codes

The list of defines in the first part of the file describes the various types of equipment from Corsair and summarizes them according to specific characteristics.
Each device type is described with two defines:

  • On the one hand the device ID with which the device can be recognized on the USB as a short
  • and on the other hand the same representation as a string, but without leading "0x".

First entry-pair is the Provider ID (vendorID) from Corsair.

Block No. | contains | Devices are bundled via ------— | -----— | --------------------— 1 | The first block contains the K63 Non RGB Keyboard. No other K63 is known so far. 2 | the K65-like keyboards, regardless of their properties (RGB, ...). | In summary, they can be queried using the macro IS_K65(). 3 | K68 keyboard | IS_K68(). 4 | the K70-like Keyboards with all their configuration types | summarized by IS_K70(). 5 | the K95 series keyboards | collected with the macro IS_K95(). 6 | strafe keyboards | IS_STRAFE() 7 | M65 mice with and without RGB | IS_M65() 8 | Sabre mice | IS_SABRE() 9 | Scimitar mice | IS_SCIMITAR() 10| Harpoon mice | IS_HARPOON() 11| Glaive mice | IS_GLAIVE()

Definition in file usb.h.

Macro Definition Documentation

#define DELAY_LONG (   kb)    clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 100000000}, NULL)
#define DELAY_MEDIUM (   kb)    clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = ((int) (kb->usbdelay)) * 10000000}, NULL)

Definition at line 182 of file usb.h.

Referenced by _usbrecv(), and setactive_kb().

#define DELAY_SHORT (   kb)    clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = ((int) (kb->usbdelay)) * 1000000}, NULL)

The short delay is used before any send or receive

Definition at line 178 of file usb.h.

Referenced by _usbrecv(), _usbsend(), and updateindicators_kb().

#define IS_FULLRANGE (   kb)    (IS_RGB((kb)->vendor, (kb)->product) && (kb)->product != P_K65 && (kb)->product != P_K70 && (kb)->product != P_K95)

Definition at line 160 of file usb.h.

Referenced by readcmd(), and updatergb_kb().

#define IS_GLAIVE (   kb)    ((kb)->vendor == V_CORSAIR && (kb)->product == P_GLAIVE)

Definition at line 121 of file usb.h.

Referenced by updatergb_mouse().

#define IS_HARPOON (   kb)    ((kb)->vendor == V_CORSAIR && (kb)->product == P_HARPOON)

Definition at line 117 of file usb.h.

#define IS_K63 (   kb)    ((kb)->vendor == V_CORSAIR && (kb)->product == P_K63_NRGB)

Definition at line 47 of file usb.h.

Referenced by has_key().

#define IS_K65 (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K65 || (kb)->product == P_K65_NRGB || (kb)->product == P_K65_LUX || (kb)->product == P_K65_RFIRE))

Definition at line 57 of file usb.h.

Referenced by has_key().

#define IS_K68 (   kb)    ((kb)->vendor == V_CORSAIR && (kb)->product == P_K68)

Definition at line 61 of file usb.h.

#define IS_K70 (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K70 || (kb)->product == P_K70_NRGB || (kb)->product == P_K70_RFIRE || (kb)->product == P_K70_RFIRE_NRGB || (kb)->product == P_K70_LUX || (kb)->product == P_K70_LUX_NRGB))

Definition at line 75 of file usb.h.

#define IS_K95 (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K95 || (kb)->product == P_K95_NRGB || (kb)->product == P_K95_PLATINUM))

Definition at line 83 of file usb.h.

Referenced by cmd_hwload_kb(), cmd_hwsave_kb(), and has_key().

#define IS_M65 (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_M65 || (kb)->product == P_M65_PRO))

Definition at line 97 of file usb.h.

Referenced by isblack().

#define IS_MONOCHROME (   vendor,
  product 
)    ((vendor) == (V_CORSAIR) && ((product) == (P_K68) || (product) == (P_STRAFE_NRGB) || (product) == (P_STRAFE_NRGB_2)))

Definition at line 151 of file usb.h.

Referenced by _setupusb().

#define IS_MONOCHROME_DEV (   kb)    IS_MONOCHROME((kb)->vendor, (kb)->product)

Definition at line 157 of file usb.h.

#define IS_MOUSE (   vendor,
  product 
)    ((vendor) == (V_CORSAIR) && ((product) == (P_M65) || (product) == (P_M65_PRO) || (product) == (P_SABRE_O) || (product) == (P_SABRE_L) || (product) == (P_SABRE_N) || (product) == (P_SCIMITAR) || (product) == (P_SCIMITAR_PRO) || (product) == (P_SABRE_O2) || (product) == (P_GLAIVE) || (product) == (P_HARPOON)))

Definition at line 163 of file usb.h.

Referenced by _setupusb(), get_vtable(), has_key(), and os_inputmain().

#define IS_MOUSE_DEV (   kb)    IS_MOUSE((kb)->vendor, (kb)->product)

Definition at line 166 of file usb.h.

Referenced by readcmd().

#define IS_PLATINUM (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K95_PLATINUM))

Definition at line 169 of file usb.h.

#define IS_RGB (   vendor,
  product 
)    ((vendor) == (V_CORSAIR) && (product) != (P_K65_NRGB) && (product) != (P_K70_NRGB) && (product) != (P_K95_NRGB))

Definition at line 146 of file usb.h.

Referenced by _setupusb(), get_vtable(), and os_inputmain().

#define IS_RGB_DEV (   kb)    IS_RGB((kb)->vendor, (kb)->product)

Definition at line 154 of file usb.h.

#define IS_SABRE (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_SABRE_O || (kb)->product == P_SABRE_L || (kb)->product == P_SABRE_N || (kb)->product == P_SABRE_O2))

Definition at line 107 of file usb.h.

Referenced by has_key(), loadrgb_mouse(), and savergb_mouse().

#define IS_SCIMITAR (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_SCIMITAR || (kb)->product == P_SCIMITAR_PRO))

Definition at line 113 of file usb.h.

Referenced by has_key(), loadrgb_mouse(), and savergb_mouse().

#define IS_STRAFE (   kb)    ((kb)->vendor == V_CORSAIR && ((kb)->product == P_STRAFE || (kb)->product == P_STRAFE_NRGB || (kb)->product == P_STRAFE_NRGB_2))

Definition at line 91 of file usb.h.

Referenced by savergb_kb().

#define IS_V2_OVERRIDE (   kb)    (IS_PLATINUM(kb) || IS_K63(kb) || IS_K68(kb) || IS_HARPOON(kb) || IS_GLAIVE(kb) || (kb)->product == P_STRAFE_NRGB_2)

Definition at line 172 of file usb.h.

Referenced by loadrgb_kb(), os_usbsend(), and savergb_kb().

#define NK95_HWOFF   0x020030
See Also
usb2.0 documentation for details. Set Hardware playback off

Definition at line 333 of file usb.h.

Referenced by start_kb_nrgb().

#define NK95_HWON   0x020001

Definition at line 336 of file usb.h.

Referenced by revertusb().

#define NK95_M1   0x140001

Definition at line 339 of file usb.h.

Referenced by setmodeindex_nrgb().

#define NK95_M2   0x140002

Definition at line 342 of file usb.h.

Referenced by setmodeindex_nrgb().

#define NK95_M3   0x140003

Definition at line 345 of file usb.h.

Referenced by setmodeindex_nrgb().

#define nk95cmd (   kb,
  command 
)    _nk95cmd(kb, (command) >> 16 & 0xFF, (command) & 0xFFFF, __FILE_NOPATH__, __LINE__)

Definition at line 328 of file usb.h.

Referenced by revertusb(), setmodeindex_nrgb(), and start_kb_nrgb().

#define P_GLAIVE   0x1b34

Definition at line 119 of file usb.h.

Referenced by product_str().

#define P_GLAIVE_STR   "1b34"

Definition at line 120 of file usb.h.

#define P_HARPOON   0x1b3c

Definition at line 115 of file usb.h.

Referenced by product_str().

#define P_HARPOON_STR   "1b3c"

Definition at line 116 of file usb.h.

#define P_K63_NRGB   0x1b40

Definition at line 45 of file usb.h.

Referenced by product_str().

#define P_K63_NRGB_STR   "1b40"

Definition at line 46 of file usb.h.

#define P_K65   0x1b17

Definition at line 49 of file usb.h.

Referenced by product_str().

#define P_K65_LUX   0x1b37

Definition at line 53 of file usb.h.

Referenced by product_str().

#define P_K65_LUX_STR   "1b37"

Definition at line 54 of file usb.h.

#define P_K65_NRGB   0x1b07

Definition at line 51 of file usb.h.

Referenced by product_str().

#define P_K65_NRGB_STR   "1b07"

Definition at line 52 of file usb.h.

#define P_K65_RFIRE   0x1b39

Definition at line 55 of file usb.h.

Referenced by product_str().

#define P_K65_RFIRE_STR   "1b39"

Definition at line 56 of file usb.h.

#define P_K65_STR   "1b17"

Definition at line 50 of file usb.h.

#define P_K68   0x1b3f

Definition at line 59 of file usb.h.

Referenced by product_str().

#define P_K68_STR   "1b3f"

Definition at line 60 of file usb.h.

#define P_K70   0x1b13

Definition at line 63 of file usb.h.

Referenced by product_str().

#define P_K70_LUX   0x1b33

Definition at line 67 of file usb.h.

Referenced by loadrgb_kb(), and product_str().

#define P_K70_LUX_NRGB   0x1b36

Definition at line 69 of file usb.h.

Referenced by loadrgb_kb(), and product_str().

#define P_K70_LUX_NRGB_STR   "1b36"

Definition at line 70 of file usb.h.

#define P_K70_LUX_STR   "1b33"

Definition at line 68 of file usb.h.

#define P_K70_NRGB   0x1b09

Definition at line 65 of file usb.h.

Referenced by product_str().

#define P_K70_NRGB_STR   "1b09"

Definition at line 66 of file usb.h.

#define P_K70_RFIRE   0x1b38

Definition at line 71 of file usb.h.

Referenced by product_str().

#define P_K70_RFIRE_NRGB   0x1b3a

Definition at line 73 of file usb.h.

Referenced by product_str().

#define P_K70_RFIRE_NRGB_STR   "1b3a"

Definition at line 74 of file usb.h.

#define P_K70_RFIRE_STR   "1b38"

Definition at line 72 of file usb.h.

#define P_K70_STR   "1b13"

Definition at line 64 of file usb.h.

#define P_K95   0x1b11

Definition at line 77 of file usb.h.

Referenced by product_str().

#define P_K95_NRGB   0x1b08

Definition at line 79 of file usb.h.

Referenced by _nk95cmd(), and product_str().

#define P_K95_NRGB_STR   "1b08"

Definition at line 80 of file usb.h.

#define P_K95_PLATINUM   0x1b2d

Definition at line 81 of file usb.h.

Referenced by product_str(), and updatergb_kb().

#define P_K95_PLATINUM_STR   "1b2d"

Definition at line 82 of file usb.h.

#define P_K95_STR   "1b11"

Definition at line 78 of file usb.h.

#define P_M65   0x1b12

Definition at line 93 of file usb.h.

Referenced by product_str().

#define P_M65_PRO   0x1b2e

Definition at line 95 of file usb.h.

Referenced by product_str().

#define P_M65_PRO_STR   "1b2e"

Definition at line 96 of file usb.h.

#define P_M65_STR   "1b12"

Definition at line 94 of file usb.h.

#define P_SABRE_L   0x1b19 /* laser */

Definition at line 101 of file usb.h.

Referenced by product_str().

#define P_SABRE_L_STR   "1b19"

Definition at line 102 of file usb.h.

#define P_SABRE_N   0x1b2f /* new? */

Definition at line 103 of file usb.h.

Referenced by product_str().

#define P_SABRE_N_STR   "1b2f"

Definition at line 104 of file usb.h.

#define P_SABRE_O   0x1b14 /* optical */

Definition at line 99 of file usb.h.

Referenced by product_str().

#define P_SABRE_O2   0x1b32 /* Observed on a CH-9000111-EU model SABRE */

Definition at line 105 of file usb.h.

Referenced by product_str().

#define P_SABRE_O2_STR   "1b32"

Definition at line 106 of file usb.h.

#define P_SABRE_O_STR   "1b14"

Definition at line 100 of file usb.h.

#define P_SCIMITAR   0x1b1e

Definition at line 109 of file usb.h.

Referenced by product_str().

#define P_SCIMITAR_PRO   0x1b3e

Definition at line 111 of file usb.h.

Referenced by product_str().

#define P_SCIMITAR_PRO_STR   "1b3e"

Definition at line 112 of file usb.h.

#define P_SCIMITAR_STR   "1b1e"

Definition at line 110 of file usb.h.

#define P_STRAFE   0x1b20

Definition at line 85 of file usb.h.

Referenced by product_str().

#define P_STRAFE_NRGB   0x1b15

Definition at line 87 of file usb.h.

Referenced by product_str().

#define P_STRAFE_NRGB_2   0x1b44

Definition at line 89 of file usb.h.

Referenced by product_str().

#define P_STRAFE_NRGB_2_STR   "1b44"

Definition at line 90 of file usb.h.

#define P_STRAFE_NRGB_STR   "1b15"

Definition at line 88 of file usb.h.

#define P_STRAFE_STR   "1b20"

Definition at line 86 of file usb.h.

#define resetusb (   kb)    _resetusb(kb, __FILE_NOPATH__, __LINE__)

Definition at line 246 of file usb.h.

Referenced by usb_tryreset().

#define USB_DELAY_DEFAULT   5

Definition at line 192 of file usb.h.

Referenced by _setupusb(), and start_dev().

#define usbrecv (   kb,
  out_msg,
  in_msg 
)    _usbrecv(kb, out_msg, in_msg, __FILE_NOPATH__, __LINE__)
Parameters
kbTHE usbdevice*
IN]out_msg What information does the caller want from the device?
OUT]in_msg Here comes the answer; The names represent the usb view, not the view of this function! So INput from usb is OUTput of this function.

Definition at line 288 of file usb.h.

Referenced by cmd_hwload_kb(), cmd_hwload_mouse(), getfwversion(), hwloadmode(), loaddpi(), loadrgb_kb(), and loadrgb_mouse().

#define usbsend (   kb,
  messages,
  count 
)    _usbsend(kb, messages, count, __FILE_NOPATH__, __LINE__)
Parameters
kbTHE usbdevice*
IN]messages a Pointer to the first byte of the logical message
IN]count how many MSG_SIZE buffers is the logical message long?

Definition at line 271 of file usb.h.

Referenced by cmd_hwsave_kb(), cmd_hwsave_mouse(), cmd_pollrate(), fwupdate(), loadrgb_kb(), savedpi(), savergb_kb(), savergb_mouse(), setactive_kb(), setactive_mouse(), updatedpi(), updatergb_kb(), and updatergb_mouse().

#define V_CORSAIR   0x1b1c
Warning
When adding new devices please update src/ckb/fwupgradedialog.cpp as well.
It should contain the same vendor/product IDs for any devices supporting firmware updates.
In the same way, all other corresponding files have to be supplemented or modified: Currently known for this are usb_linux.c and usb_mac.c

Definition at line 42 of file usb.h.

Referenced by usb_add_device(), and vendor_str().

#define V_CORSAIR_STR   "1b1c"

Definition at line 43 of file usb.h.

Referenced by udev_enum(), and usb_add_device().

Function Documentation

int _nk95cmd ( usbdevice kb,
uchar  bRequest,
ushort  wValue,
const char *  file,
int  line 
)
Parameters
kbTHE usbdevice*
bRequestthe byte array with the usb request
wValuea usb wValue
filefor error message
linefor error message
Returns
1 (true) on failure, 0 (false) on success.

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
int _resetusb ( usbdevice kb,
const char *  file,
int  line 
)
Parameters
kbTHE usbdevice*
filefilename for error messages
lineline where it is called for error messages
Returns
Returns 0 on success, -1 if device should be removed

_resetusb Reset a USB device.

First reset the device via os_resetusb() after a long delay (it may send something to the host). If this worked (retval == 0), give the device another long delay Then perform the initialization via the device specific start() function entry in kb->vtable and if this is successful also, return the result of the device depenten updatergb() with force=true.

Definition at line 436 of file usb.c.

References usbdevice::active, DELAY_LONG, os_resetusb(), and usbdevice::vtable.

436  {
437  // Perform a USB reset
438  DELAY_LONG(kb);
439  int res = os_resetusb(kb, file, line);
440  if(res)
441  return res;
442  DELAY_LONG(kb);
443  // Re-initialize the device
444  if(kb->vtable->start(kb, kb->active) != 0)
445  return -1;
446  if(kb->vtable->updatergb(kb, 1) != 0)
447  return -1;
448  return 0;
449 }
#define DELAY_LONG(kb)
The longest delay takes place where something went wrong (eg when resetting the device) ...
Definition: usb.h:186
int os_resetusb(usbdevice *kb, const char *file, int line)
os_resetusb is the os specific implementation for resetting usb
Definition: usb_linux.c:510
char active
Definition: structures.h:231
const union devcmd * vtable
Definition: structures.h:180

+ Here is the call graph for this function:

int _usbrecv ( usbdevice kb,
const uchar out_msg,
uchar in_msg,
const char *  file,
int  line 
)
Parameters
kbTHE usbdevice*
IN]out_msg What information does the caller want from the device?
OUT]in_msg Here comes the answer; The names represent the usb view, not the view of this function! So INput from usb is OUTput of this function.
IN]file for debugging
IN]line for debugging
IN]reset_stop global variable is read
Returns
number of bytes read or zero on failure.

_usbrecv Request data from a USB device by first sending an output packet and then reading the response.

To fully understand this, you need to know about usb: All control is at the usb host (the CPU). If the device wants to communicate something to the host, it must wait for the host to ask. The usb protocol defines the cycles and periods in which actions are to be taken.

So in order to receive a data packet from the device, the host must first send a send request.
This is done by _usbrecv() in the first block by sending the MSG_SIZE large data block from out_msg via os_usbsend() as it is a machine depending implementation. The usb target device is as always determined over kb.

For os_usbsend() to know that it is a receive request, the is_recv parameter is set to true (1). With this, os_usbsend () generates a control package for the hardware, not a data packet.

If sending of the control package is not successful, a maximum of 5 times the transmission is repeated (including the first attempt). If a non-cancelable error is signaled or the drive is stopped via reset_stop, _usbrecv() immediately returns 0.

After this, the function waits for the requested response from the device using os_usbrecv ().

os_usbrecv() returns 0, -1 or something else.
Zero signals a serious error which is not treatable and _usbrecv() also returns 0.
-1 means that it is a treatable error - a timeout for example - and therefore the next transfer attempt is started after a long pause (DELAY_LONG) if not reset_stop or the wrong hwload_mode require a termination with a return value of 0.

After 5 attempts, _usbrecv () returns and returns 0 as well as an error message.

When data is received, the number of received bytes is returned. This should always be MSG_SIZE, but os_usbrecv() can also return less. It should not be more, because then there would be an unhandled buffer overflow, but it could be less. This would be signaled in os_usbrecv () with a message.

The buffers behind out_msg and in_msg are MSG_SIZE at least (currently 64 Bytes). More is ok but useless, less brings unpredictable behavior.

< Synchonization between macro and color information

Definition at line 611 of file usb.c.

References ckb_err_fn, DELAY_LONG, DELAY_MEDIUM, DELAY_SHORT, hwload_mode, mmutex, os_usbrecv(), os_usbsend(), and reset_stop.

611  {
612  // Try a maximum of 5 times
613  for (int try = 0; try < 5; try++) {
614  // Send the output message
615  pthread_mutex_lock(mmutex(kb));
616  DELAY_SHORT(kb);
617  int res = os_usbsend(kb, out_msg, 1, file, line);
618  pthread_mutex_unlock(mmutex(kb));
619  if (res == 0)
620  return 0;
621  else if (res == -1) {
622  // Retry on temporary failure
623  if (reset_stop)
624  return 0;
625  DELAY_LONG(kb);
626  continue;
627  }
628  // Wait for the response
629  DELAY_MEDIUM(kb);
630  res = os_usbrecv(kb, in_msg, file, line);
631  if(res == 0)
632  return 0;
633  else if(res != -1)
634  return res;
635  if(reset_stop || hwload_mode != 2)
636  return 0;
637  DELAY_LONG(kb);
638  }
639  // Give up
640  ckb_err_fn("Too many send/recv failures. Dropping.\n", file, line);
641  return 0;
642 }
#define mmutex(kb)
Definition: device.h:26
#define DELAY_MEDIUM(kb)
the medium delay is used after sending a command before waiting for the answer.
Definition: usb.h:182
#define DELAY_SHORT(kb)
USB delays for when the keyboards get picky about timing That was the original comment, but it is used anytime.
Definition: usb.h:178
#define DELAY_LONG(kb)
The longest delay takes place where something went wrong (eg when resetting the device) ...
Definition: usb.h:186
int os_usbrecv(usbdevice *kb, uchar *in_msg, const char *file, int line)
os_usbrecv receives a max MSGSIZE long buffer from usb device
Definition: usb_linux.c:130
volatile int reset_stop
brief .
Definition: usb.c:25
int hwload_mode
hwload_mode is defined in device.c
Definition: device.c:7
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
Definition: usb_linux.c:68
#define ckb_err_fn(fmt, file, line, args...)
Definition: includes.h:48

+ Here is the call graph for this function:

int _usbsend ( usbdevice kb,
const uchar messages,
int  count,
const char *  file,
int  line 
)
Parameters
kbTHE usbdevice*
IN]messages a Pointer to the first byte of the logical message
IN]count how many MSG_SIZE buffers is the logical message long?
IN]file for debugging
IN]line for debugging
[in]reset_stopglobal variable is read
Returns
number of Bytes sent (ideal == count * MSG_SIZE);
0 if a block could not be sent and it was not a timeout OR reset_stop was required or hwload_mode is not set to "always"

_usbsend send a logical message completely to the given device

Todo:
A lot of different conditions are combined in this code. Don't think, it is good in every combination...

The main task of _usbsend () is to transfer the complete logical message from the buffer beginning with messages to count * MSG_SIZE.
According to usb 2.0 specification, a USB transmits a maximum of 64 byte user data packets. For the transmission of longer messages we need a segmentation. And that is exactly what happens here.

The message is given one by one to os_usbsend() in MSG_SIZE (= 64) byte large bites.

Attention
This means that the buffer given as argument must be n * MSG_SIZE Byte long.

An essential constant parameter which is relevant for os_usbsend() only is is_recv = 0, which means sending.

Now it gets a little complicated again:

  • If os_usbsend() returns 0, only zero bytes could be sent in one of the packets, or it was an error (-1 from the systemcall), but not a timeout. How many Bytes were sent in total from earlier calls does not seem to matter, _usbsend() returns a total of 0.
  • Returns os_usbsend() -1, first check if reset_stop is set globally or (incomprehensible) hwload_mode is not set to "always". In either case, _usbsend() returns 0, otherwise it is assumed to be a temporary transfer error and it simply retransmits the physical packet after a long delay.
  • If the return value of os_usbsend() was neither 0 nor -1, it specifies the numer of bytes transferred.
    Here is an information hiding conflict with os_usbsend() (at least in the Linux version):
    If os_usbsend() can not transfer the entire packet, errors are thrown and the number of bytes sent is returned. _usbsend() interprets this as well and remembers the total number of bytes transferred in the local variable total_sent. Subsequently, however, transmission is continued with the next complete MSG_SIZE block and not with the first of the possibly missing bytes.
    Todo:
    Check whether this is the same in the macOS variant. It is not dramatic, but if errors occur, it can certainly irritate the devices completely if they receive incomplete data streams. Do we have errors with the messages "Wrote YY bytes (expected 64)" in the system logs? If not, we do not need to look any further.

When the last packet is transferred, _usbsend() returns the effectively counted set of bytes (from total_sent). This at least gives the caller the opportunity to check whether something has been lost in the middle.

A bit strange is the structure of the program: Handling the count MSG_SIZE blocks to be transferred is done in the outer for (...) loop. Repeating the transfer with a treatable error is managed by the inner while(1) loop.
This must be considered when reading the code; The "break" on successful block transfer leaves the inner while, not the for (...).

< Synchonization between macro and color information

Definition at line 542 of file usb.c.

References DELAY_LONG, DELAY_SHORT, hwload_mode, mmutex, MSG_SIZE, os_usbsend(), and reset_stop.

542  {
543  int total_sent = 0;
544  for(int i = 0; i < count; i++){
545  // Send each message via the OS function
546  while(1){
547  pthread_mutex_lock(mmutex(kb));
548  DELAY_SHORT(kb);
549  int res = os_usbsend(kb, messages + i * MSG_SIZE, 0, file, line);
550  pthread_mutex_unlock(mmutex(kb));
551  if(res == 0)
552  return 0;
553  else if(res != -1){
554  total_sent += res;
555  break;
556  }
557  // Stop immediately if the program is shutting down or hardware load is set to tryonce
558  if(reset_stop || hwload_mode != 2)
559  return 0;
560  // Retry as long as the result is temporary failure
561  DELAY_LONG(kb);
562  }
563  }
564  return total_sent;
565 }
#define MSG_SIZE
Definition: structures.h:176
#define mmutex(kb)
Definition: device.h:26
#define DELAY_SHORT(kb)
USB delays for when the keyboards get picky about timing That was the original comment, but it is used anytime.
Definition: usb.h:178
#define DELAY_LONG(kb)
The longest delay takes place where something went wrong (eg when resetting the device) ...
Definition: usb.h:186
volatile int reset_stop
brief .
Definition: usb.c:25
int hwload_mode
hwload_mode is defined in device.c
Definition: device.c:7
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
Definition: usb_linux.c:68

+ Here is the call graph for this function:

int closeusb ( usbdevice kb)
Parameters
IN,OUT]kb
Returns
Returns 0 (everytime. No error handling is done!)

closeusb Close a USB device and remove device entry.

An imutex lock ensures first of all, that no communication is currently running from the viewpoint of the driver to the user input device (ie the virtual driver with which characters or mouse movements are sent from the daemon to the operating system as inputs).

If the kb has an acceptable value != 0, the index of the device is looked for and with this index os_inputclose() is called. After this no more characters can be sent to the operating system.

Then the connection to the usb device is capped by os_closeusb().

Todo:
What is not yet comprehensible is the call to updateconnected() BEFORE os_closeusb(). Should that be in the other sequence? Or is updateconnected() not displaying the connected usb devices, but the representation which uinput devices are loaded? Questions about questions ...

If there is no valid handle, only updateconnected() is called. We are probably trying to disconnect a connection under construction. Not clear.

The cmd pipe as well as all open notify pipes are deleted via rmdevpath ().
This means that nothing can happen to the input path - so the device-specific imutex is unlocked again and remains unlocked.

Also the dmutex is unlocked now, but only to join the thread, which was originally taken under kb->thread (which started with _setupusb()) with pthread_join() again. Because of the closed devices that thread would have to quit sometime

See Also
the hack note with rmdevpath())

As soon as the thread is caught, the dmutex is locked again, which is what I do not understand yet: What other thread can do usb communication now?
If the vtabel exists for the given kb (why not? It seems to have race conditions here!!), via the vtable the actually device-specific, but still everywhere identical freeprofile() is called. This frees areas that are no longer needed. Then the usbdevice structure in its array is set to zero completely.

Error handling is rather unusual in closeusb(); Everything works (no matter what the called functions return), and closeusb() always returns zero (success).

Definition at line 687 of file usb.c.

References ckb_info, devpath, dmutex, usbdevice::handle, imutex, INDEX_OF, keyboard, os_closeusb(), os_inputclose(), rmdevpath(), usbdevice::thread, updateconnected(), and usbdevice::vtable.

Referenced by _setupusb(), devmain(), quitWithLock(), and usb_rm_device().

687  {
688  pthread_mutex_lock(imutex(kb));
689  if(kb->handle){
690  int index = INDEX_OF(kb, keyboard);
691  ckb_info("Disconnecting %s%d\n", devpath, index);
692  os_inputclose(kb);
693  updateconnected();
694  // Close USB device
695  os_closeusb(kb);
696  } else
697  updateconnected();
698  rmdevpath(kb);
699 
700  // Wait for thread to close
701  pthread_mutex_unlock(imutex(kb));
702  pthread_mutex_unlock(dmutex(kb));
703  pthread_join(kb->thread, 0);
704  pthread_mutex_lock(dmutex(kb));
705 
706  // Delete the profile and the control path
707  if(!kb->vtable)
708  return 0;
709  kb->vtable->freeprofile(kb);
710  memset(kb, 0, sizeof(usbdevice));
711  return 0;
712 }
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
void os_closeusb(usbdevice *kb)
os_closeusb unclaim it, destroy the udev device and clear data structures at kb
Definition: usb_linux.c:448
QString devpath
Definition: kbmanager.cpp:4
#define ckb_info(fmt, args...)
Definition: includes.h:55
#define INDEX_OF(entry, array)
Definition: includes.h:27
const union devcmd * vtable
Definition: structures.h:180
#define imutex(kb)
Definition: device.h:22
int handle
Definition: structures.h:187
void os_inputclose(usbdevice *kb)
Definition: input_linux.c:76
pthread_t thread
Definition: structures.h:217
#define dmutex(kb)
Definition: device.h:18
int rmdevpath(usbdevice *kb)
Remove the dev path for the keyboard at index. Returns 0 on success.
Definition: devnode.c:275
void updateconnected()
Update the list of connected devices.
Definition: devnode.c:81

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void os_closeusb ( usbdevice kb)
Parameters
IN,OUT]kb THE usbdevice*

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)
Parameters
contextTHE usbdevice* ; Because os_inputmain() is started as a new thread, its formal parameter is named "context".
Returns
null

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 
)
Parameters
kbTHE usbdevice*
filefilename for error messages
lineline where it is called for error messages
Returns
Returns 0 on success, -2 if device should be removed and -1 if reset should by tried again

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)
Parameters
kbTHE usbdevice*

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)
Parameters
kbTHE usbdevice*
Returns
0 on success, -1 otherwise.

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 
)
Parameters
kbTHE usbdevice*
in_msgthe buffer to fill with the message received
filefor debugging
linefor debugging
Returns
-1 on timeout, 0 on hard error, numer of bytes received otherwise

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 
)
Parameters
kbTHE usbdevice*
out_msgthe MSGSIZE char long buffer to send
is_recvif true, just send an ioctl for further reading packets. If false, send the data at out_msg.
filefor debugging
linefor debugging
Returns
-1 on timeout (try again), 0 on hard error, numer of bytes sent otherwise

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:

const char* product_str ( short  product)
Parameters
productis the short USB device product ID
Returns
string to identify a type of device (see below)

product_str returns a condensed view on what type of device we have.

At present, various models and their properties are known from corsair products. Some models differ in principle (mice and keyboards), others differ in the way they function (for example, RGB and non RGB), but they are very similar.

Here, only the first point is taken into consideration and we return a unified model string. If the model is not known with its number, product_str returns an empty string.

The model numbers and corresponding strings wwith the numbers in hex-string are defined in usb.h

At present, this function is used to initialize kb->name and to give information in debug strings.

Attention
The combinations below have to fit to the combinations in the macros mentioned above. So if you add a device with a new number, change both.
Todo:
There are macros defined in usb.h to detect all the combinations below. the only difference is the parameter: The macros need the kb*, product_str() needs the product ID

Definition at line 70 of file usb.c.

References P_GLAIVE, P_HARPOON, P_K63_NRGB, P_K65, P_K65_LUX, P_K65_NRGB, P_K65_RFIRE, P_K68, P_K70, P_K70_LUX, P_K70_LUX_NRGB, P_K70_NRGB, P_K70_RFIRE, P_K70_RFIRE_NRGB, P_K95, P_K95_NRGB, P_K95_PLATINUM, P_M65, P_M65_PRO, P_SABRE_L, P_SABRE_N, P_SABRE_O, P_SABRE_O2, P_SCIMITAR, P_SCIMITAR_PRO, P_STRAFE, P_STRAFE_NRGB, and P_STRAFE_NRGB_2.

Referenced by _mkdevpath(), and _setupusb().

70  {
71  if(product == P_K95 || product == P_K95_NRGB)
72  return "k95";
73  if(product == P_K95_PLATINUM)
74  return "k95p";
75  if(product == P_K70 || product == P_K70_NRGB || product == P_K70_LUX || product == P_K70_LUX_NRGB || product == P_K70_RFIRE || product == P_K70_RFIRE_NRGB)
76  return "k70";
77  if(product == P_K68)
78  return "k68";
79  if(product == P_K65 || product == P_K65_NRGB || product == P_K65_LUX || product == P_K65_RFIRE)
80  return "k65";
81  if(product == P_K63_NRGB)
82  return "k63";
83  if(product == P_STRAFE || product == P_STRAFE_NRGB || product == P_STRAFE_NRGB_2)
84  return "strafe";
85  if(product == P_M65 || product == P_M65_PRO)
86  return "m65";
87  if(product == P_SABRE_O || product == P_SABRE_L || product == P_SABRE_N || product == P_SABRE_O2)
88  return "sabre";
89  if(product == P_SCIMITAR || product == P_SCIMITAR_PRO)
90  return "scimitar";
91  if(product == P_HARPOON)
92  return "harpoon";
93  if(product == P_GLAIVE)
94  return "glaive";
95  return "";
96 }
#define P_K70_RFIRE_NRGB
Definition: usb.h:73
#define P_GLAIVE
Definition: usb.h:119
#define P_K95_PLATINUM
Definition: usb.h:81
#define P_K65_LUX
Definition: usb.h:53
#define P_K95
Definition: usb.h:77
#define P_STRAFE_NRGB_2
Definition: usb.h:89
#define P_SABRE_N
Definition: usb.h:103
#define P_SABRE_O
Definition: usb.h:99
#define P_K65
Definition: usb.h:49
#define P_K70_NRGB
Definition: usb.h:65
#define P_K63_NRGB
Definition: usb.h:45
#define P_M65
Definition: usb.h:93
#define P_STRAFE
Definition: usb.h:85
#define P_SABRE_L
Definition: usb.h:101
#define P_HARPOON
Definition: usb.h:115
#define P_K68
Definition: usb.h:59
#define P_M65_PRO
Definition: usb.h:95
#define P_K70_RFIRE
Definition: usb.h:71
#define P_K65_NRGB
Definition: usb.h:51
#define P_SCIMITAR_PRO
Definition: usb.h:111
#define P_K70
Definition: usb.h:63
#define P_K95_NRGB
Definition: usb.h:79
#define P_SABRE_O2
Definition: usb.h:105
#define P_STRAFE_NRGB
Definition: usb.h:87
#define P_K70_LUX
Definition: usb.h:67
#define P_K70_LUX_NRGB
Definition: usb.h:69
#define P_SCIMITAR
Definition: usb.h:109
#define P_K65_RFIRE
Definition: usb.h:55

+ Here is the caller graph for this function:

int revertusb ( usbdevice kb)
Parameters
kbTHE usbdevice*
Returns
0 on success or if device needs firmware upgrade, -1 otherwise

revertusb sets a given device to inactive (hardware controlled) mode if not a fw-ugrade is indicated

First is checked, whether a firmware-upgrade is indicated for the device. If so, revertusb() returns 0.

Todo:
Why is this useful? Are there problems seen with deactivating a device with older fw-version??? Why isn't this an error indicating reason and we return success (0)?

Anyway, the following steps are similar to some other procs, dealing with low level usb handling:

  • If we do not have an RGB device, a simple setting to Hardware-mode (NK95_HWON) is sent to the device via n95cmd().
    Todo:
    The return value of nk95cmd() is ignored (but sending the ioctl may produce an error and _nk95_cmd will indicate this), instead revertusb() returns success in any case.
  • If we have an RGB device, setactive() is called with second param active = false. That function will have a look on differences between keyboards and mice.
    More precisely setactive() is just a macro to call via the kb->vtable enties either the active() or the idle() function where the vtable points to. setactive() may return error indications. If so, revertusb() returns -1, otherwise 0 in any other case.

Definition at line 417 of file usb.c.

References FEAT_RGB, HAS_FEATURES, NEEDS_FW_UPDATE, NK95_HWON, nk95cmd, and setactive.

Referenced by quitWithLock().

417  {
418  if(NEEDS_FW_UPDATE(kb))
419  return 0;
420  if(!HAS_FEATURES(kb, FEAT_RGB)){
421  nk95cmd(kb, NK95_HWON);
422  return 0;
423  }
424  if(setactive(kb, 0))
425  return -1;
426  return 0;
427 }
#define nk95cmd(kb, command)
nk95cmd() macro is used to wrap _nk95cmd() with debugging information (file and lineno). the command structure is different: Just the bits 23..16 are used as bits 7..0 for bRequest Bits 15..0 are used as wValue
Definition: usb.h:328
#define FEAT_RGB
Definition: structures.h:136
#define NK95_HWON
Hardware playback on.
Definition: usb.h:336
#define NEEDS_FW_UPDATE(kb)
Definition: structures.h:161
#define HAS_FEATURES(kb, feat)
Definition: structures.h:157
#define setactive(kb, makeactive)
setactive() calls via the corresponding kb->vtable either the active() or the idle() function...
Definition: device.h:44

+ Here is the caller graph for this function:

void setupusb ( usbdevice kb)
Attention
Lock a device's dmutex (see device.h) before accessing the USB interface.
Parameters
kbTHE usbdevice* used everywhere
OUT]kb->thread is used to store the thread ID of the fresh created thread.

setupusb starts a thread with kb as parameter and _setupusb() as entrypoint.

Set up a USB device after its handle is open. Spawns a new thread _setupusb() with standard parameter kb. dmutex must be locked prior to calling this function. The function will unlock it when finished. In kb->thread the thread id is mentioned, because closeusb() needs this info for joining that thread again.

Definition at line 396 of file usb.c.

References _setupusb(), ckb_err, imutex, and usbdevice::thread.

Referenced by usbadd().

396  {
397  pthread_mutex_lock(imutex(kb));
398  if(pthread_create(&kb->thread, 0, _setupusb, kb))
399  ckb_err("Failed to create USB thread\n");
400 }
#define ckb_err(fmt, args...)
Definition: includes.h:49
static void * _setupusb(void *context)
brief .
Definition: usb.c:224
#define imutex(kb)
Definition: device.h:22
pthread_t thread
Definition: structures.h:217

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int usb_tryreset ( usbdevice kb)
Parameters
[in,out]kbTHE usbdevice*
[in]reset_stopglobal variable is read
Returns
0 on success, -1 otherwise

usb_tryreset does what the name means: Try to reset the usb via resetusb()

This function is called if an usb command ran into an error in case of one of the following two situations:

  • When setting up a new usb device and the start() function got an error (
    See Also
    _setupusb())
  • If upgrading to a new firmware gets an error (
    See Also
    cmd_fwupdate()).
    The previous action which got the error will NOT be re-attempted.

In an endless loop usb_tryreset() tries to reset the given usb device via the macro resetusb().
This macro calls _resetusb() with debugging information.
_resetusb() sends a command via the operating system dependent function os_resetusb() and - if successful - reinitializes the device. os_resetusb() returns -2 to indicate a broken device and all structures should be removed for it.
In that case, the loop is terminated, an error message is produced and usb_tryreset() returns -1.

In case resetusb() has success, the endless loop is left via a return 0 (success).
If the return value from resetusb() is -1, the loop is continued with the next try.

If the global variable reset_stop is set directly when the function is called or after each try, usb_tryreset() stops working and returns -1.

Todo:
Why does usb_tryreset() hide the information returned from resetusb()? Isn't it needed by the callers?

Definition at line 475 of file usb.c.

References ckb_err, ckb_info, reset_stop, and resetusb.

Referenced by _setupusb(), cmd_fwupdate(), os_sendindicators(), and os_setupusb().

475  {
476  if(reset_stop)
477  return -1;
478  ckb_info("Attempting reset...\n");
479  while(1){
480  int res = resetusb(kb);
481  if(!res){
482  ckb_info("Reset success\n");
483  return 0;
484  }
485  if(res == -2 || reset_stop)
486  break;
487  }
488  ckb_err("Reset failed. Disconnecting.\n");
489  return -1;
490 }
#define ckb_err(fmt, args...)
Definition: includes.h:49
volatile int reset_stop
brief .
Definition: usb.c:25
#define ckb_info(fmt, args...)
Definition: includes.h:55
#define resetusb(kb)
resetusb() is just a macro to call _resetusb() with debuggin constants (file, lineno) ...
Definition: usb.h:246

+ 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:

const char* vendor_str ( short  vendor)

uncomment to see USB packets received from the device vendor_str Vendor/product string representations

Parameters
vendorshort vendor ID
Returns
a string: either "" or "corsair"

uncomment to see USB packets sent to the device

vendor_str returns "corsair" if the given vendor argument is equal to V_CORSAIR (0x1bc) else it returns ""

Attention
There is also a string defined V_CORSAIR_STR, which returns the device number as string in hex "1b1c".

Definition at line 43 of file usb.c.

References V_CORSAIR.

Referenced by _mkdevpath(), and _setupusb().

43  {
44  if(vendor == V_CORSAIR)
45  return "corsair";
46  return "";
47 }
#define V_CORSAIR
For the following Defines please see "Detailed Description".
Definition: usb.h:42

+ Here is the caller graph for this function: