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
firmware.c File Reference
#include "devnode.h"
#include "firmware.h"
#include "notify.h"
#include "usb.h"
+ Include dependency graph for firmware.c:

Go to the source code of this file.

Macros

#define FW_OK   0
 
#define FW_NOFILE   -1
 
#define FW_WRONGDEV   -2
 
#define FW_USBFAIL   -3
 
#define FW_MAXSIZE   (255 * 256)
 

Functions

int getfwversion (usbdevice *kb)
 
int fwupdate (usbdevice *kb, const char *path, int nnumber)
 
int cmd_fwupdate (usbdevice *kb, usbmode *dummy1, int nnumber, int dummy2, const char *path)
 

Macro Definition Documentation

#define FW_MAXSIZE   (255 * 256)

Definition at line 51 of file firmware.c.

Referenced by fwupdate().

#define FW_NOFILE   -1

Definition at line 7 of file firmware.c.

Referenced by cmd_fwupdate(), and fwupdate().

#define FW_OK   0

Definition at line 6 of file firmware.c.

Referenced by cmd_fwupdate(), and fwupdate().

#define FW_USBFAIL   -3

Definition at line 9 of file firmware.c.

Referenced by cmd_fwupdate(), and fwupdate().

#define FW_WRONGDEV   -2

Definition at line 8 of file firmware.c.

Referenced by cmd_fwupdate(), and fwupdate().

Function Documentation

int cmd_fwupdate ( usbdevice kb,
usbmode dummy1,
int  nnumber,
int  dummy2,
const char *  path 
)

Definition at line 154 of file firmware.c.

References FEAT_FWUPDATE, FW_NOFILE, FW_OK, FW_USBFAIL, FW_WRONGDEV, fwupdate(), HAS_FEATURES, nprintf(), and usb_tryreset().

154  {
155  (void)dummy1;
156  (void)dummy2;
157 
158  if(!HAS_FEATURES(kb, FEAT_FWUPDATE))
159  return 0;
160  // Update the firmware
161  int ret = fwupdate(kb, path, nnumber);
162  while(ret == FW_USBFAIL){
163  // Try to reset the device if it fails
164  if(usb_tryreset(kb))
165  break;
166  ret = fwupdate(kb, path, nnumber);
167  }
168  switch(ret){
169  case FW_OK:
170  nprintf(kb, nnumber, 0, "fwupdate %s ok\n", path);
171  break;
172  case FW_NOFILE:
173  case FW_WRONGDEV:
174  nprintf(kb, nnumber, 0, "fwupdate %s invalid\n", path);
175  break;
176  case FW_USBFAIL:
177  nprintf(kb, nnumber, 0, "fwupdate %s fail\n", path);
178  return -1;
179  }
180  return 0;
181 }
void nprintf(usbdevice *kb, int nodenumber, usbmode *mode, const char *format,...)
Definition: notify.c:8
int usb_tryreset(usbdevice *kb)
Definition: usb.c:475
#define FW_WRONGDEV
Definition: firmware.c:8
#define FW_NOFILE
Definition: firmware.c:7
#define FW_USBFAIL
Definition: firmware.c:9
#define FW_OK
Definition: firmware.c:6
#define HAS_FEATURES(kb, feat)
Definition: structures.h:157
int fwupdate(usbdevice *kb, const char *path, int nnumber)
Definition: firmware.c:55
#define FEAT_FWUPDATE
Definition: structures.h:143

+ Here is the call graph for this function:

int fwupdate ( usbdevice kb,
const char *  path,
int  nnumber 
)

Definition at line 55 of file firmware.c.

References ckb_err, ckb_info, FW_MAXSIZE, FW_NOFILE, FW_OK, FW_USBFAIL, FW_WRONGDEV, usbdevice::fwversion, mkfwnode(), MSG_SIZE, nprintf(), usbdevice::product, usbdevice::usbdelay, usbsend, and usbdevice::vendor.

Referenced by cmd_fwupdate().

