cypress_bootloader.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Cypress bootloader driver
  3. * Firmware update support for Cypress based devices
  4. *
  5. * Copyright (C) 2009 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include "cypress_bootloader.h"
  18. #include "razer_private.h"
  19. struct cypress_command {
  20. be16_t command;
  21. uint8_t key[8];
  22. uint8_t payload[54];
  23. } _packed;
  24. #define CYPRESS_CMD_ENTERBL cpu_to_be16(0xFF38) /* Enter bootloader */
  25. #define CYPRESS_CMD_WRITEFL cpu_to_be16(0xFF39) /* Write flash */
  26. #define CYPRESS_CMD_VERIFYFL cpu_to_be16(0xFF3A) /* Verify flash */
  27. #define CYPRESS_CMD_EXITBL cpu_to_be16(0xFF3B) /* Exit bootloader */
  28. #define CYPRESS_CMD_UPCHK cpu_to_be16(0xFF3C) /* Update checksum */
  29. struct cypress_status {
  30. uint8_t status0;
  31. uint8_t status1;
  32. uint8_t _padding[62];
  33. } _packed;
  34. #define CYPRESS_STAT_BLMODE 0x20 /* Bootload mode (success) */
  35. #define CYPRESS_STAT_BOOTOK 0x01 /* Boot completed OK */
  36. #define CYPRESS_STAT_IMAGERR 0x02 /* Image verify error */
  37. #define CYPRESS_STAT_FLCHK 0x04 /* Flash checksum error */
  38. #define CYPRESS_STAT_FLPROT 0x08 /* Flash protection error */
  39. #define CYPRESS_STAT_COMCHK 0x10 /* Communication checksum error */
  40. #define CYPRESS_STAT_INVALKEY 0x40 /* Invalid bootloader key */
  41. #define CYPRESS_STAT_INVALCMD 0x80 /* Invalid command error */
  42. #define CYPRESS_STAT_ALL 0xFF
  43. static void cypress_print_one_status(int *ctx, char *buf, const char *message)
  44. {
  45. if (*ctx)
  46. strcat(buf, ", ");
  47. strcat(buf, message);
  48. (*ctx)++;
  49. }
  50. static void cypress_print_status(uint8_t status, int error)
  51. {
  52. char buf[512] = { 0, }; /* big enough for all messages */
  53. int ctx = 0;
  54. if (!(status & CYPRESS_STAT_BLMODE))
  55. cypress_print_one_status(&ctx, buf, "Not in bootloader mode");
  56. if (status & CYPRESS_STAT_IMAGERR)
  57. cypress_print_one_status(&ctx, buf, "Image verify error");
  58. if (status & CYPRESS_STAT_FLCHK)
  59. cypress_print_one_status(&ctx, buf, "Flash checksum error");
  60. if (status & CYPRESS_STAT_FLPROT)
  61. cypress_print_one_status(&ctx, buf, "Flash protection error");
  62. if (status & CYPRESS_STAT_COMCHK)
  63. cypress_print_one_status(&ctx, buf, "Communication checksum error");
  64. if (status & CYPRESS_STAT_INVALKEY)
  65. cypress_print_one_status(&ctx, buf, "Invalid bootloader key");
  66. if (status & CYPRESS_STAT_INVALCMD)
  67. cypress_print_one_status(&ctx, buf, "Invalid command");
  68. if (error)
  69. razer_error("Bootloader status: %s\n", buf);
  70. else
  71. razer_info("Bootloader status: %s\n", buf);
  72. }
  73. static void cmd_checksum(struct cypress_command *_cmd)
  74. {
  75. char *cmd = (char *)_cmd;
  76. unsigned int i, sum = 0;
  77. for (i = 0; i < 45; i++)
  78. sum += cmd[i];
  79. cmd[45] = sum & 0xFF;
  80. }
  81. static int cypress_send_command(struct cypress *c,
  82. struct cypress_command *command,
  83. size_t command_size, uint8_t status_mask)
  84. {
  85. struct cypress_status status;
  86. int err, transferred;
  87. uint8_t stat;
  88. cmd_checksum(command);
  89. razer_dump("cypress command", command, sizeof(*command));
  90. err = libusb_bulk_transfer(c->usb.h, c->ep_out,
  91. (unsigned char *)command, command_size,
  92. &transferred, RAZER_USB_TIMEOUT);
  93. if (err || transferred < 0 || (size_t)transferred != command_size) {
  94. razer_error("cypress: Failed to send command 0x%02X\n",
  95. be16_to_cpu(command->command));
  96. return -1;
  97. }
  98. razer_msleep(100);
  99. err = libusb_bulk_transfer(c->usb.h, c->ep_in,
  100. (unsigned char *)&status, sizeof(status),
  101. &transferred, RAZER_USB_TIMEOUT);
  102. if (err || transferred != sizeof(status)) {
  103. razer_error("cypress: Failed to receive status report\n");
  104. return -1;
  105. }
  106. status_mask |= CYPRESS_STAT_BLMODE; /* Always check the blmode bit */
  107. status_mask &= ~CYPRESS_STAT_BOOTOK; /* Always ignore the bootok bit */
  108. stat = (status.status0 | status.status1) & status_mask;
  109. if (stat != CYPRESS_STAT_BLMODE) {
  110. razer_error("cypress: Command 0x%04X failed with "
  111. "status0=0x%02X status1=0x%02X\n",
  112. be16_to_cpu(command->command),
  113. status.status0, status.status1);
  114. cypress_print_status(stat, 1);
  115. return -1;
  116. }
  117. return 0;
  118. }
  119. static void cypress_assign_default_key(uint8_t *key)
  120. {
  121. unsigned int i;
  122. for (i = 0; i < 8; i++)
  123. key[i] = i;
  124. }
  125. static int cypress_cmd_enterbl(struct cypress *c)
  126. {
  127. struct cypress_command cmd;
  128. memset(&cmd, 0, sizeof(cmd));
  129. cmd.command = CYPRESS_CMD_ENTERBL;
  130. c->assign_key(cmd.key);
  131. return cypress_send_command(c, &cmd, sizeof(cmd),
  132. CYPRESS_STAT_INVALKEY |
  133. CYPRESS_STAT_INVALCMD);
  134. }
  135. static int cypress_cmd_exitbl(struct cypress *c)
  136. {
  137. struct cypress_command cmd;
  138. memset(&cmd, 0, sizeof(cmd));
  139. cmd.command = CYPRESS_CMD_EXITBL;
  140. c->assign_key(cmd.key);
  141. return cypress_send_command(c, &cmd, sizeof(cmd),
  142. CYPRESS_STAT_ALL);
  143. }
  144. static int cypress_cmd_verifyfl(struct cypress *c)
  145. {
  146. struct cypress_command cmd;
  147. memset(&cmd, 0, sizeof(cmd));
  148. cmd.command = CYPRESS_CMD_VERIFYFL;
  149. c->assign_key(cmd.key);
  150. return cypress_send_command(c, &cmd, sizeof(cmd),
  151. CYPRESS_STAT_ALL);
  152. }
  153. static int cypress_cmd_updatechksum(struct cypress *c)
  154. {
  155. struct cypress_command cmd;
  156. memset(&cmd, 0, sizeof(cmd));
  157. cmd.command = CYPRESS_CMD_UPCHK;
  158. c->assign_key(cmd.key);
  159. return cypress_send_command(c, &cmd, sizeof(cmd),
  160. CYPRESS_STAT_ALL);
  161. }
  162. static int cypress_cmd_writefl(struct cypress *c, uint16_t blocknr,
  163. uint8_t segment, const char *data)
  164. {
  165. struct cypress_command cmd;
  166. memset(&cmd, 0, sizeof(cmd));
  167. cmd.command = CYPRESS_CMD_WRITEFL;
  168. c->assign_key(cmd.key);
  169. cmd.payload[0] = blocknr >> 8;
  170. cmd.payload[1] = blocknr;
  171. cmd.payload[2] = segment;
  172. memcpy(&cmd.payload[3], data, 32);
  173. return cypress_send_command(c, &cmd, sizeof(cmd),
  174. CYPRESS_STAT_ALL);
  175. }
  176. static int cypress_writeflash(struct cypress *c,
  177. const char *image, size_t len)
  178. {
  179. unsigned int block;
  180. int err;
  181. if (len % 64) {
  182. razer_error("cypress_writeflash: internal error\n");
  183. return -EINVAL;
  184. }
  185. for (block = 0; block < len / 64; block++) {
  186. /* First 32 bytes */
  187. err = cypress_cmd_writefl(c, block, 0, image);
  188. if (err) {
  189. razer_error("cypress: Failed to write image "
  190. "(block %u, segment 0)\n", block);
  191. return -EIO;
  192. }
  193. image += 32;
  194. /* Last 32 bytes */
  195. err = cypress_cmd_writefl(c, block, 1, image);
  196. if (err) {
  197. razer_error("cypress: Failed to write image "
  198. "(block %u, segment 1)\n", block);
  199. return -EIO;
  200. }
  201. image += 32;
  202. }
  203. return 0;
  204. }
  205. int cypress_open(struct cypress *c, struct libusb_device *dev,
  206. void (*assign_key)(uint8_t *key))
  207. {
  208. int err;
  209. BUILD_BUG_ON(sizeof(struct cypress_command) != 64);
  210. BUILD_BUG_ON(sizeof(struct cypress_status) != 64);
  211. return -1; //FIXME: Does not work, yet.
  212. memset(c, 0, sizeof(*c));
  213. if (!assign_key)
  214. assign_key = cypress_assign_default_key;
  215. c->assign_key = assign_key;
  216. c->usb.dev = dev;
  217. c->usb.bConfigurationValue = 1;
  218. err = razer_usb_add_used_interface(&c->usb, 0, 0);
  219. if (err)
  220. return err;
  221. err = razer_generic_usb_claim(&c->usb);
  222. if (err) {
  223. razer_error("cypress: Failed to open and claim device\n");
  224. return err;
  225. }
  226. /* EP numbers are hardcoded */
  227. c->ep_in = 0x81;
  228. c->ep_out = 0x02;
  229. return 0;
  230. }
  231. void cypress_close(struct cypress *c)
  232. {
  233. razer_generic_usb_release(&c->usb);
  234. memset(c, 0, sizeof(*c));
  235. }
  236. int cypress_upload_image(struct cypress *c,
  237. const char *image, size_t len)
  238. {
  239. int err;
  240. int result = 0;
  241. if (len % 64) {
  242. razer_error("cypress: Image size is not a multiple "
  243. "of the block size (64)\n");
  244. return -EINVAL;
  245. }
  246. razer_dump("image", image, len);
  247. err = cypress_cmd_enterbl(c);
  248. if (err) {
  249. razer_error("cypress: Failed to enter bootloader\n");
  250. result = err;
  251. goto out;
  252. }
  253. err = cypress_writeflash(c, image, len);
  254. if (err) {
  255. razer_error("cypress: Failed to write flash image\n");
  256. result = err;
  257. goto out;
  258. }
  259. err = cypress_cmd_verifyfl(c);
  260. if (err) {
  261. razer_error("cypress: Failed to verify the flash\n");
  262. result = err;
  263. goto out;
  264. }
  265. err = cypress_cmd_updatechksum(c);
  266. if (err) {
  267. razer_error("cypress: Failed to update the checksum\n");
  268. result = err;
  269. goto out;
  270. }
  271. err = cypress_cmd_exitbl(c);
  272. if (err) {
  273. razer_error("cypress: Failed to exit bootloader\n");
  274. result = err;
  275. }
  276. out:
  277. return result;
  278. }