/* $NetBSD: putflash.c,v 1.4 2025/11/29 18:39:15 brad Exp $ */ /* * Copyright (c) 2024 Brad Spencer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #ifdef __RCSID __RCSID("$NetBSD: putflash.c,v 1.4 2025/11/29 18:39:15 brad Exp $"); #endif /* Functions to parse stuff */ #include #include #include #include #include #include #include #include #undef EXTERN #define EXTERN #include "putflash.h" int mcp2221_parse_flash_gp_req(int fd, struct mcp2221_put_flash_req *req, char *argv[], int start, int end, bool debug) { int error = 0; struct umcpmio_ioctl_get_flash current_flash; int arggood = false; current_flash.subcode = MCP2221_FLASH_SUBCODE_GP; error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); if (debug) fprintf(stderr, "CURRENT FLASH: error=%d\n", error); if (!error) { int argcount = start; uint8_t *gp; uint8_t *bbuf = ¤t_flash.res.get_blob[0]; if (debug) { fprintf(stderr, "CURRENT REQ:\n"); for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ fprintf(stderr, "%02x ", bbuf[i]); } fprintf(stderr, "\n"); } /* When flash is put, you put ALL of a particular subcode, so * you have to do a get + put */ req->u.gp.gp0_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp0_settings; req->u.gp.gp1_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp1_settings; req->u.gp.gp2_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp2_settings; req->u.gp.gp3_settings = current_flash.res.mcp2221_get_flash_res.u.gp.gp3_settings; if (debug) 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); while (argcount < end) { gp = NULL; if (strncmp(argv[argcount], "GP0", 4) == 0) { gp = (uint8_t *) & req->u.gp.gp0_settings; } if (strncmp(argv[argcount], "GP1", 4) == 0) { gp = (uint8_t *) & req->u.gp.gp1_settings; } if (strncmp(argv[argcount], "GP2", 4) == 0) { gp = (uint8_t *) & req->u.gp.gp2_settings; } if (strncmp(argv[argcount], "GP3", 4) == 0) { gp = (uint8_t *) & req->u.gp.gp3_settings; } if (gp == NULL) { if (debug) fprintf(stderr, "NOT GPn: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } argcount++; if (argcount < end) { arggood = false; if (strncmp(argv[argcount], "GPIO_PIN_INPUT", 15) == 0) { *gp &= MCP2221_FLASH_GPIO_VALUE_MASK; *gp |= MCP2221_FLASH_GPIO_INPUT; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_OUTPUT", 16) == 0) { *gp &= MCP2221_FLASH_GPIO_VALUE_MASK; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT0", 14) == 0) { *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; *gp |= MCP2221_FLASH_PIN_IS_ALT0; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT1", 14) == 0) { *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; *gp |= MCP2221_FLASH_PIN_IS_ALT1; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT2", 14) == 0) { *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; *gp |= MCP2221_FLASH_PIN_IS_ALT2; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT3", 14) == 0) { *gp &= (MCP2221_FLASH_GPIO_VALUE_MASK | MCP2221_FLASH_GPIO_INPUT); *gp &= ~MCP2221_FLASH_PIN_TYPE_MASK; *gp |= MCP2221_FLASH_PIN_IS_DED; arggood = true; } if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ZERO", 20) == 0) { *gp &= ~MCP2221_FLASH_GPIO_VALUE_MASK; arggood = true; } if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ONE", 19) == 0) { *gp |= MCP2221_FLASH_GPIO_VALUE_MASK; arggood = true; } if (!arggood) { if (debug) fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } } else { error = EINVAL; } argcount++; } } return (error); } int mcp2210_parse_flash_gp_req(int fd, struct mcp2210_set_nvram_req *req, char *argv[], int start, int end, bool debug) { int error = 0; struct umcpmio_ioctl_get_flash current_flash; int arggood = false; current_flash.subcode = MCP2210_NVRAM_SUBCODE_CS; error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); if (debug) fprintf(stderr, "CURRENT FLASH: error=%d\n", error); if (!error) { int argcount = start; uint8_t *gp; uint8_t *bbuf = ¤t_flash.res.get_blob[0]; if (debug) { fprintf(stderr, "CURRENT REQ:\n"); for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ fprintf(stderr, "%02x ", bbuf[i]); } fprintf(stderr, "\n"); } /* This needs to be a read / modify / write sort of thing */ memset(req, 0, MCP2210_REQ_BUFFER_SIZE); memcpy(&req->u.cs.gp0_designation, ¤t_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation, ¤t_flash.res.mcp2210_get_nvram_res.u.cs.nvram_protection - ¤t_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation + 1); if (debug) fprintf(stderr, "CURRENT FLASH: DESIGNATION: %02x %02x %02x %02x %02x %02x %02x %02x %02x" "- DIRECTION: %02x %02x - VALUE: %02x %02x - OTHER_SETTINGS: %02x\n", current_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp1_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp2_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp3_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp4_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp5_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp6_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp7_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.gp8_designation, current_flash.res.mcp2210_get_nvram_res.u.cs.default_direction_lsb, current_flash.res.mcp2210_get_nvram_res.u.cs.default_direction_msb, current_flash.res.mcp2210_get_nvram_res.u.cs.default_output_lsb, current_flash.res.mcp2210_get_nvram_res.u.cs.default_output_msb, current_flash.res.mcp2210_get_nvram_res.u.cs.other_settings); int pin; while (argcount < end) { gp = NULL; pin = -1; if (strncmp(argv[argcount], "GP0", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp0_designation; pin = 0; } if (strncmp(argv[argcount], "GP1", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp1_designation; pin = 1; } if (strncmp(argv[argcount], "GP2", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp2_designation; pin = 2; } if (strncmp(argv[argcount], "GP3", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp3_designation; pin = 3; } if (strncmp(argv[argcount], "GP4", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp4_designation; pin = 4; } if (strncmp(argv[argcount], "GP5", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp5_designation; pin = 5; } if (strncmp(argv[argcount], "GP6", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp6_designation; pin = 6; } if (strncmp(argv[argcount], "GP7", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp7_designation; pin = 7; } if (strncmp(argv[argcount], "GP8", 4) == 0) { gp = (uint8_t *) & req->u.cs.gp8_designation; pin = 8; } if (gp == NULL) { if (debug) fprintf(stderr, "NOT GPn: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } argcount++; if (argcount < end) { arggood = false; if (strncmp(argv[argcount], "GPIO_PIN_INPUT", 15) == 0) { *gp = MCP2210_PIN_IS_GPIO; if (pin < 8) { req->u.cs.default_direction_lsb |= (1 << pin); } arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_OUTPUT", 16) == 0) { *gp = MCP2210_PIN_IS_GPIO; if (pin < 8) { req->u.cs.default_direction_lsb &= ~(1 << pin); } arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT0", 14) == 0) { *gp = MCP2210_PIN_IS_ALT0; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT3", 14) == 0) { *gp = MCP2210_PIN_IS_DED; req->u.cs.other_settings &= 0xf1; req->u.cs.other_settings |= MCP2210_COUNTER_FALLING_EDGE << 1; arggood = true; } if (pin == 6) { if (strncmp(argv[argcount], "GPIO_PIN_ALT4", 14) == 0) { *gp = MCP2210_PIN_IS_DED; req->u.cs.other_settings &= 0xf1; req->u.cs.other_settings |= MCP2210_COUNTER_RISING_EDGE << 1; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT5", 14) == 0) { *gp = MCP2210_PIN_IS_DED; req->u.cs.other_settings &= 0xf1; req->u.cs.other_settings |= MCP2210_COUNTER_LOW_PULSE << 1; arggood = true; } if (strncmp(argv[argcount], "GPIO_PIN_ALT6", 14) == 0) { *gp = MCP2210_PIN_IS_DED; req->u.cs.other_settings &= 0xf1; req->u.cs.other_settings |= MCP2210_COUNTER_HIGH_PULSE << 1; arggood = true; } } if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ZERO", 20) == 0) { if (pin < 8) { req->u.cs.default_output_lsb &= ~(1 << pin); } arggood = true; } if (strncmp(argv[argcount], "DEFAULT_OUTPUT_ONE", 19) == 0) { if (pin < 8) { req->u.cs.default_output_lsb |= (1 << pin); } arggood = true; } if (!arggood) { if (debug) fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } } else { error = EINVAL; } argcount++; } } return (error); } int mcp2210_parse_flash_spi_req(int fd, struct mcp2210_set_nvram_req *req, char *argv[], int start, int end, bool debug) { int error = 0; struct umcpmio_ioctl_get_flash current_flash; current_flash.subcode = MCP2210_NVRAM_SUBCODE_SPI; error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); if (debug) fprintf(stderr, "CURRENT FLASH: error=%d\n", error); if (!error) { int argcount = start; uint8_t *p_lsb; uint8_t *p_msb; uint8_t *bbuf = ¤t_flash.res.get_blob[0]; if (debug) { fprintf(stderr, "CURRENT REQ:\n"); for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ fprintf(stderr, "%02x ", bbuf[i]); } fprintf(stderr, "\n"); } /* This needs to be a read / modify / write sort of thing */ memcpy(req, ¤t_flash.res, MCP2210_REQ_BUFFER_SIZE); while (argcount < end) { p_lsb = p_msb = NULL; if (strncmp(argv[argcount], "CS_TO_DATA_DELAY", 17) == 0) { p_lsb = (uint8_t *) & req->u.spi.cs_to_data_delay_lsb; p_msb = (uint8_t *) & req->u.spi.cs_to_data_delay_msb; } if (strncmp(argv[argcount], "LAST_BYTE_TO_CS_DELAY", 22) == 0) { p_lsb = (uint8_t *) & req->u.spi.lb_to_cs_deassert_delay_lsb; p_msb = (uint8_t *) & req->u.spi.lb_to_cs_deassert_delay_msb; } if (strncmp(argv[argcount], "DELAY_BETWEEN_BYTES", 20) == 0) { p_lsb = (uint8_t *) & req->u.spi.delay_between_bytes_lsb; p_msb = (uint8_t *) & req->u.spi.delay_between_bytes_msb; } if (p_lsb == NULL) { if (debug) fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } argcount++; if (argcount < end) { uint16_t v; v = (uint16_t) strtoi(argv[argcount], NULL, 0, 0, 0xffff, &error); if (error) { if (debug) fprintf(stderr, "BAD CONVERSION OF uint16_t: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } *p_lsb = (uint8_t)(v & 0x00ff); *p_msb = (uint8_t)((v >> 8) & 0x00ff); } else { error = EINVAL; } argcount++; } } return error; } int mcp2210_parse_flash_usbkeyparams_req(int fd, struct mcp2210_set_nvram_req *req, char *argv[], int start, int end, bool debug) { int error = 0; struct umcpmio_ioctl_get_flash current_flash; current_flash.subcode = MCP2210_NVRAM_SUBCODE_USBKEYPARAMS; error = ioctl(fd, UMCPMIO_GET_FLASH, ¤t_flash); if (debug) fprintf(stderr, "CURRENT FLASH: error=%d\n", error); if (!error) { int argcount = start; uint8_t *bbuf = ¤t_flash.res.get_blob[0]; if (debug) { fprintf(stderr, "CURRENT REQ:\n"); for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ fprintf(stderr, "%02x ", bbuf[i]); } fprintf(stderr, "\n"); } /* This needs to be a read / modify / write sort of thing */ memset(req, 0, MCP2210_REQ_BUFFER_SIZE); req->u.usbkeyparams.usb_power_attributes = current_flash.res.mcp2210_get_nvram_res.u.usbkeyparams.usb_power_attributes; req->u.usbkeyparams.usb_requested_ma = current_flash.res.mcp2210_get_nvram_res.u.usbkeyparams.usb_requested_ma; bbuf = &req->cmd; if (debug) { fprintf(stderr, "COPY REQ:\n"); for (int i = 0; i < MCP2221_RES_BUFFER_SIZE; i++){ fprintf(stderr, "%02x ", bbuf[i]); } fprintf(stderr, "\n"); } bool powered = false; bool ma = false; while (argcount < end) { powered = ma = false; if (strncmp(argv[argcount], "POWERED", 8) == 0) { powered = true; } if (strncmp(argv[argcount], "MA", 3) == 0) { ma = true; } if (powered == false && ma == false) { if (debug) fprintf(stderr, "BAD ARGUMENT: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } argcount++; if (argcount < end) { if (powered) { uint8_t power_type = 0; if (strncmp(argv[argcount], "SELF", 5) == 0) { power_type = MCP2210_USBPOWER_SELF; } if (strncmp(argv[argcount], "BUS", 4) == 0) { power_type = MCP2210_USBPOWER_BUSS; } if (power_type == 0) { if (debug) fprintf(stderr, "BAD ARGUMENT: %s\n", argv[argcount]); error = EINVAL; break; } if (debug) fprintf(stderr, "REQUESTED power_type=%02x\n", power_type); req->u.usbkeyparams.usb_power_attributes &= ~(MCP2210_USBPOWER_SELF | MCP2210_USBPOWER_BUSS); req->u.usbkeyparams.usb_power_attributes |= power_type; } if (ma) { uint16_t power_ma = 0; uint8_t pm; power_ma = (uint16_t) strtoi(argv[argcount], NULL, 0, 1, 511, &error); if (error) { if (debug) fprintf(stderr, "BAD CONVERSION OF MA 1 - 511: %d %s\n", argcount, argv[argcount]); error = EINVAL; break; } if (debug) fprintf(stderr, "REQUESTED power_ma=%d\n", power_ma); pm = (uint8_t)(power_ma / 2); if (pm == 0) pm = 1; req->u.usbkeyparams.usb_requested_ma = pm; } } else { error = EINVAL; } argcount++; } } return error; }