ckb-next
v0.2.8 at branch master
ckb-next driver for corsair devices
|
Go to the source code of this file.
Data Structures | |
struct | _model |
Macros | |
#define | DEBUG |
all open usb devices have their system path names here in this array. More... | |
#define | TEST_RESET(op) |
TEST_RESET doesa "try / catch" for resetting the usb interface. More... | |
#define | N_MODELS (sizeof(models) / sizeof(_model)) |
Functions | |
int | os_usbsend (usbdevice *kb, const uchar *out_msg, int is_recv, const char *file, int line) |
os_usbsend sends a data packet (MSG_SIZE = 64) Bytes long More... | |
int | os_usbrecv (usbdevice *kb, uchar *in_msg, const char *file, int line) |
os_usbrecv receives a max MSGSIZE long buffer from usb device More... | |
int | _nk95cmd (usbdevice *kb, uchar bRequest, ushort wValue, const char *file, int line) |
_nk95cmd If we control a non RGB keyboard, set the keyboard via ioctl with usbdevfs_ctrltransfer More... | |
void | os_sendindicators (usbdevice *kb) |
void * | os_inputmain (void *context) |
os_inputmain This function is run in a separate thread and will be detached from the main thread, so it needs to clean up its own resources. More... | |
static int | usbunclaim (usbdevice *kb, int resetting) |
void | os_closeusb (usbdevice *kb) |
static int | usbclaim (usbdevice *kb) |
int | os_resetusb (usbdevice *kb, const char *file, int line) |
void | strtrim (char *string) |
int | os_setupusb (usbdevice *kb) |
int | usbadd (struct udev_device *dev, short vendor, short product) |
static int | usb_add_device (struct udev_device *dev) |
Add a udev device. Returns 0 if device was recognized/added. More... | |
static void | usb_rm_device (struct udev_device *dev) |
usb_rm_device find the usb port to remove and close it via closeusb(). More... | |
static void | udev_enum () |
udev_enum use the udev_enumerate_add_match_subsystem() to get all you need but only that. More... | |
int | usbmain () |
void | usbkill () |
Stop the USB system. More... | |
Variables | |
static char | kbsyspath [9][FILENAME_MAX] |
static struct udev * | udev |
struct udef is defined in /usr/include/libudev.h More... | |
pthread_t | usbthread |
pthread_t | udevthread |
static _model | models [] |
struct _model |
Definition at line 658 of file usb_linux.c.
Data Fields | ||
---|---|---|
const char * | name | |
short | number |
#define DEBUG |
Definition at line 11 of file usb_linux.c.
Definition at line 700 of file usb_linux.c.
Referenced by usb_add_device().
#define TEST_RESET | ( | op | ) |
Definition at line 492 of file usb_linux.c.
Referenced by os_resetusb().
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 |
Definition at line 189 of file usb_linux.c.
References ckb_err_fn, usbdevice::handle, P_K95_NRGB, and usbdevice::product.
void os_closeusb | ( | usbdevice * | kb | ) |
os_closeusb unclaim it, destroy the udev device and clear data structures at kb
os_closeusb is the linux specific implementation for closing an active usb port.
If a valid handle is given in the kb structure, the usb port is unclaimed (usbunclaim()).
The device in unrefenced via library function udev_device_unref().
handle, udev and the first char of kbsyspath are cleared to 0 (empty string for kbsyspath).
Definition at line 448 of file usb_linux.c.
References usbdevice::handle, INDEX_OF, kbsyspath, keyboard, usbdevice::udev, and usbunclaim().
Referenced by closeusb().
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.
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().
int os_resetusb | ( | usbdevice * | kb, |
const char * | file, | ||
int | line | ||
) |
os_resetusb is the os specific implementation for resetting usb
Try to reset an usb device in a linux user space driver.
Definition at line 510 of file usb_linux.c.
References usbdevice::handle, TEST_RESET, usbclaim(), and usbunclaim().
Referenced by _resetusb().
void os_sendindicators | ( | usbdevice * | kb | ) |
os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else?)
os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else?)
Read the data from kb->ileds ans send them via ioctl() to the keyboard.
bRequestType | bRequest | wValue | EP | size | Timeout | data |
---|---|---|---|---|---|---|
0x21 | 0x09 | 0x0200 | Interface 0 | MSG_SIZE 1 Byte | timeout 0,5ms | the message buffer pointer |
Host to Device, Type=Class, Recipient=Interface (why not endpoint?) | 9 = SEND? | specific | 0 | 1 | 500 | struct* kb->ileds |
The ioctl command is USBDEVFS_CONTROL.
Definition at line 214 of file usb_linux.c.
References ckb_err, usbdevice::fwversion, usbdevice::handle, usbdevice::ileds, and usb_tryreset().
Referenced by updateindicators_kb().
int os_setupusb | ( | usbdevice * | kb | ) |
os_setupusb OS-specific setup for a specific usb device.
Perform the operating system-specific opening of the interface in os_setupusb(). As a result, some parameters should be set in kb (name, serial, fwversion, epcount = number of usb endpoints), and all endpoints should be claimed with usbclaim(). Claiming is the only point where os_setupusb() can produce an error (-1).
< 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().
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 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().
os_usbsend has two functions:
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.
The ioctl() - no matter what type - returns the number of bytes sent. Now comes the usual check:
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().
void strtrim | ( | char * | string | ) |
strtrim trims a string by removing leading and trailing spaces.
string |
Definition at line 523 of file usb_linux.c.
Referenced by os_setupusb().
|
static |
Reduce the hits of the enumeration by limiting to usb as technology and corsair as idVendor. Then filter with udev_enumerate_scan_devices () all hits.
The following call to udev_enumerate_get_list_entry() fetches the entire hitlist as udev_list_entry *.
Use udev_list_entry_foreach() to iterate through the hit set.
If both the device name exists (udev_list_entry_get_name) and the subsequent creation of a new udev_device (udev_device_new_from_syspath) is ok, the new device is added to the list with usb_add_device().
If the latter does not work, the new device is released again (udev_device_unref ()).
After the last iteration, the enumerator is released with udev_enumerate_unref ().
Definition at line 765 of file usb_linux.c.
References usb_add_device(), and V_CORSAIR_STR.
Referenced by usbmain().
|
static |
If the device id can be found, call usbadd() with the appropriate parameters.
dev | the functions usb_*_device get a struct udev* with the neccessary hardware-related information. |
First get the idVendor via udev_device_get_sysattr_value(). If this is equal to the ID-string of corsair ("1b1c"), get the idProduct on the same way.
If we can find the model name in the model array, call usbadd() with the model number.
Definition at line 713 of file usb_linux.c.
References N_MODELS, usbadd(), V_CORSAIR, and V_CORSAIR_STR.
Referenced by udev_enum(), and usbmain().
|
static |
dev | the functions usb_*_device get a struct udev* with the neccessary hardware-related information. |
First try to find the system path of the device given in parameter dev. The index where the name is found is the same index we need to address the global keyboard array. That array holds all usbdevices.
Searching for the correct name in kbsyspath-array and closing the usb via closeusb() are protected by lock..unlock of the corresponding devmutex arraymember.
Definition at line 738 of file usb_linux.c.
References closeusb(), DEV_MAX, devmutex, kbsyspath, and keyboard.
Referenced by usbmain().
int usbadd | ( | struct udev_device * | dev, |
short | vendor, | ||
short | product | ||
) |
Definition at line 606 of file usb_linux.c.
References ckb_err, ckb_info, DEV_MAX, dmutex, usbdevice::handle, IS_CONNECTED, kbsyspath, keyboard, usbdevice::product, setupusb(), usbdevice::udev, and usbdevice::vendor.
Referenced by usb_add_device().
|
static |
usbclaim does claiming all EPs for the usb device gicen by kb.
kb | THE usbdevice* |
Claim all endpoints for a given device (remeber the decrementing of the file descriptor) via ioctl(USBDEVFS_DISCONNECT) and ioctl(USBDEVFS_CLAIMINTERFACE).
Error handling is done for the ioctl(USBDEVFS_CLAIMINTERFACE) only. If this fails, now an error message is thrown and -1 is returned. Function is called in usb_linux.c only, so it is declared as static now.
Definition at line 472 of file usb_linux.c.
References ckb_err, ckb_info, usbdevice::epcount, and usbdevice::handle.
Referenced by os_resetusb(), and os_setupusb().
void usbkill | ( | ) |
Definition at line 853 of file usb_linux.c.
Referenced by quitWithLock().
int usbmain | ( | ) |
Start the USB main loop. Returns program exit code when finished.
usbmain is called by main() after setting up all other stuff.
First check whether the uinput module is loaded by the kernel.
Create the udev object with udev_new() (is a function from libudev.h) terminate -1 if error
Enumerate all currently connected devices
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().
|
static |
usbunclaim do an unclaiming of the usb device gicen by kb.
kb | THE usbdevice* |
resetting | boolean flag: If resseting is true, the caller will perform a bus reset command after unclaiming the device. |
Unclaim all endpoints for a given device (remeber the decrementing of the file descriptor) via ioctl(USBDEVFS_DISCARDURB).
Afterwards - if ressetting is false - do a USBDEVFS_CONNECT for EP 0 and 1. If it is a non RGB device, connect EP 2 also. The comment mentions RGB keyboards only, but as I understand the code, this is valid also for RGB mice.
There is no error handling yet. Function is called in usb_linux.c only, so it is declared as static now.
Definition at line 419 of file usb_linux.c.
References usbdevice::epcount, FEAT_RGB, usbdevice::handle, and HAS_FEATURES.
Referenced by os_closeusb(), and os_resetusb().
|
static |
Definition at line 13 of file usb_linux.c.
Referenced by os_closeusb(), usb_rm_device(), and usbadd().
|
static |
In this structure array models[] for each device the name (the device id as string in hex without leading 0x) and its usb device id as short must be entered in this array.
Definition at line 668 of file usb_linux.c.
|
static |
Definition at line 652 of file usb_linux.c.
pthread_t udevthread |
Definition at line 655 of file usb_linux.c.
pthread_t usbthread |
Definition at line 655 of file usb_linux.c.