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.c
Go to the documentation of this file.
1 #include "command.h"
2 #include "device.h"
3 #include "devnode.h"
4 #include "firmware.h"
5 #include "input.h"
6 #include "led.h"
7 #include "notify.h"
8 #include "profile.h"
9 #include "usb.h"
10 
17 pthread_mutex_t usbmutex = PTHREAD_MUTEX_INITIALIZER;
18 
25 volatile int reset_stop = 0;
26 
35 int features_mask = -1;
36 
43 const char* vendor_str(short vendor){
44  if(vendor == V_CORSAIR)
45  return "corsair";
46  return "";
47 }
48 
70 const char* product_str(short product){
71  if(product == P_K95 || product == P_K95_NRGB || product == P_K95_PLATINUM)
72  return "k95";
73  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)
74  return "k70";
75  if(product == P_K65 || product == P_K65_NRGB || product == P_K65_LUX || product == P_K65_RFIRE)
76  return "k65";
77  if(product == P_STRAFE || product == P_STRAFE_NRGB)
78  return "strafe";
79  if(product == P_M65 || product == P_M65_PRO)
80  return "m65";
81  if(product == P_SABRE_O || product == P_SABRE_L || product == P_SABRE_N || product == P_SABRE_O2)
82  return "sabre";
83  if(product == P_SCIMITAR || product == P_SCIMITAR_PRO)
84  return "scimitar";
85  return "";
86 }
87 
102 static const devcmd* get_vtable(short vendor, short product){
103  return IS_MOUSE(vendor, product) ? &vtable_mouse : IS_RGB(vendor, product) ? &vtable_keyboard : &vtable_keyboard_nonrgb;
104 }
105 
106 // USB device main loop
135 static void* devmain(usbdevice* kb){
137  int kbfifo = kb->infifo - 1;
140  readlines_ctx linectx;
141  readlines_ctx_init(&linectx);
146  while(1){
153  pthread_mutex_unlock(dmutex(kb));
154  // Read from FIFO
155  const char* line;
156  int lines = readlines(kbfifo, linectx, &line);
157  pthread_mutex_lock(dmutex(kb));
158  // End thread when the handle is removed
159  if(!IS_CONNECTED(kb))
160  break;
164  if(lines){
167  if(readcmd(kb, line)){
173  // USB transfer failed; destroy device
174  closeusb(kb);
175  break;
176  }
177  }
178  }
179  pthread_mutex_unlock(dmutex(kb));
182  readlines_ctx_free(linectx);
183  return 0;
184 }
185 
200 
201 
213 
214 static void* _setupusb(void* context){
227  usbdevice* kb = context;
228  // Set standard fields
229  short vendor = kb->vendor, product = kb->product;
230  const devcmd* vt = kb->vtable = get_vtable(vendor, product);
231  kb->features = (IS_RGB(vendor, product) ? FEAT_STD_RGB : FEAT_STD_NRGB) & features_mask;
232  if(IS_MOUSE(vendor, product)) kb->features |= FEAT_ADJRATE;
233  if(IS_MONOCHROME(vendor, product)) kb->features |= FEAT_MONOCHROME;
235 
236  // Perform OS-specific setup
240  DELAY_LONG(kb);
241 
247  if(os_setupusb(kb))
248  goto fail;
249 
255  // Make up a device name and serial if they weren't assigned
256  if(!kb->serial[0])
257  snprintf(kb->serial, SERIAL_LEN, "%04x:%04x-NoID", kb->vendor, kb->product);
258  if(!kb->name[0])
259  snprintf(kb->name, KB_NAME_LEN, "%s %s", vendor_str(kb->vendor), product_str(kb->product));
260 
261  // Set up an input device for key events
269  if(os_inputopen(kb))
270  goto fail;
274  if(pthread_create(&kb->inputthread, 0, os_inputmain, kb))
275  goto fail;
276  pthread_detach(kb->inputthread);
282  if(os_setupindicators(kb))
283  goto fail;
284 
285  // Set up device
298  vt->allocprofile(kb);
309  vt->updateindicators(kb, 1);
314  pthread_mutex_unlock(imutex(kb));
348  if(vt->start(kb, 0) && usb_tryreset(kb))
349  goto fail_noinput;
355  // Make /dev path
356  if(mkdevpath(kb))
357  goto fail_noinput;
363  // Finished. Enter main loop
364  int index = INDEX_OF(kb, keyboard);
365  ckb_info("Setup finished for %s%d\n", devpath, index);
366  updateconnected();
369  return devmain(kb);
372  fail:
373  pthread_mutex_unlock(imutex(kb));
374  fail_noinput:
375  closeusb(kb);
376  pthread_mutex_unlock(dmutex(kb));
377  return 0;
378 }
379 
386 void setupusb(usbdevice* kb){
387  pthread_mutex_lock(imutex(kb));
388  if(pthread_create(&kb->thread, 0, _setupusb, kb))
389  ckb_err("Failed to create USB thread\n");
390 }
391 
408  if(NEEDS_FW_UPDATE(kb))
409  return 0;
410  if(!HAS_FEATURES(kb, FEAT_RGB)){
411  nk95cmd(kb, NK95_HWON);
412  return 0;
413  }
414  if(setactive(kb, 0))
415  return -1;
416  return 0;
417 }
418 
426 int _resetusb(usbdevice* kb, const char* file, int line){
427  // Perform a USB reset
428  DELAY_LONG(kb);
429  int res = os_resetusb(kb, file, line);
430  if(res)
431  return res;
432  DELAY_LONG(kb);
433  // Re-initialize the device
434  if(kb->vtable->start(kb, kb->active) != 0)
435  return -1;
436  if(kb->vtable->updatergb(kb, 1) != 0)
437  return -1;
438  return 0;
439 }
440 
466  if(reset_stop)
467  return -1;
468  ckb_info("Attempting reset...\n");
469  while(1){
470  int res = resetusb(kb);
471  if(!res){
472  ckb_info("Reset success\n");
473  return 0;
474  }
475  if(res == -2 || reset_stop)
476  break;
477  }
478  ckb_err("Reset failed. Disconnecting.\n");
479  return -1;
480 }
481 
485 extern int hwload_mode;
486 
532 int _usbsend(usbdevice* kb, const uchar* messages, int count, const char* file, int line){
533  int total_sent = 0;
534  for(int i = 0; i < count; i++){
535  // Send each message via the OS function
536  while(1){
537  pthread_mutex_lock(mmutex(kb));
538  DELAY_SHORT(kb);
539  int res = os_usbsend(kb, messages + i * MSG_SIZE, 0, file, line);
540  pthread_mutex_unlock(mmutex(kb));
541  if(res == 0)
542  return 0;
543  else if(res != -1){
544  total_sent += res;
545  break;
546  }
547  // Stop immediately if the program is shutting down or hardware load is set to tryonce
548  if(reset_stop || hwload_mode != 2)
549  return 0;
550  // Retry as long as the result is temporary failure
551  DELAY_LONG(kb);
552  }
553  }
554  return total_sent;
555 }
556 
601 int _usbrecv(usbdevice* kb, const uchar* out_msg, uchar* in_msg, const char* file, int line){
602  // Try a maximum of 5 times
603  for (int try = 0; try < 5; try++) {
604  // Send the output message
605  pthread_mutex_lock(mmutex(kb));
606  DELAY_SHORT(kb);
607  int res = os_usbsend(kb, out_msg, 1, file, line);
608  pthread_mutex_unlock(mmutex(kb));
609  if (res == 0)
610  return 0;
611  else if (res == -1) {
612  // Retry on temporary failure
613  if (reset_stop)
614  return 0;
615  DELAY_LONG(kb);
616  continue;
617  }
618  // Wait for the response
619  DELAY_MEDIUM(kb);
620  res = os_usbrecv(kb, in_msg, file, line);
621  if(res == 0)
622  return 0;
623  else if(res != -1)
624  return res;
625  if(reset_stop || hwload_mode != 2)
626  return 0;
627  DELAY_LONG(kb);
628  }
629  // Give up
630  ckb_err_fn("Too many send/recv failures. Dropping.\n", file, line);
631  return 0;
632 }
633 
678  pthread_mutex_lock(imutex(kb));
679  if(kb->handle){
680  int index = INDEX_OF(kb, keyboard);
681  ckb_info("Disconnecting %s%d\n", devpath, index);
682  os_inputclose(kb);
683  updateconnected();
684  // Close USB device
685  os_closeusb(kb);
686  } else
687  updateconnected();
688  rmdevpath(kb);
689 
690  // Wait for thread to close
691  pthread_mutex_unlock(imutex(kb));
692  pthread_mutex_unlock(dmutex(kb));
693  pthread_join(kb->thread, 0);
694  pthread_mutex_lock(dmutex(kb));
695 
696  // Delete the profile and the control path
697  if(!kb->vtable)
698  return 0;
699  kb->vtable->freeprofile(kb);
700  memset(kb, 0, sizeof(usbdevice));
701  return 0;
702 }
#define P_K70_RFIRE_NRGB
Definition: usb.h:61
#define KB_NAME_LEN
Definition: structures.h:174
#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:296
static void * devmain(usbdevice *kb)
brief .
Definition: usb.c:135
#define MSG_SIZE
Definition: structures.h:176
#define mmutex(kb)
Definition: device.h:26
void setupusb(usbdevice *kb)
Definition: usb.c:386
Definition: command.h:73
#define P_K95_PLATINUM
Definition: usb.h:69
int usb_tryreset(usbdevice *kb)
Definition: usb.c:465
#define P_K65_LUX
Definition: usb.h:45
char name[40+1]
Definition: structures.h:233
#define P_K95
Definition: usb.h:65
#define IS_CONNECTED(kb)
Definition: device.h:12
#define DELAY_MEDIUM(kb)
the medium delay is used after sending a command before waiting for the answer.
Definition: usb.h:152
int readcmd(usbdevice *kb, const char *line)
Definition: command.c:68
const char * vendor_str(short vendor)
brief .
Definition: usb.c:43
unsigned readlines(int fd, readlines_ctx ctx, const char **input)
Definition: devnode.c:353
#define P_SABRE_N
Definition: usb.h:89
#define P_SABRE_O
Definition: usb.h:85
#define DELAY_SHORT(kb)
USB delays for when the keyboards get picky about timing That was the original comment, but it is used anytime. The short delay is used before any send or receive.
Definition: usb.h:149
#define DELAY_LONG(kb)
The longest delay takes place where something went wrong (eg when resetting the device) ...
Definition: usb.h:155
int mkdevpath(usbdevice *kb)
Create a dev path for the keyboard at index. Returns 0 on success.
Definition: devnode.c:268
#define P_K65
Definition: usb.h:41
#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
pthread_t inputthread
Definition: structures.h:219
#define P_K70_NRGB
Definition: usb.h:53
#define FEAT_RGB
Definition: structures.h:136
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
int os_resetusb(usbdevice *kb, const char *file, int line)
os_resetusb is the os specific implementation for resetting usb
Definition: usb_linux.c:497
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.
Definition: usb_linux.c:238
void os_closeusb(usbdevice *kb)
os_closeusb unclaim it, destroy the udev device and clear data structures at kb
Definition: usb_linux.c:435
#define P_M65
Definition: usb.h:79
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:129
int os_setupusb(usbdevice *kb)
os_setupusb OS-specific setup for a specific usb device.
Definition: usb_linux.c:535
char active
Definition: structures.h:231
#define P_STRAFE
Definition: usb.h:73
const devcmd vtable_mouse
#define P_SABRE_L
Definition: usb.h:87
#define IS_MONOCHROME(vendor, product)
The difference between non RGB and monochrome is, that monochrome has lights, but just in one color...
Definition: usb.h:129
int infifo
Definition: structures.h:225
int _usbrecv(usbdevice *kb, const uchar *out_msg, uchar *in_msg, const char *file, int line)
Definition: usb.c:601
volatile int reset_stop
brief .
Definition: usb.c:25
#define IS_MOUSE(vendor, product)
Mouse vs keyboard test.
Definition: usb.h:141
#define NK95_HWON
Hardware playback on.
Definition: usb.h:304
unsigned char uchar
Definition: includes.h:24
int hwload_mode
hwload_mode is defined in device.c
Definition: device.c:7
int os_inputopen(usbdevice *kb)
os_inputopen
Definition: input_linux.c:55
static const devcmd * get_vtable(short vendor, short product)
brief .
Definition: usb.c:102
#define P_M65_PRO
Definition: usb.h:81
#define P_K70_RFIRE
Definition: usb.h:59
void readlines_ctx_init(readlines_ctx *ctx)
Definition: devnode.c:341
int features_mask
brief .
Definition: usb.c:35
const char *const devpath
Definition: devnode.c:11
#define ckb_info(fmt, args...)
Definition: includes.h:55
int _resetusb(usbdevice *kb, const char *file, int line)
Definition: usb.c:426
#define P_K65_NRGB
Definition: usb.h:43
#define P_SCIMITAR_PRO
Definition: usb.h:97
short product
Definition: structures.h:237
static void * _setupusb(void *context)
brief .
Definition: usb.c:214
#define INDEX_OF(entry, array)
Definition: includes.h:27
#define USB_DELAY_DEFAULT
This constant is used to initialize kb->usbdelay. It is used in many places (see macros above) but of...
Definition: usb.h:160
#define P_K70
Definition: usb.h:51
int _usbsend(usbdevice *kb, const uchar *messages, int count, const char *file, int line)
Definition: usb.c:532
#define NEEDS_FW_UPDATE(kb)
Definition: structures.h:161
#define FEAT_STD_RGB
Definition: structures.h:152
const char * product_str(short product)
brief .
Definition: usb.c:70
const union devcmd * vtable
Definition: structures.h:180
#define P_K95_NRGB
Definition: usb.h:67
#define FEAT_MONOCHROME
Definition: structures.h:137
#define P_SABRE_O2
Definition: usb.h:91
int os_setupindicators(usbdevice *kb)
Definition: input_linux.c:189
int closeusb(usbdevice *kb)
Definition: usb.c:677
char serial[34]
Definition: structures.h:235
#define imutex(kb)
Definition: device.h:22
pthread_mutex_t usbmutex
brief .
Definition: usb.c:17
#define P_STRAFE_NRGB
Definition: usb.h:75
int handle
Definition: structures.h:187
void os_inputclose(usbdevice *kb)
Definition: input_linux.c:76
ushort features
Definition: structures.h:229
char usbdelay
Definition: structures.h:243
#define HAS_FEATURES(kb, feat)
Definition: structures.h:157
Definitions for using USB interface.
pthread_t thread
Definition: structures.h:217
#define P_K70_LUX
Definition: usb.h:55
#define V_CORSAIR
For the following Defines please see "Detailed Description".
Definition: usb.h:38
#define resetusb(kb)
resetusb() is just a macro to call _resetusb() with debuggin constants (file, lineno) ...
Definition: usb.h:214
#define P_K70_LUX_NRGB
Definition: usb.h:57
#define P_SCIMITAR
Definition: usb.h:95
#define FEAT_STD_NRGB
Definition: structures.h:153
const devcmd vtable_keyboard
RGB keyboard vtable holds functions for each device type.
Definition: device_vtable.c:29
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 dmutex(kb)
Definition: device.h:18
void readlines_ctx_free(readlines_ctx ctx)
Definition: devnode.c:348
#define FEAT_ADJRATE
Definition: structures.h:139
int rmdevpath(usbdevice *kb)
Remove the dev path for the keyboard at index. Returns 0 on success.
Definition: devnode.c:275
short vendor
Definition: structures.h:237
#define ckb_err_fn(fmt, file, line, args...)
Definition: includes.h:48
void updateconnected()
Update the list of connected devices.
Definition: devnode.c:81
#define SERIAL_LEN
Definition: structures.h:175
#define P_K65_RFIRE
Definition: usb.h:47
int revertusb(usbdevice *kb)
Definition: usb.c:407
const devcmd vtable_keyboard_nonrgb
Definition: device_vtable.c:76
#define setactive(kb, makeactive)
setactive() calls via the corresponding kb->vtable either the active() or the idle() function...
Definition: device.h:44