55  {
56  // Read the firmware from the given path
57  char* fwdata = calloc(1, FW_MAXSIZE + 256);
58  int fd = open(path, O_RDONLY);
59  if(fd == -1){
60  ckb_err("Failed to open firmware file %s: %s\n", path, strerror(errno));
61  return FW_NOFILE;
62  }
63  ssize_t length = read(fd, fwdata, FW_MAXSIZE + 1);
64  if(length <= 0x108 || length > FW_MAXSIZE){
65  ckb_err("Failed to read firmware file %s: %s\n", path, length <= 0 ? strerror(errno) : "Wrong size");
66  close(fd);
67  return FW_NOFILE;
68  }
69  close(fd);
70 
71  short vendor, product, version;
72  // Copy the vendor ID, product ID, and version from the firmware file
73  memcpy(&vendor, fwdata + 0x102, 2);
74  memcpy(&product, fwdata + 0x104, 2);
75  memcpy(&version, fwdata + 0x106, 2);
76  // Check against the actual device
77  if(vendor != kb->vendor || product != kb->product){
78  ckb_err("Firmware file %s doesn't match device (V: %04x P: %04x)\n", path, vendor, product);
79  return FW_WRONGDEV;
80  }
81  ckb_info("Loading firmware version %04x from %s\n", version, path);
82  nprintf(kb, nnumber, 0, "fwupdate %s 0/%d\n", path, (int)length);
83  // Force the device to 10ms delay (we need to deliver packets very slowly to make sure it doesn't get overwhelmed)
84  kb->usbdelay = 10;
85  // Send the firmware messages (256 bytes at a time)
86  uchar data_pkt[7][MSG_SIZE] = {
87  { 0x07, 0x0c, 0xf0, 0x01, 0 },
88  { 0x07, 0x0d, 0xf0, 0 },
89  { 0x7f, 0x01, 0x3c, 0 },
90  { 0x7f, 0x02, 0x3c, 0 },
91  { 0x7f, 0x03, 0x3c, 0 },
92  { 0x7f, 0x04, 0x3c, 0 },
93  { 0x7f, 0x05, 0x10, 0 }
94  };
95  int output = 0, last = 0;
96  int index = 0;
97  while(output < length){
98  int npackets = 1;
99  // Packet 1: data position
100  data_pkt[1][6] = index++;
101  while(output < length){
102  npackets++;
103  if(npackets != 6){
104  // Packets 2-5: 60 bytes of data
105  memcpy(data_pkt[npackets] + 4, fwdata + output, 60);
106  last = output;
107  output += 60;
108  } else {
109  // Packet 6: 16 bytes
110  memcpy(data_pkt[npackets] + 4, fwdata + output, 16);
111  last = output;
112  output += 16;
113  break;
114  }
115  }
116  if(index == 1){
117  if(!usbsend(kb, data_pkt[0], 1)){
118  ckb_err("Firmware update failed\n");
119  return FW_USBFAIL;
120  }
121  // The above packet can take a lot longer to process, so wait for a while
122  sleep(3);
123  if(!usbsend(kb, data_pkt[2], npackets - 1)){
124  ckb_err("Firmware update failed\n");
125  return FW_USBFAIL;
126  }
127  } else {
128  // If the output ends here, set the length byte appropriately
129  if(output >= length)
130  data_pkt[npackets][2] = length - last;
131  if(!usbsend(kb, data_pkt[1], npackets)){
132  ckb_err("Firmware update failed\n");
133  return FW_USBFAIL;
134  }
135  }
136  nprintf(kb, nnumber, 0, "fwupdate %s %d/%d\n", path, output, (int)length);
137  }
138  // Send the final pair of messages
139  uchar data_pkt2[2][MSG_SIZE] = {
140  { 0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, index },
141  { 0x07, 0x02, 0xf0, 0 }
142  };
143  if(!usbsend(kb, data_pkt2[0], 2)){
144  ckb_err("Firmware update failed\n");
145  return FW_USBFAIL;
146  }
147  // Updated successfully
148  kb->fwversion = version;
149  mkfwnode(kb);
150  ckb_info("Firmware update complete\n");
151  return FW_OK;
152 }
void nprintf(usbdevice *kb, int nodenumber, usbmode *mode, const char *format,...)
Definition: notify.c:8
#define MSG_SIZE
Definition: structures.h:176
#define FW_WRONGDEV
Definition: firmware.c:8
#define FW_NOFILE
Definition: firmware.c:7
#define ckb_err(fmt, args...)
Definition: includes.h:49
ushort fwversion
Definition: structures.h:239
int mkfwnode(usbdevice *kb)
Writes a keyboard's firmware version and poll rate to its device node.
Definition: devnode.c:299
#define FW_USBFAIL
Definition: firmware.c:9
unsigned char uchar
Definition: includes.h:24
#define FW_OK
Definition: firmware.c:6
#define ckb_info(fmt, args...)
Definition: includes.h:55
short product
Definition: structures.h:237
#define FW_MAXSIZE
Definition: firmware.c:51
char usbdelay
Definition: structures.h:243
#define usbsend(kb, messages, count)
usbsend macro is used to wrap _usbsend() with debugging information (file and lineno) ...
Definition: usb.h:271
short vendor
Definition: structures.h:237

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int getfwversion ( usbdevice kb)

