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.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)
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 }
97 
112 static const devcmd* get_vtable(short vendor, short product){
113  return IS_MOUSE(vendor, product) ? &vtable_mouse : IS_RGB(vendor, product) ? &vtable_keyboard : &vtable_keyboard_nonrgb;
114 }
115 
116 // USB device main loop
145 static void* devmain(usbdevice* kb){
147  int kbfifo = kb->infifo - 1;
150  readlines_ctx linectx;
151  readlines_ctx_init(&linectx);
156  while(1){
163  pthread_mutex_unlock(dmutex(kb));
164  // Read from FIFO
165  const char* line;
166  int lines = readlines(kbfifo, linectx, &line);
167  pthread_mutex_lock(dmutex(kb));
168  // End thread when the handle is removed
169  if(!IS_CONNECTED(kb))
170  break;
174  if(lines){
177  if(readcmd(kb, line)){
183  // USB transfer failed; destroy device
184  closeusb(kb);
185  break;
186  }
187  }
188  }
189  pthread_mutex_unlock(dmutex(kb));
192  readlines_ctx_free(linectx);
193  return 0;
194 }
195 
210 
211 
223 
224 static void* _setupusb(void* context){
237  usbdevice* kb = context;
238  // Set standard fields
239  short vendor = kb->vendor, product = kb->product;
240  const devcmd* vt = kb->vtable = get_vtable(vendor, product);
241  kb->features = (IS_RGB(vendor, product) ? FEAT_STD_RGB : FEAT_STD_NRGB) & features_mask;
242  if(IS_MOUSE(vendor, product)) kb->features |= FEAT_ADJRATE;
243  if(IS_MONOCHROME(vendor, product)) kb->features |= FEAT_MONOCHROME;
245 
246  // Perform OS-specific setup
250  DELAY_LONG(kb);
251 
257  if(os_setupusb(kb))
258  goto fail;
259 
265  // Make up a device name and serial if they weren't assigned
266  if(!kb->serial[0])
267  snprintf(kb->serial, SERIAL_LEN, "%04x:%04x-NoID", kb->vendor, kb->product);
268  if(!kb->name[0])
269  snprintf(kb->name, KB_NAME_LEN, "%s %s", vendor_str(kb->vendor), product_str(kb->product));
270 
271  // Set up an input device for key events
279  if(os_inputopen(kb))
280  goto fail;
284  if(pthread_create(&kb->inputthread, 0, os_inputmain, kb))
285  goto fail;
286  pthread_detach(kb->inputthread);
292  if(os_setupindicators(kb))
293  goto fail;
294 
295  // Set up device
308  vt->allocprofile(kb);
319  vt->updateindicators(kb, 1);
324  pthread_mutex_unlock(imutex(kb));
358  if(vt->start(kb, 0) && usb_tryreset(kb))
359  goto fail_noinput;
365  // Make /dev path
366  if(mkdevpath(kb))
367  goto fail_noinput;
373  // Finished. Enter main loop
374  int index = INDEX_OF(kb, keyboard);
375  ckb_info("Setup finished for %s%d\n", devpath, index);
376  updateconnected();
379  return devmain(kb);
382  fail:
383  pthread_mutex_unlock(imutex(kb));
384  fail_noinput:
385  closeusb(kb);
386  pthread_mutex_unlock(dmutex(kb));
387  return 0;
388 }
389 
396 void setupusb(usbdevice* kb){
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 }
401 
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 }
428 
436 int _resetusb(usbdevice* kb, const char* file, int line){
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 }
450 
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 }
491 
495 extern int hwload_mode;
496 
542 int _usbsend(usbdevice* kb, const uchar* messages, int count, const char* file, int line){
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 }
566 
611 int _usbrecv(usbdevice* kb, const uchar* out_msg, uchar* in_msg, const char* file, int line){
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 }
643 
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 }
#define P_K70_RFIRE_NRGB
Definition: usb.h:73
#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:328
static void * devmain(usbdevice *kb)
brief .
Definition: usb.c:145
#define MSG_SIZE
Definition: structures.h:176
#define P_GLAIVE
Definition: usb.h:119
#define mmutex(kb)
Definition: device.h:26
void setupusb(usbdevice *kb)
Definition: usb.c:396
Definition: command.h:73
#define P_K95_PLATINUM
Definition: usb.h:81
int usb_tryreset(usbdevice *kb)
Definition: usb.c:475
#define P_K65_LUX
Definition: usb.h:53
char name[40+1]
Definition: structures.h:233
#define P_K95
Definition: usb.h:77
#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:182
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_STRAFE_NRGB_2
Definition: usb.h:89
#define P_SABRE_N
Definition: usb.h:103
#define P_SABRE_O
Definition: usb.h:99
#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 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:49
#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
pthread_t inputthread
Definition: structures.h:219
#define P_K70_NRGB
Definition: usb.h:65
#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:510
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:248
void os_closeusb(usbdevice *kb)
os_closeusb unclaim it, destroy the udev device and clear data structures at kb
Definition: usb_linux.c:448
#define P_K63_NRGB
Definition: usb.h:45
#define P_M65
Definition: usb.h:93
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
int os_setupusb(usbdevice *kb)
os_setupusb OS-specific setup for a specific usb device.
Definition: usb_linux.c:548
char active
Definition: structures.h:231
#define P_STRAFE
Definition: usb.h:85
const devcmd vtable_mouse
#define P_SABRE_L
Definition: usb.h:101
#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:151
int infifo
Definition: structures.h:225
#define P_HARPOON
Definition: usb.h:115
int _usbrecv(usbdevice *kb, const uchar *out_msg, uchar *in_msg, const char *file, int line)
Definition: usb.c:611
volatile int reset_stop
brief .
Definition: usb.c:25
#define IS_MOUSE(vendor, product)
Mouse vs keyboard test.
Definition: usb.h:163
#define NK95_HWON
Hardware playback on.
Definition: usb.h:336
unsigned char uchar
Definition: includes.h:24
QString devpath
Definition: kbmanager.cpp:4
#define P_K68
Definition: usb.h:59
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:112
#define P_M65_PRO
Definition: usb.h:95
#define P_K70_RFIRE
Definition: usb.h:71
void readlines_ctx_init(readlines_ctx *ctx)
Definition: devnode.c:341
int features_mask
brief .
Definition: usb.c:35
#define ckb_info(fmt, args...)
Definition: includes.h:55
int _resetusb(usbdevice *kb, const char *file, int line)
Definition: usb.c:436
#define P_K65_NRGB
Definition: usb.h:51
#define P_SCIMITAR_PRO
Definition: usb.h:111
short product
Definition: structures.h:237
static void * _setupusb(void *context)
brief .
Definition: usb.c:224
#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:192
#define P_K70
Definition: usb.h:63
int _usbsend(usbdevice *kb, const uchar *messages, int count, const char *file, int line)
Definition: usb.c:542
#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:79
#define FEAT_MONOCHROME
Definition: structures.h:137
#define P_SABRE_O2
Definition: usb.h:105
int os_setupindicators(usbdevice *kb)
Definition: input_linux.c:189
int closeusb(usbdevice *kb)
Definition: usb.c:687
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:87
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:67
#define V_CORSAIR
For the following Defines please see "Detailed Description".
Definition: usb.h:42
#define resetusb(kb)
resetusb() is just a macro to call _resetusb() with debuggin constants (file, lineno) ...
Definition: usb.h:246
#define P_K70_LUX_NRGB
Definition: usb.h:69
#define P_SCIMITAR
Definition: usb.h:109
#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:52
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:55
int revertusb(usbdevice *kb)
Definition: usb.c:417
const devcmd vtable_keyboard_nonrgb
Definition: device_vtable.c:99
#define setactive(kb, makeactive)
setactive() calls via the corresponding kb->vtable either the active() or the idle() function...
Definition: device.h:44