1 /* $NetBSD: putflash.c,v 1.4 2025/11/29 18:39:15 brad Exp $ */ 2 3 /* 4 * Copyright (c) 2024 Brad Spencer <brad (at) anduin.eldar.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 #ifdef __RCSID 21 __RCSID("$NetBSD: putflash.c,v 1.4 2025/11/29 18:39:15 brad Exp $"); 22 #endif 23 24 /* Functions to parse stuff */ 25 26 #include <stdio.h> 27 #include <errno.h> 28 #include <string.h> 29 #include <stdbool.h> 30 #include <inttypes.h> 31 32 #include <dev/usb/umcpmio_hid_reports.h> 33 #include <dev/usb/umcpmio_io.h> 34 #include <sys/ioctl.h> 35 36 #undef EXTERN 37 #define EXTERN 38 #include "putflash.h" 39 40 41 int 42 mcp2221_parse_flash_gp_req(int fd, struct mcp2221_put_flash_req *req, char *argv[], int start, int end, bool debug) 43 { 44 int error = 0; 45 struct umcpmio_ioctl_get_flash current_flash; 46 int arggood = false; 47 48 current_flash.subcode = MCP2221_FLASH_SUBCODE_GP; 49 error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); 50 51 if (debug) 52 fprintf(stderr, "CURRENT FLASH: error=%d\n", error); 53 54 if (!error) { 55 int argcount = start; 56 uint8_t *gp; 57 58 uint8_t *bbuf = ¤t_flash.res.get_blob[0]; 59 if (debug) { 60 fprintf(stderr, "CURRENT REQ:\n"); 61 for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ 62 fprintf(stderr, "%02x ", bbuf[i]); 63 } 64 fprintf(stderr, "\n"); 65 } 66 67 /* When flash is put, you put ALL of a particular subcode, so 68 * you have to do a get + put */ 69 req->u.gp.gp0_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp0_settings; 70 req->u.gp.gp1_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp1_settings; 71 req->u.gp.gp2_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp2_settings; 72 req->u.gp.gp3_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp3_settings; 73 74 if (debug) 75 fprintf(stderr, "CURRENT FLASH: %02x %02x %02x %02x\n", current_flash.res.mcp2221_get_flash_res.u.gp.gp0_settings, current_flash.res.mcp2221_get_flash_res.u.gp.gp1_settings, current_flash.res.mcp2221_get_flash_res.u.gp.gp2_settings, current_flash.res.mcp2221_get_flash_res.u.gp.gp3_settings); 76 77 while (argcount < end) { 78 gp = NULL; 79 if (strncmp(argv[argcount], "GP0", 4) == 0) { 80 gp = (uint8_t *) & req->u.gp.gp0_settings; 81 } 82 if (strncmp(argv[argcount], "GP1", 4) == 0) { 83 gp = (uint8_t *) & req->u.gp.gp1_settings; 84 } 85 if (strncmp(argv[argcount], "GP2", 4) == 0) { 86 gp = (uint8_t *) & req->u.gp.gp2_settings; 87 } 88 if (strncmp(argv[argcount], "GP3", 4) == 0) { 89 gp = (uint8_t *) & req->u.gp.gp3_settings; 90 } 91 if (gp == NULL) { 92 if (debug) 93 fprintf(stderr, "NOT GPn: %d %s\n", argcount, argv[argcount]); 94 error = EINVAL; 95 break; 96 } 97 argcount++; 98 if (argcount < end) { 99 arggood = false; 100 if (strncmp(argv[argcount], "GPIO_PIN_INPUT", 15) == 0) { 101 *gp &= MCP2221_FLASH_GPIO_VALUE_MASK; 102 *gp |= MCP2221_FLASH_GPIO_INPUT; 103 arggood = true; 104 } 105 if (strncmp(argv[argcount], "GPIO_PIN_OUTPUT", 16) == 0) { 106 *gp &= MCP2221_FLASH_GPIO_VALUE_MASK; 107 arggood = true; 108 } 109 if (strncmp(argv[argcount], "GPIO_PIN_ALT0", 14) == 0) { 110 *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); 111 *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; 112 *gp |= MCP2221_FLASH_PIN_IS_ALT0; 113 arggood = true; 114 } 115 if (strncmp(argv[argcount], "GPIO_PIN_ALT1", 14) == 0) { 116 *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); 117 *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; 118 *gp |= MCP2221_FLASH_PIN_IS_ALT1; 119 arggood = true; 120 } 121 if (strncmp(argv[argcount], "GPIO_PIN_ALT2", 14) == 0) { 122 *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); 123 *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; 124 *gp |= MCP2221_FLASH_PIN_IS_ALT2; 125 arggood = true; 126 } 127 if (strncmp(argv[argcount], "GPIO_PIN_ALT3", 14) == 0) { 128 *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); 129 *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; 130 *gp |= MCP2221_FLASH_PIN_IS_DED; 131 arggood = true; 132 } 133 if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ZERO", 20) == 0) { 134 *gp &= ~MCP2221_FLASH_GPIO_VALUE_MASK; 135 arggood = true; 136 } 137 if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ONE", 19) == 0) { 138 *gp |= MCP2221_FLASH_GPIO_VALUE_MASK; 139 arggood = true; 140 } 141 if (!arggood) { 142 if (debug) 143 fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); 144 error = EINVAL; 145 break; 146 } 147 } else { 148 error = EINVAL; 149 } 150 151 argcount++; 152 } 153 } 154 return (error); 155 } 156 157 int 158 mcp2210_parse_flash_gp_req(int fd, struct mcp2210_set_nvram_req *req, char *argv[], int start, int end, bool debug) 159 { 160 int error = 0; 161 struct umcpmio_ioctl_get_flash current_flash; 162 int arggood = false; 163 164 current_flash.subcode = MCP2210_NVRAM_SUBCODE_CS; 165 error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); 166 167 if (debug) 168 fprintf(stderr, "CURRENT FLASH: error=%d\n", error); 169 170 if (!error) { 171 int argcount = start; 172 uint8_t *gp; 173 174 uint8_t *bbuf = ¤t_flash.res.get_blob[0]; 175 if (debug) { 176 fprintf(stderr, "CURRENT REQ:\n"); 177 for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ 178 fprintf(stderr, "%02x ", bbuf[i]); 179 } 180 fprintf(stderr, "\n"); 181 } 182 183 /* This needs to be a read / modify / write sort of thing */ 184 memset(req, 0, MCP2210_REQ_BUFFER_SIZE); 185 memcpy(&req->u.cs.gp0_designation, 186 ¤t_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation, 187 ¤t_flash.res.mcp2210_get_nvram_res.u.cs.nvram_protection - 188 ¤t_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation + 1); 189 190 if (debug) 191 fprintf(stderr, "CURRENT FLASH: DESIGNATION: %02x %02x %02x %02x %02x %02x %02x %02x %02x" 192 "- DIRECTION: %02x %02x - VALUE: %02x %02x - OTHER_SETTINGS: %02x\n", 193 current_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation, 194 current_flash.res.mcp2210_get_nvram_res.u.cs.gp1_designation, 195 current_flash.res.mcp2210_get_nvram_res.u.cs.gp2_designation, 196 current_flash.res.mcp2210_get_nvram_res.u.cs.gp3_designation, 197 current_flash.res.mcp2210_get_nvram_res.u.cs.gp4_designation, 198 current_flash.res.mcp2210_get_nvram_res.u.cs.gp5_designation, 199 current_flash.res.mcp2210_get_nvram_res.u.cs.gp6_designation, 200 current_flash.res.mcp2210_get_nvram_res.u.cs.gp7_designation, 201 current_flash.res.mcp2210_get_nvram_res.u.cs.gp8_designation, 202 current_flash.res.mcp2210_get_nvram_res.u.cs.default_direction_lsb, 203 current_flash.res.mcp2210_get_nvram_res.u.cs.default_direction_msb, 204 current_flash.res.mcp2210_get_nvram_res.u.cs.default_output_lsb, 205 current_flash.res.mcp2210_get_nvram_res.u.cs.default_output_msb, 206 current_flash.res.mcp2210_get_nvram_res.u.cs.other_settings); 207 208 int pin; 209 while (argcount < end) { 210 gp = NULL; 211 pin = -1; 212 if (strncmp(argv[argcount], "GP0", 4) == 0) { 213 gp = (uint8_t *) & req->u.cs.gp0_designation; 214 pin = 0; 215 } 216 if (strncmp(argv[argcount], "GP1", 4) == 0) { 217 gp = (uint8_t *) & req->u.cs.gp1_designation; 218 pin = 1; 219 } 220 if (strncmp(argv[argcount], "GP2", 4) == 0) { 221 gp = (uint8_t *) & req->u.cs.gp2_designation; 222 pin = 2; 223 } 224 if (strncmp(argv[argcount], "GP3", 4) == 0) { 225 gp = (uint8_t *) & req->u.cs.gp3_designation; 226 pin = 3; 227 } 228 if (strncmp(argv[argcount], "GP4", 4) == 0) { 229 gp = (uint8_t *) & req->u.cs.gp4_designation; 230 pin = 4; 231 } 232 if (strncmp(argv[argcount], "GP5", 4) == 0) { 233 gp = (uint8_t *) & req->u.cs.gp5_designation; 234 pin = 5; 235 } 236 if (strncmp(argv[argcount], "GP6", 4) == 0) { 237 gp = (uint8_t *) & req->u.cs.gp6_designation; 238 pin = 6; 239 } 240 if (strncmp(argv[argcount], "GP7", 4) == 0) { 241 gp = (uint8_t *) & req->u.cs.gp7_designation; 242 pin = 7; 243 } 244 if (strncmp(argv[argcount], "GP8", 4) == 0) { 245 gp = (uint8_t *) & req->u.cs.gp8_designation; 246 pin = 8; 247 } 248 if (gp == NULL) { 249 if (debug) 250 fprintf(stderr, "NOT GPn: %d %s\n", argcount, argv[argcount]); 251 error = EINVAL; 252 break; 253 } 254 argcount++; 255 if (argcount < end) { 256 arggood = false; 257 if (strncmp(argv[argcount], "GPIO_PIN_INPUT", 15) == 0) { 258 *gp = MCP2210_PIN_IS_GPIO; 259 if (pin < 8) { 260 req->u.cs.default_direction_lsb |= (1 << pin); 261 } 262 arggood = true; 263 } 264 if (strncmp(argv[argcount], "GPIO_PIN_OUTPUT", 16) == 0) { 265 *gp = MCP2210_PIN_IS_GPIO; 266 if (pin < 8) { 267 req->u.cs.default_direction_lsb &= ~(1 << pin); 268 } 269 arggood = true; 270 } 271 if (strncmp(argv[argcount], "GPIO_PIN_ALT0", 14) == 0) { 272 *gp = MCP2210_PIN_IS_ALT0; 273 arggood = true; 274 } 275 if (strncmp(argv[argcount], "GPIO_PIN_ALT3", 14) == 0) { 276 *gp = MCP2210_PIN_IS_DED; 277 req->u.cs.other_settings &= 0xf1; 278 req->u.cs.other_settings |= MCP2210_COUNTER_FALLING_EDGE << 1; 279 arggood = true; 280 } 281 if (pin == 6) { 282 if (strncmp(argv[argcount], "GPIO_PIN_ALT4", 14) == 0) { 283 *gp = MCP2210_PIN_IS_DED; 284 req->u.cs.other_settings &= 0xf1; 285 req->u.cs.other_settings |= MCP2210_COUNTER_RISING_EDGE << 1; 286 arggood = true; 287 } 288 if (strncmp(argv[argcount], "GPIO_PIN_ALT5", 14) == 0) { 289 *gp = MCP2210_PIN_IS_DED; 290 req->u.cs.other_settings &= 0xf1; 291 req->u.cs.other_settings |= MCP2210_COUNTER_LOW_PULSE << 1; 292 arggood = true; 293 } 294 if (strncmp(argv[argcount], "GPIO_PIN_ALT6", 14) == 0) { 295 *gp = MCP2210_PIN_IS_DED; 296 req->u.cs.other_settings &= 0xf1; 297 req->u.cs.other_settings |= MCP2210_COUNTER_HIGH_PULSE << 1; 298 arggood = true; 299 } 300 } 301 if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ZERO", 20) == 0) { 302 if (pin < 8) { 303 req->u.cs.default_output_lsb &= ~(1 << pin); 304 } 305 arggood = true; 306 } 307 if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ONE", 19) == 0) { 308 if (pin < 8) { 309 req->u.cs.default_output_lsb |= (1 << pin); 310 } 311 arggood = true; 312 } 313 if (!arggood) { 314 if (debug) 315 fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); 316 error = EINVAL; 317 break; 318 } 319 } else { 320 error = EINVAL; 321 } 322 323 argcount++; 324 } 325 } 326 return (error); 327 } 328 329 int 330 mcp2210_parse_flash_spi_req(int fd, struct mcp2210_set_nvram_req *req, char *argv[], int start, int end, bool debug) 331 { 332 int error = 0; 333 struct umcpmio_ioctl_get_flash current_flash; 334 335 current_flash.subcode = MCP2210_NVRAM_SUBCODE_SPI; 336 error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); 337 338 if (debug) 339 fprintf(stderr, "CURRENT FLASH: error=%d\n", error); 340 341 if (!error) { 342 int argcount = start; 343 uint8_t *p_lsb; 344 uint8_t *p_msb; 345 346 uint8_t *bbuf = ¤t_flash.res.get_blob[0]; 347 if (debug) { 348 fprintf(stderr, "CURRENT REQ:\n"); 349 for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ 350 fprintf(stderr, "%02x ", bbuf[i]); 351 } 352 fprintf(stderr, "\n"); 353 } 354 355 /* This needs to be a read / modify / write sort of thing */ 356 memcpy(req, ¤t_flash.res, MCP2210_REQ_BUFFER_SIZE); 357 358 while (argcount < end) { 359 p_lsb = p_msb = NULL; 360 if (strncmp(argv[argcount], "CS_TO_DATA_DELAY", 17) == 0) { 361 p_lsb = (uint8_t *) & req->u.spi.cs_to_data_delay_lsb; 362 p_msb = (uint8_t *) & req->u.spi.cs_to_data_delay_msb; 363 } 364 if (strncmp(argv[argcount], "LAST_BYTE_TO_CS_DELAY", 22) == 0) { 365 p_lsb = (uint8_t *) & req->u.spi.lb_to_cs_deassert_delay_lsb; 366 p_msb = (uint8_t *) & req->u.spi.lb_to_cs_deassert_delay_msb; 367 } 368 if (strncmp(argv[argcount], "DELAY_BETWEEN_BYTES", 20) == 0) { 369 p_lsb = (uint8_t *) & req->u.spi.delay_between_bytes_lsb; 370 p_msb = (uint8_t *) & req->u.spi.delay_between_bytes_msb; 371 } 372 if (p_lsb == NULL) { 373 if (debug) 374 fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); 375 error = EINVAL; 376 break; 377 } 378 argcount++; 379 if (argcount < end) { 380 uint16_t v; 381 v = (uint16_t) strtoi(argv[argcount], NULL, 0, 0, 0xffff, &error); 382 if (error) { 383 if (debug) 384 fprintf(stderr, "BAD CONVERSION OF uint16_t: %d %s\n", argcount, argv[argcount]); 385 error = EINVAL; 386 break; 387 } 388 *p_lsb = (uint8_t)(v & 0x00ff); 389 *p_msb = (uint8_t)((v >> 8) & 0x00ff); 390 } else { 391 error = EINVAL; 392 } 393 394 argcount++; 395 } 396 } 397 return error; 398 } 399 400 int 401 mcp2210_parse_flash_usbkeyparams_req(int fd, struct mcp2210_set_nvram_req *req, char *argv[], int start, int end, bool debug) 402 { 403 int error = 0; 404 struct umcpmio_ioctl_get_flash current_flash; 405 406 current_flash.subcode = MCP2210_NVRAM_SUBCODE_USBKEYPARAMS; 407 error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); 408 409 if (debug) 410 fprintf(stderr, "CURRENT FLASH: error=%d\n", error); 411 412 if (!error) { 413 int argcount = start; 414 415 uint8_t *bbuf = ¤t_flash.res.get_blob[0]; 416 if (debug) { 417 fprintf(stderr, "CURRENT REQ:\n"); 418 for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ 419 fprintf(stderr, "%02x ", bbuf[i]); 420 } 421 fprintf(stderr, "\n"); 422 } 423 424 /* This needs to be a read / modify / write sort of thing */ 425 memset(req, 0, MCP2210_REQ_BUFFER_SIZE); 426 req->u.usbkeyparams.usb_power_attributes = 427 current_flash.res.mcp2210_get_nvram_res.u.usbkeyparams.usb_power_attributes; 428 req->u.usbkeyparams.usb_requested_ma = 429 current_flash.res.mcp2210_get_nvram_res.u.usbkeyparams.usb_requested_ma; 430 431 bbuf = &req->cmd; 432 if (debug) { 433 fprintf(stderr, "COPY REQ:\n"); 434 for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ 435 fprintf(stderr, "%02x ", bbuf[i]); 436 } 437 fprintf(stderr, "\n"); 438 } 439 bool powered = false; 440 bool ma = false; 441 while (argcount < end) { 442 powered = ma = false; 443 if (strncmp(argv[argcount], "POWERED", 8) == 0) { 444 powered = true; 445 } 446 if (strncmp(argv[argcount], "MA", 3) == 0) { 447 ma = true; 448 } 449 if (powered == false && 450 ma == false) { 451 if (debug) 452 fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); 453 error = EINVAL; 454 break; 455 } 456 argcount++; 457 if (argcount < end) { 458 if (powered) { 459 uint8_t power_type = 0; 460 if (strncmp(argv[argcount], "SELF", 5) == 0) { 461 power_type = MCP2210_USBPOWER_SELF; 462 } 463 if (strncmp(argv[argcount], "BUS", 4) == 0) { 464 power_type = MCP2210_USBPOWER_BUSS; 465 } 466 if (power_type == 0) { 467 if (debug) 468 fprintf(stderr, "BAD ARGUMENT: %s\n", argv[argcount]); 469 error = EINVAL; 470 break; 471 } 472 if (debug) 473 fprintf(stderr, "REQUESTED power_type=%02x\n", power_type); 474 req->u.usbkeyparams.usb_power_attributes &= 475 ~(MCP2210_USBPOWER_SELF | MCP2210_USBPOWER_BUSS); 476 req->u.usbkeyparams.usb_power_attributes |= power_type; 477 } 478 if (ma) { 479 uint16_t power_ma = 0; 480 uint8_t pm; 481 482 power_ma = (uint16_t) strtoi(argv[argcount], NULL, 0, 1, 511, &error); 483 if (error) { 484 if (debug) 485 fprintf(stderr, "BAD CONVERSION OF MA 1 - 511: %d %s\n", argcount, argv[argcount]); 486 error = EINVAL; 487 break; 488 } 489 if (debug) 490 fprintf(stderr, "REQUESTED power_ma=%d\n", power_ma); 491 pm = (uint8_t)(power_ma / 2); 492 if (pm == 0) 493 pm = 1; 494 req->u.usbkeyparams.usb_requested_ma = pm; 495 } 496 } else { 497 error = EINVAL; 498 } 499 500 argcount++; 501 } 502 } 503 return error; 504 } 505