#include <sys/cdefs.h>
#ifdef __RCSID
__RCSID("$NetBSD: putflash.c,v 1.4 2025/11/29 18:39:15 brad Exp $");
#endif
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include <dev/usb/umcpmio_hid_reports.h>
#include <dev/usb/umcpmio_io.h>
#include <sys/ioctl.h>
#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");
}
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");
}
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");
}
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");
}
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;
}