Definition at line 11 of file firmware.c.

References ckb_err, ckb_warn, FEAT_POLLRATE, usbdevice::features, usbdevice::fwversion, MSG_SIZE, usbdevice::pollrate, usbdevice::product, usbrecv, and usbdevice::vendor.

Referenced by _start_dev().

11  {
12  // Ask board for firmware info
13  uchar data_pkt[MSG_SIZE] = { 0x0e, 0x01, 0 };
14  uchar in_pkt[MSG_SIZE];
15  if(!usbrecv(kb, data_pkt, in_pkt))
16  return -1;
17  if(in_pkt[0] != 0x0e || in_pkt[1] != 0x01){
18  ckb_err("Bad input header\n");
19  return -1;
20  }
21  short vendor, product, version, bootloader;
22  // Copy the vendor ID, product ID, version, and poll rate from the firmware data
23  memcpy(&version, in_pkt + 8, 2);
24  memcpy(&bootloader, in_pkt + 10, 2);
25  memcpy(&vendor, in_pkt + 12, 2);
26  memcpy(&product, in_pkt + 14, 2);
27  char poll = in_pkt[16];
28  if(poll <= 0){
29  poll = -1;
30  kb->features &= ~FEAT_POLLRATE;
31  }
32  // Print a warning if the message didn't match the expected data
33  if(vendor != kb->vendor)
34  ckb_warn("Got vendor ID %04x (expected %04x)\n", vendor, kb->vendor);
35  if(product != kb->product)
36  ckb_warn("Got product ID %04x (expected %04x)\n", product, kb->product);
37  // Set firmware version and poll rate
38  if(version == 0 || bootloader == 0){
39  // Needs firmware update
40  kb->fwversion = 0;
41  kb->pollrate = -1;
42  } else {
43  if(version != kb->fwversion && kb->fwversion != 0)
44  ckb_warn("Got firmware version %04x (expected %04x)\n", version, kb->fwversion);
45  kb->fwversion = version;
46  kb->pollrate = poll;
47  }
48  return 0;
49 }
#define MSG_SIZE
Definition: structures.h:176
#define ckb_err(fmt, args...)
Definition: includes.h:49
ushort fwversion
Definition: structures.h:239
unsigned char uchar
Definition: includes.h:24
#define ckb_warn(fmt, args...)
Definition: includes.h:52
short product
Definition: structures.h:237
char pollrate
Definition: structures.h:241
ushort features
Definition: structures.h:229
#define usbrecv(kb, out_msg, in_msg)
usbrecv macro is used to wrap _usbrecv() with debugging information (file and lineno) ...
Definition: usb.h:288
short vendor
Definition: structures.h:237
#define FEAT_POLLRATE
Definition: structures.h:138

+ Here is the caller graph for this function: