Home | History | Annotate | Line # | Download | only in umcpmioctl
      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, &current_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 = &current_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, &current_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 = &current_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 		    &current_flash.res.mcp2210_get_nvram_res.u.cs.gp0_designation,
    187 		    &current_flash.res.mcp2210_get_nvram_res.u.cs.nvram_protection -
    188 		    &current_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, &current_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 = &current_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, &current_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, &current_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 = &current_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