Home | History | Annotate | Line # | Download | only in usb
      1 /*	$NetBSD: umcpmio.c,v 1.9 2025/12/12 17:49:35 andvar 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 __KERNEL_RCSID(0, "$NetBSD: umcpmio.c,v 1.9 2025/12/12 17:49:35 andvar Exp $");
     21 
     22 /*
     23  * Driver for the Microchip MCP2221 / MCP2221A USB multi-io chip
     24  *
     25  * https://www.microchip.com/en-us/product/MCP2210
     26  * https://www.microchip.com/en-us/product/MCP2221
     27  *
     28  */
     29 
     30 #ifdef _KERNEL_OPT
     31 #include "opt_usb.h"
     32 #endif
     33 
     34 #include <sys/param.h>
     35 #include <sys/types.h>
     36 
     37 #include <sys/conf.h>
     38 #include <sys/device.h>
     39 #include <sys/file.h>
     40 #include <sys/gpio.h>
     41 #include <sys/kauth.h>
     42 #include <sys/kernel.h>
     43 #include <sys/kmem.h>
     44 #include <sys/lwp.h>
     45 #include <sys/sysctl.h>
     46 #include <sys/systm.h>
     47 #include <sys/tty.h>
     48 #include <sys/vnode.h>
     49 
     50 #include <dev/usb/umcpmio.h>
     51 #include <dev/usb/umcpmio_info.h>
     52 #include <dev/usb/umcpmio_hid_reports.h>
     53 #include <dev/usb/umcpmio_io.h>
     54 #include <dev/usb/umcpmio_transport.h>
     55 #include <dev/usb/umcpmio_gpio.h>
     56 #include <dev/usb/umcpmio_spi.h>
     57 #include <dev/usb/umcpmio_iic.h>
     58 #include <dev/usb/umcpmio_subr.h>
     59 
     60 static const struct usb_devno umcpmio_devs[] = {
     61 	{USB_VENDOR_MICROCHIP, USB_PRODUCT_MICROCHIP_MCP2210},
     62 	{USB_VENDOR_MICROCHIP, USB_PRODUCT_MICROCHIP_MCP2221},
     63 };
     64 #define umcpmio_lookup(v, p) usb_lookup(umcpmio_devs, v, p)
     65 
     66 static int umcpmio_match(device_t, cfdata_t, void *);
     67 static void umcpmio_attach(device_t, device_t, void *);
     68 static int umcpmio_detach(device_t, int);
     69 static int umcpmio_activate(device_t, enum devact);
     70 static int umcpmio_verify_sysctl(SYSCTLFN_ARGS);
     71 static int mcp2221_verify_dac_sysctl(SYSCTLFN_ARGS);
     72 static int mcp2221_verify_adc_sysctl(SYSCTLFN_ARGS);
     73 static int mcp2221_verify_gpioclock_dc_sysctl(SYSCTLFN_ARGS);
     74 static int mcp2221_verify_gpioclock_cd_sysctl(SYSCTLFN_ARGS);
     75 static int mcp2210_verify_counter_sysctl(SYSCTLFN_ARGS);
     76 static int mcp2210_reset_counter_sysctl(SYSCTLFN_ARGS);
     77 
     78 #define UMCPMIO_DEBUG 1
     79 #ifdef UMCPMIO_DEBUG
     80 #define DPRINTF(x)	do { if (umcpmiodebug) printf x; } while (0)
     81 #define DPRINTFN(n, x)	do { if (umcpmiodebug > (n)) printf x; } while (0)
     82 int umcpmiodebug = 0;
     83 #else
     84 #define DPRINTF(x)	__nothing
     85 #define DPRINTFN(n, x)	__nothing
     86 #endif
     87 
     88 CFATTACH_DECL_NEW(umcpmio, sizeof(struct umcpmio_softc), umcpmio_match,
     89     umcpmio_attach, umcpmio_detach, umcpmio_activate);
     90 
     91 extern struct cfdriver umcpmio_cd;
     92 
     93 static dev_type_open(umcpmio_dev_open);
     94 static dev_type_read(umcpmio_dev_read);
     95 static dev_type_write(umcpmio_dev_write);
     96 static dev_type_close(umcpmio_dev_close);
     97 static dev_type_ioctl(umcpmio_dev_ioctl);
     98 
     99 const struct cdevsw umcpmio_cdevsw = {
    100 	.d_open = umcpmio_dev_open,
    101 	.d_close = umcpmio_dev_close,
    102 	.d_read = umcpmio_dev_read,
    103 	.d_write = umcpmio_dev_write,
    104 	.d_ioctl = umcpmio_dev_ioctl,
    105 	.d_stop = nostop,
    106 	.d_tty = notty,
    107 	.d_poll = nopoll,
    108 	.d_mmap = nommap,
    109 	.d_kqfilter = nokqfilter,
    110 	.d_discard = nodiscard,
    111 	.d_flag = D_OTHER
    112 };
    113 
    114 static const char umcpmio_valid_vrefs[] =
    115 "4.096V, 2.048V, 1.024V, OFF, VDD";
    116 
    117 static const char umcpmio_valid_dcs[] =
    118 "75%, 50%, 25%, 0%";
    119 
    120 static const char umcpmio_valid_cds[] =
    121 "375kHz, 750kHz, 1.5MHz, 3MHz, 6MHz, 12MHz, 24MHz";
    122 
    123 
    124 /* Accessing the ADC, DAC or EEPROM part of the chip */
    125 
    126 #define UMCPMIO_DEV_UNIT(m) ((m) & 0x100 ? ((m) & 0xff) : (m) & 0x80 ? ((m) & 0x7f) / 3 : (m))
    127 #define UMCPMIO_DEV_WHAT(m) ((m) & 0x100 ? EEPROM_DEV : (m) & 0x80 ? (((m) & 0x7f) % 3) + 1 : CONTROL_DEV)
    128 
    129 
    130 static int
    131 umcpmio_dev_open(dev_t dev, int flags, int fmt, struct lwp *l)
    132 {
    133 	struct umcpmio_softc *sc;
    134 	int dunit;
    135 	int pin = -1;
    136 	int error = 0;
    137 
    138 	sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
    139 	if (!sc)
    140 		return ENXIO;
    141 
    142 	dunit = UMCPMIO_DEV_WHAT(minor(dev));
    143 
    144 	if (sc->sc_dev_open[dunit]) {
    145 		DPRINTF(("umcpmio_dev_open: dunit=%d BUSY\n", dunit));
    146 		return EBUSY;
    147 	}
    148 
    149 	/* The control device only allows for ioctl calls, so pretty much allow
    150 	 * any sort of access.  For the ADC, you perform a strict O_RDONLY and
    151 	 * for the DAC a strict O_WRONLY.  It is an error to try and do a
    152 	 * O_RDWR It makes little sense to try and support select or poll.  The
    153 	 * ADC and DAC are always available for use. */
    154 	if (dunit != CONTROL_DEV &&
    155 	    ((flags & FREAD) && (flags & FWRITE))) {
    156 		DPRINTF(("umcpmio_dev_open: Not CONTROL device and trying to"
    157 		    " do READ and WRITE\n"));
    158 		return EINVAL;
    159 	}
    160 	error = 0;
    161 
    162 	mutex_enter(&sc->sc_action_mutex);
    163 
    164 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) {
    165 		if (dunit != CONTROL_DEV &&
    166 		    dunit != EEPROM_DEV)
    167 			error = EINVAL;
    168 	}
    169 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
    170 		if (dunit != CONTROL_DEV) {
    171 			switch (dunit) {
    172 			case GP1_DEV:
    173 				pin = 1;
    174 				break;
    175 			case GP2_DEV:
    176 				pin = 2;
    177 				break;
    178 			case GP3_DEV:
    179 				pin = 3;
    180 				break;
    181 			default:
    182 				error = EINVAL;
    183 			}
    184 
    185 			if (!error) {
    186 				if (flags & FREAD) {
    187 					sc->sc_adcdac_pin_flags[pin] = sc->sc_gpio_pins[pin].pin_flags;
    188 					error = mcp2221_gpio_pin_ctl(sc, pin,
    189 					    GPIO_PIN_ALT0);
    190 				} else {
    191 					if (pin == 1) {
    192 						error = EINVAL;
    193 					} else {
    194 						sc->sc_adcdac_pin_flags[pin] =
    195 						    sc->sc_gpio_pins[pin].pin_flags;
    196 						error = mcp2221_gpio_pin_ctl(sc,
    197 						    pin, GPIO_PIN_ALT1);
    198 					}
    199 				}
    200 			}
    201 		}
    202 	}
    203 	if (!error)
    204 		sc->sc_dev_open[dunit] = true;
    205 
    206 	mutex_exit(&sc->sc_action_mutex);
    207 
    208 	DPRINTF(("umcpmio_dev_open: Opened dunit=%d, pin=%d, error=%d\n",
    209 	    dunit, pin, error));
    210 
    211 	return error;
    212 }
    213 /* Read the ADC on the MCP2221 / MCP2221A */
    214 
    215 static int
    216 umcpmio_dev_read_adc(dev_t dev, struct uio *uio, int flags,
    217     int dunit, struct umcpmio_softc *sc)
    218 {
    219 	struct mcp2221_status_res status_res;
    220 	int error = 0;
    221 	uint8_t adc_lsb;
    222 	uint8_t adc_msb;
    223 	uint16_t buf;
    224 
    225 	while (uio->uio_resid && !sc->sc_dying) {
    226 		mutex_enter(&sc->sc_action_mutex);
    227 		error = mcp2221_get_status(sc, &status_res);
    228 		mutex_exit(&sc->sc_action_mutex);
    229 		if (error)
    230 			break;
    231 		switch (dunit) {
    232 		case GP1_DEV:
    233 			adc_lsb = status_res.adc_channel0_lsb;
    234 			adc_msb = status_res.adc_channel0_msb;
    235 			break;
    236 		case GP2_DEV:
    237 			adc_lsb = status_res.adc_channel1_lsb;
    238 			adc_msb = status_res.adc_channel1_msb;
    239 			break;
    240 		case GP3_DEV:
    241 			adc_lsb = status_res.adc_channel2_lsb;
    242 			adc_msb = status_res.adc_channel2_msb;
    243 			break;
    244 		default:
    245 			error = EINVAL;
    246 			break;
    247 		}
    248 		if (error)
    249 			break;
    250 		if (sc->sc_dying)
    251 			break;
    252 
    253 		buf = adc_msb << 8;
    254 		buf |= adc_lsb;
    255 		error = uiomove(&buf, 2, uio);
    256 		if (error)
    257 			break;
    258 	}
    259 
    260 	return error;
    261 }
    262 /* Read the EEPROM on the MCP2210 */
    263 
    264 static int
    265 umcpmio_dev_read_eeprom(dev_t dev, struct uio *uio, int flags,
    266     struct umcpmio_softc *sc)
    267 {
    268 	int error;
    269 
    270 	/* We do not make this an error.  There is nothing wrong with running
    271 	 * off the end here, just return EOF. */
    272 	if (uio->uio_offset > 0xff)
    273 		return 0;
    274 
    275 	while (uio->uio_resid &&
    276 	    uio->uio_offset <= 0xff &&
    277 	    !sc->sc_dying) {
    278 		uint8_t buf;
    279 		int reg_addr = uio->uio_offset;
    280 
    281 		if ((error = mcp2210_read_eeprom(sc, reg_addr, &buf)) != 0) {
    282 			aprint_error_dev(sc->sc_dev,
    283 			    "%s: read failed at 0x%02x: %d\n",
    284 			    __func__, reg_addr, error);
    285 			return error;
    286 		}
    287 		if (sc->sc_dying)
    288 			break;
    289 
    290 		if ((error = uiomove(&buf, 1, uio)) != 0)
    291 			return error;
    292 	}
    293 
    294 	if (sc->sc_dying) {
    295 		return EIO;
    296 	}
    297 	return 0;
    298 }
    299 
    300 static int
    301 umcpmio_dev_read(dev_t dev, struct uio *uio, int flags)
    302 {
    303 	struct umcpmio_softc *sc;
    304 	int dunit;
    305 
    306 	sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
    307 	if (sc == NULL)
    308 		return ENXIO;
    309 
    310 	dunit = UMCPMIO_DEV_WHAT(minor(dev));
    311 
    312 	if (dunit == CONTROL_DEV) {
    313 		return EINVAL;
    314 	}
    315 	if (dunit != EEPROM_DEV)
    316 		return (umcpmio_dev_read_adc(dev, uio, flags, dunit, sc));
    317 	else
    318 		return (umcpmio_dev_read_eeprom(dev, uio, flags, sc));
    319 }
    320 
    321 /* Write to the DAC on the MCP2221 / MCP2221A*/
    322 
    323 static int
    324 umcpmio_dev_write_dac(dev_t dev, struct uio *uio, int flags,
    325     struct umcpmio_softc *sc)
    326 {
    327 	int error = 0;
    328 
    329 	while (uio->uio_resid && !sc->sc_dying) {
    330 		uint8_t buf;
    331 
    332 		if ((error = uiomove(&buf, 1, uio)) != 0)
    333 			break;
    334 
    335 		if (sc->sc_dying)
    336 			break;
    337 
    338 		mutex_enter(&sc->sc_action_mutex);
    339 		error = mcp2221_set_dac_value_one(sc, buf);
    340 		mutex_exit(&sc->sc_action_mutex);
    341 		if (error)
    342 			break;
    343 	}
    344 
    345 	return error;
    346 }
    347 
    348 /* Write to the EEPROM on the MCP2210 */
    349 
    350 static int
    351 umcpmio_dev_write_eeprom(dev_t dev, struct uio *uio, int flags,
    352     struct umcpmio_softc *sc)
    353 {
    354 	int error;
    355 
    356 	/* Same thing as read, this is not considered an error */
    357 	if (uio->uio_offset > 0xff)
    358 		return 0;
    359 
    360 	while (uio->uio_resid &&
    361 	    uio->uio_offset <= 0xff &&
    362 	    !sc->sc_dying) {
    363 		uint8_t buf;
    364 		int reg_addr = uio->uio_offset;
    365 
    366 		if ((error = uiomove(&buf, 1, uio)) != 0)
    367 			break;
    368 
    369 		if (sc->sc_dying)
    370 			break;
    371 
    372 		if ((error = mcp2210_write_eeprom(sc, (uint8_t) reg_addr, buf)) != 0) {
    373 			device_printf(sc->sc_dev,
    374 			    "%s: write failed at 0x%02x: %d\n",
    375 			    __func__, reg_addr, error);
    376 			return error;
    377 		}
    378 	}
    379 
    380 	if (sc->sc_dying) {
    381 		return EIO;
    382 	}
    383 	return error;
    384 }
    385 
    386 static int
    387 umcpmio_dev_write(dev_t dev, struct uio *uio, int flags)
    388 {
    389 	struct umcpmio_softc *sc;
    390 	int dunit;
    391 
    392 	sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
    393 	if (sc == NULL)
    394 		return ENXIO;
    395 
    396 	dunit = UMCPMIO_DEV_WHAT(minor(dev));
    397 
    398 	if (dunit == CONTROL_DEV) {
    399 		return EINVAL;
    400 	}
    401 	if (dunit != EEPROM_DEV)
    402 		return (umcpmio_dev_write_dac(dev, uio, flags, sc));
    403 	else
    404 		return (umcpmio_dev_write_eeprom(dev, uio, flags, sc));
    405 }
    406 
    407 /* Close everything up */
    408 
    409 static int
    410 umcpmio_dev_close(dev_t dev, int flags, int fmt, struct lwp *l)
    411 {
    412 	struct umcpmio_softc *sc;
    413 	int dunit;
    414 	int pin;
    415 	int error = 0;
    416 
    417 	sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
    418 	if (sc->sc_dying)
    419 		return EIO;
    420 
    421 	dunit = UMCPMIO_DEV_WHAT(minor(dev));
    422 
    423 	mutex_enter(&sc->sc_action_mutex);
    424 
    425 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
    426 		if (dunit != CONTROL_DEV &&
    427 		    dunit != EEPROM_DEV) {
    428 			switch (dunit) {
    429 			case GP1_DEV:
    430 				pin = 1;
    431 				break;
    432 			case GP2_DEV:
    433 				pin = 2;
    434 				break;
    435 			case GP3_DEV:
    436 				pin = 3;
    437 				break;
    438 			default:
    439 				error = EINVAL;
    440 				goto out;
    441 				break;
    442 			}
    443 			if (sc->sc_adcdac_pin_flags[pin] != -1) {
    444 				error = mcp2221_gpio_pin_ctl(sc, pin, sc->sc_adcdac_pin_flags[pin]);
    445 				sc->sc_adcdac_pin_flags[pin] = -1;
    446 			} else {
    447 				error = mcp2221_gpio_pin_ctl(sc, pin, GPIO_PIN_INPUT);
    448 			}
    449 		}
    450 	}
    451 out:
    452 	sc->sc_dev_open[dunit] = false;
    453 	mutex_exit(&sc->sc_action_mutex);
    454 
    455 	return error;
    456 }
    457 
    458 static int
    459 umcpmio_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    460 {
    461 	struct umcpmio_softc *sc;
    462 	union umcpmio_ioctl_get_status get_status_res;
    463 	struct mcp2221_get_sram_res get_sram_res;
    464 	struct mcp2221_get_gpio_cfg_res get_gpio_cfg_res;
    465 	struct umcpmio_ioctl_get_flash get_flash_res;
    466 	union umcpmio_ioctl_get_status *ioctl_get_status;
    467 	struct mcp2221_get_sram_res *ioctl_get_sram;
    468 	struct mcp2221_get_gpio_cfg_res *ioctl_get_gpio_cfg;
    469 	struct umcpmio_ioctl_get_flash *ioctl_get_flash;
    470 	struct umcpmio_ioctl_put_flash *ioctl_put_flash;
    471 	struct mcp2221_put_flash_req mcp2221_put_req;
    472 	struct mcp2221_put_flash_res mcp2221_put_res;
    473 	struct mcp2210_ioctl_get_sram *mcp2210_get_sram;
    474 	struct mcp2210_get_nvram_res mcp2210_gnvram_res;
    475 	struct mcp2210_set_nvram_req mcp2210_snvram_req;
    476 	struct mcp2210_set_nvram_res mcp2210_snvram_res;
    477 	struct mcp2210_cancel_spi_res *ioctl_cancel_spi;
    478 	struct mcp2210_cancel_spi_res mcp2210_cancel_spi;
    479 	uint8_t blob_req[UMCPMIO_REQ_BUFFER_SIZE];
    480 	uint8_t blob_res[UMCPMIO_RES_BUFFER_SIZE];
    481 	uint8_t *chip_type;
    482 	int dunit;
    483 	int error = 0;
    484 
    485 	sc = device_lookup_private(&umcpmio_cd, UMCPMIO_DEV_UNIT(minor(dev)));
    486 	if (sc->sc_dying)
    487 		return EIO;
    488 
    489 	dunit = UMCPMIO_DEV_WHAT(minor(dev));
    490 
    491 	if (dunit != CONTROL_DEV) {
    492 		/* It actually is fine to call ioctl with a unsupported cmd,
    493 		 * but be a little noisy if debug is enabled. */
    494 		DPRINTF(("umcpmio_dev_ioctl: dunit is not the CONTROL device:"
    495 		    " dunit=%d, cmd=%ld\n", dunit, cmd));
    496 		return EINVAL;
    497 	}
    498 	mutex_enter(&sc->sc_action_mutex);
    499 
    500 	switch (cmd) {
    501 		/* The GET calls use a shadow buffer for each type of call.
    502 		 * That probably isn't actually needed and the memcpy could be
    503 		 * avoided.  but...  it is only ever 64 bytes, so maybe not a
    504 		 * big deal. */
    505 
    506 	case UMCPMIO_GET_STATUS:
    507 		ioctl_get_status = (union umcpmio_ioctl_get_status *)data;
    508 		switch (sc->sc_chipinfo->usb_id) {
    509 		case USB_PRODUCT_MICROCHIP_MCP2210:
    510 			error = mcp2210_get_status(sc, &get_status_res.mcp2210_status_res);
    511 			break;
    512 		case USB_PRODUCT_MICROCHIP_MCP2221:
    513 			error = mcp2221_get_status(sc, &get_status_res.mcp2221_status_res);
    514 			break;
    515 		default:
    516 			panic("UMCPMIO_GET_STATUS ioctl.  Unknown sc_chipinfo.usb_id");
    517 		};
    518 		umcpmio_dump_buffer(sc->sc_dumpbuffer,
    519 		    &get_status_res.status_blob[0], UMCPMIO_RES_BUFFER_SIZE,
    520 		    "umcpmio_dev_ioctl: UMCPMIO_GET_STATUS: get_status_res");
    521 		DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_GET_STATUS:"
    522 		    " error=%d\n", error));
    523 		if (error)
    524 			break;
    525 		memcpy(ioctl_get_status, &get_status_res,
    526 		    UMCPMIO_RES_BUFFER_SIZE);
    527 		break;
    528 
    529 	case MCP2210_CANCEL_SPI:
    530 		if (sc->sc_chipinfo->usb_id != USB_PRODUCT_MICROCHIP_MCP2210) {
    531 			error = EINVAL;
    532 			break;
    533 		}
    534 		ioctl_cancel_spi = (struct mcp2210_cancel_spi_res *)data;
    535 		error = mcp2210_cancel_spi_transfer(sc, &mcp2210_cancel_spi);
    536 		if (error)
    537 			break;
    538 		memcpy(ioctl_cancel_spi, &mcp2210_cancel_spi,
    539 		    MCP2210_RES_BUFFER_SIZE);
    540 		break;
    541 
    542 	case MCP2210_GET_SRAM:
    543 		if (sc->sc_chipinfo->usb_id != USB_PRODUCT_MICROCHIP_MCP2210) {
    544 			error = EINVAL;
    545 			break;
    546 		}
    547 		mcp2210_get_sram = (struct mcp2210_ioctl_get_sram *)data;
    548 		memset(&blob_req[0], 0, UMCPMIO_REQ_BUFFER_SIZE);
    549 		DPRINTF(("umcpmio_dev_ioctl: MCP2210_GET_SRAM:"
    550 		    " cmd=%d\n", mcp2210_get_sram->cmd));
    551 		if (mcp2210_get_sram->cmd == MCP2210_CMD_GET_GPIO_SRAM ||
    552 		    mcp2210_get_sram->cmd == MCP2210_CMD_GET_GPIO_VAL_SRAM ||
    553 		    mcp2210_get_sram->cmd == MCP2210_CMD_GET_GPIO_DIR_SRAM ||
    554 		    mcp2210_get_sram->cmd == MCP2210_CMD_GET_SPI_SRAM) {
    555 			blob_req[0] = mcp2210_get_sram->cmd;
    556 			DPRINTF(("umcpmio_dev_ioctl: MCP2210_GET_SRAM:"
    557 			    " blob_req[0]=%d\n", blob_req[0]));
    558 			error = umcpmio_send_report(sc, &blob_req[0], UMCPMIO_REQ_BUFFER_SIZE,
    559 			    &blob_res[0], sc->sc_cv_wait);
    560 		} else {
    561 			error = EINVAL;
    562 		}
    563 
    564 		DPRINTF(("umcpmio_dev_ioctl: MCP2210_GET_SRAM:"
    565 		    " error=%d\n", error));
    566 
    567 		if (!error)
    568 			memcpy(mcp2210_get_sram->res, &blob_res[0], UMCPMIO_RES_BUFFER_SIZE);
    569 
    570 		break;
    571 
    572 	case MCP2221_GET_SRAM:
    573 		if (sc->sc_chipinfo->usb_id != USB_PRODUCT_MICROCHIP_MCP2221) {
    574 			error = EINVAL;
    575 			break;
    576 		}
    577 		ioctl_get_sram = (struct mcp2221_get_sram_res *)data;
    578 		error = mcp2221_get_sram(sc, &get_sram_res);
    579 		umcpmio_dump_buffer(sc->sc_dumpbuffer,
    580 		    (uint8_t *) & get_sram_res, MCP2221_RES_BUFFER_SIZE,
    581 		    "umcpmio_dev_ioctl: MCP2221_GET_SRAM: get_sram_res");
    582 		DPRINTF(("umcpmio_dev_ioctl: MCP2221_GET_SRAM:"
    583 		    " mcp2221_get_sram error=%d\n", error));
    584 		if (error)
    585 			break;
    586 		memcpy(ioctl_get_sram, &get_sram_res,
    587 		    MCP2221_RES_BUFFER_SIZE);
    588 		break;
    589 
    590 	case MCP2221_GET_GP_CFG:
    591 		if (sc->sc_chipinfo->usb_id != USB_PRODUCT_MICROCHIP_MCP2221) {
    592 			error = EINVAL;
    593 			break;
    594 		}
    595 		ioctl_get_gpio_cfg = (struct mcp2221_get_gpio_cfg_res *)data;
    596 		error = mcp2221_get_gpio_cfg(sc, &get_gpio_cfg_res);
    597 		umcpmio_dump_buffer(sc->sc_dumpbuffer,
    598 		    (uint8_t *) & get_gpio_cfg_res, MCP2221_RES_BUFFER_SIZE,
    599 		    "umcpmio_dev_ioctl: MCP2221_GET_GP_CFG: get_gpio_cfg_res");
    600 		DPRINTF(("umcpmio_dev_ioctl: MCP2221_GET_GP_CFG:"
    601 		    " mcp2221_get_gpio_cfg error=%d\n", error));
    602 		if (error)
    603 			break;
    604 		memcpy(ioctl_get_gpio_cfg, &get_gpio_cfg_res,
    605 		    MCP2221_RES_BUFFER_SIZE);
    606 		break;
    607 
    608 	case UMCPMIO_GET_FLASH:
    609 		ioctl_get_flash = (struct umcpmio_ioctl_get_flash *)data;
    610 		switch (sc->sc_chipinfo->usb_id) {
    611 		case USB_PRODUCT_MICROCHIP_MCP2210:
    612 			error = mcp2210_get_nvram(sc, ioctl_get_flash->subcode,
    613 			    &get_flash_res.res.mcp2210_get_nvram_res);
    614 			break;
    615 		case USB_PRODUCT_MICROCHIP_MCP2221:
    616 			error = mcp2221_get_flash(sc, ioctl_get_flash->subcode,
    617 			    &get_flash_res.res.mcp2221_get_flash_res);
    618 			break;
    619 		default:
    620 			panic("UMCPMIO_GET_FLASH ioctl.  Unknown sc_chipinfo.usb_id");
    621 		};
    622 		umcpmio_dump_buffer(sc->sc_dumpbuffer,
    623 		    &get_flash_res.res.get_blob[0], MCP2221_RES_BUFFER_SIZE,
    624 		    "umcpmio_dev_ioctl: UMCPMIO_GET_FLASH: get_flash_res");
    625 		DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_GET_FLASH:"
    626 		    " subcode=%d, error=%d\n",
    627 		    ioctl_get_flash->subcode, error));
    628 		if (error)
    629 			break;
    630 		memcpy(&ioctl_get_flash->res.get_blob[0], &get_flash_res.res.get_blob[0],
    631 		    UMCPMIO_RES_BUFFER_SIZE);
    632 		break;
    633 
    634 	case UMCPMIO_PUT_FLASH:
    635 		ioctl_put_flash = (struct umcpmio_ioctl_put_flash *)data;
    636 		DPRINTF(("umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH:"
    637 		    " subcode=%d\n",
    638 		    ioctl_put_flash->subcode));
    639 
    640 		if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) {
    641 			/* For the MCP-2210:
    642 			 *
    643 			 * Always do a read-modify-write operation filling in
    644 			 * only the values that are allowed.  We allow gpio,
    645 			 * SPI and some USB power parameters to be changed. */
    646 			if (ioctl_put_flash->subcode != MCP2210_NVRAM_SUBCODE_SPI &&
    647 			    ioctl_put_flash->subcode != MCP2210_NVRAM_SUBCODE_CS &&
    648 			    ioctl_put_flash->subcode != MCP2210_NVRAM_SUBCODE_USBKEYPARAMS) {
    649 				error = EINVAL;
    650 				break;
    651 			}
    652 			error = mcp2210_get_nvram(sc, ioctl_put_flash->subcode,
    653 			    &mcp2210_gnvram_res);
    654 			if (error)
    655 				break;
    656 
    657 			uint8_t x, y;
    658 			switch (ioctl_put_flash->subcode) {
    659 			case MCP2210_NVRAM_SUBCODE_SPI:
    660 				memcpy(&mcp2210_snvram_req, &mcp2210_gnvram_res, UMCPMIO_REQ_BUFFER_SIZE);
    661 				mcp2210_snvram_req.subcode = MCP2210_NVRAM_SUBCODE_SPI;
    662 				memcpy(&mcp2210_snvram_req.u.spi.cs_to_data_delay_lsb,
    663 				    &ioctl_put_flash->req.mcp2210_set_req.u.spi.cs_to_data_delay_lsb,
    664 				    &mcp2210_snvram_req.u.spi.bytes_per_spi_transaction_msb -
    665 				    &mcp2210_snvram_req.u.spi.cs_to_data_delay_lsb + 1);
    666 				break;
    667 			case MCP2210_NVRAM_SUBCODE_CS:
    668 				memcpy(&mcp2210_snvram_req, &mcp2210_gnvram_res, UMCPMIO_REQ_BUFFER_SIZE);
    669 				mcp2210_snvram_req.subcode = MCP2210_NVRAM_SUBCODE_CS;
    670 				/* Make sure that the password fields are
    671 				 * blanked out with 0 so the password can't be
    672 				 * changed by accident. */
    673 				memset(&mcp2210_snvram_req.u.cs.password_byte_1, 0,
    674 				    &mcp2210_snvram_req.u.cs.password_byte_8 -
    675 				    &mcp2210_snvram_req.u.cs.password_byte_1 + 1);
    676 				memcpy(&mcp2210_snvram_req.u.cs.gp0_designation,
    677 				    &ioctl_put_flash->req.mcp2210_set_req.u.cs.gp0_designation,
    678 				    &mcp2210_snvram_req.u.cs.default_direction_msb -
    679 				    &mcp2210_snvram_req.u.cs.gp0_designation + 1);
    680 				break;
    681 			case MCP2210_NVRAM_SUBCODE_USBKEYPARAMS:
    682 				/* For this subcode, the get and set are not
    683 				 * really symmetric, so copy the fields in one
    684 				 * at a time. */
    685 				mcp2210_snvram_req.subcode = MCP2210_NVRAM_SUBCODE_USBKEYPARAMS;
    686 				mcp2210_snvram_req.u.usbkeyparams.lsb_usb_vid =
    687 				    mcp2210_gnvram_res.u.usbkeyparams.lsb_usb_vid;
    688 				mcp2210_snvram_req.u.usbkeyparams.msb_usb_vid =
    689 				    mcp2210_gnvram_res.u.usbkeyparams.msb_usb_vid;
    690 				mcp2210_snvram_req.u.usbkeyparams.lsb_usb_pid =
    691 				    mcp2210_gnvram_res.u.usbkeyparams.lsb_usb_pid;
    692 				mcp2210_snvram_req.u.usbkeyparams.msb_usb_pid =
    693 				    mcp2210_gnvram_res.u.usbkeyparams.msb_usb_pid;
    694 
    695 				/* Take care to only copy in the power source
    696 				 * bits */
    697 				x = mcp2210_snvram_req.u.usbkeyparams.usb_power_attributes;
    698 				x &= ~(MCP2210_USBPOWER_SELF | MCP2210_USBPOWER_BUSS);
    699 				y = ioctl_put_flash->req.mcp2210_set_req.u.usbkeyparams.usb_power_attributes;
    700 				y &= (MCP2210_USBPOWER_SELF | MCP2210_USBPOWER_BUSS);
    701 				x |= y;
    702 				mcp2210_snvram_req.u.usbkeyparams.usb_power_attributes = x;
    703 				mcp2210_snvram_req.u.usbkeyparams.usb_requested_ma =
    704 				    ioctl_put_flash->req.mcp2210_set_req.u.usbkeyparams.usb_requested_ma;
    705 
    706 				/* Do a check to make sure that the SELF and
    707 				 * BUSS powered bits are not both set or both
    708 				 * unset.  You are not suppose to do that
    709 				 * according to the datasheet for the chip. */
    710 				x = mcp2210_snvram_req.u.usbkeyparams.usb_power_attributes &=
    711 				    (MCP2210_USBPOWER_SELF | MCP2210_USBPOWER_BUSS);
    712 				if (x == 0 ||
    713 				    x == (MCP2210_USBPOWER_SELF | MCP2210_USBPOWER_BUSS))
    714 					error = EINVAL;
    715 				break;
    716 			default:
    717 				error = EINVAL;
    718 			};
    719 
    720 			if (error)
    721 				break;
    722 
    723 			umcpmio_dump_buffer(sc->sc_dumpbuffer,
    724 			    &ioctl_put_flash->req.put_req_blob[0],
    725 			    UMCPMIO_REQ_BUFFER_SIZE,
    726 			    "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH:"
    727 			    " ioctl put request");
    728 			umcpmio_dump_buffer(sc->sc_dumpbuffer,
    729 			    (uint8_t *) & mcp2210_snvram_req, MCP2210_REQ_BUFFER_SIZE,
    730 			    "umcpmio_dev_ioctl:"
    731 			    " UMCPMIO_PUT_FLASH: mcp2210_snvram_req");
    732 
    733 
    734 			memset(&mcp2210_snvram_res, 0, MCP2210_RES_BUFFER_SIZE);
    735 			error = mcp2210_set_nvram(sc, &mcp2210_snvram_req,
    736 			    &mcp2210_snvram_res);
    737 			if (error)
    738 				break;
    739 
    740 			umcpmio_dump_buffer(sc->sc_dumpbuffer,
    741 			    (uint8_t *) & mcp2210_snvram_res, MCP2210_RES_BUFFER_SIZE,
    742 			    "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH:"
    743 			    " mcp2210_snvram_res");
    744 			memcpy(&ioctl_put_flash->res.mcp2210_set_res, &mcp2210_snvram_res,
    745 			    MCP2210_RES_BUFFER_SIZE);
    746 		}
    747 		if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
    748 			/* For the MCP-2221:
    749 			 *
    750 			 * We only allow the flash parts related to gpio to be
    751 			 * changed. Bounce any attempt to do something else.
    752 			 * Also use a shadow buffer for the put, so we get to
    753 			 * control just literally everything about the write to
    754 			 * flash. */
    755 			if (ioctl_put_flash->subcode != MCP2221_FLASH_SUBCODE_GP) {
    756 				error = EINVAL;
    757 				break;
    758 			}
    759 			memset(&mcp2221_put_req, 0, MCP2221_REQ_BUFFER_SIZE);
    760 			mcp2221_put_req.subcode = ioctl_put_flash->subcode;
    761 			mcp2221_put_req.u.gp.gp0_settings =
    762 			    ioctl_put_flash->req.mcp2221_put_req.u.gp.gp0_settings;
    763 			mcp2221_put_req.u.gp.gp1_settings =
    764 			    ioctl_put_flash->req.mcp2221_put_req.u.gp.gp1_settings;
    765 			mcp2221_put_req.u.gp.gp2_settings =
    766 			    ioctl_put_flash->req.mcp2221_put_req.u.gp.gp2_settings;
    767 			mcp2221_put_req.u.gp.gp3_settings =
    768 			    ioctl_put_flash->req.mcp2221_put_req.u.gp.gp3_settings;
    769 			umcpmio_dump_buffer(sc->sc_dumpbuffer,
    770 			    &ioctl_put_flash->req.put_req_blob[0],
    771 			    UMCPMIO_REQ_BUFFER_SIZE,
    772 			    "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH:"
    773 			    " ioctl mcp2221_put_req");
    774 			umcpmio_dump_buffer(sc->sc_dumpbuffer,
    775 			    (uint8_t *) & mcp2221_put_req, MCP2221_REQ_BUFFER_SIZE,
    776 			    "umcpmio_dev_ioctl:"
    777 			    " UMCPMIO_PUT_FLASH: mcp2221_put_req");
    778 
    779 			memset(&mcp2221_put_res, 0, MCP2221_RES_BUFFER_SIZE);
    780 			error = mcp2221_put_flash(sc, &mcp2221_put_req, &mcp2221_put_res);
    781 			if (error)
    782 				break;
    783 
    784 			umcpmio_dump_buffer(sc->sc_dumpbuffer,
    785 			    (uint8_t *) & mcp2221_put_res, MCP2221_RES_BUFFER_SIZE,
    786 			    "umcpmio_dev_ioctl: UMCPMIO_PUT_FLASH:"
    787 			    " mcp2221_put_res");
    788 
    789 			memcpy(&ioctl_put_flash->res.mcp2221_put_res, &mcp2221_put_res,
    790 			    MCP2221_RES_BUFFER_SIZE);
    791 		}
    792 		break;
    793 
    794 	case UMCPMIO_CHIP_TYPE:
    795 		chip_type = (uint8_t *) data;
    796 		*chip_type = 0;
    797 		switch (sc->sc_chipinfo->usb_id) {
    798 		case USB_PRODUCT_MICROCHIP_MCP2210:
    799 			*chip_type = UMCPMIO_CHIP_TYPE_2210;
    800 			break;
    801 		case USB_PRODUCT_MICROCHIP_MCP2221:
    802 			*chip_type = UMCPMIO_CHIP_TYPE_2221;
    803 			break;
    804 		default:
    805 			break;
    806 		}
    807 		break;
    808 
    809 	default:
    810 		error = EINVAL;
    811 	}
    812 
    813 	mutex_exit(&sc->sc_action_mutex);
    814 
    815 	return error;
    816 }
    817 
    818 /* This is for sysctl variables that don't actually change the chip.  */
    819 
    820 int
    821 umcpmio_verify_sysctl(SYSCTLFN_ARGS)
    822 {
    823 	int error, t;
    824 	struct sysctlnode node;
    825 
    826 	node = *rnode;
    827 	t = *(int *)rnode->sysctl_data;
    828 	node.sysctl_data = &t;
    829 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    830 	if (error || newp == NULL)
    831 		return error;
    832 
    833 	if (t < 0)
    834 		return EINVAL;
    835 
    836 	*(int *)rnode->sysctl_data = t;
    837 
    838 	return 0;
    839 }
    840 
    841 /*
    842  * sysctl validation for stuff that interacts with the chip needs to
    843  * happen in a transaction.  The read of the current state and the
    844  * update to new state can't allow for someone to sneak in between the
    845  * two.
    846  *
    847  * We use text for the values of a lot of these variables so you don't
    848  * need the datasheet in front of you.  You get to do that with
    849  * umcpmioctl(8).
    850  */
    851 
    852 static struct umcpmio_sysctl_name mcp2221_vref_names[] = {
    853 	{
    854 		.text = "4.096V",
    855 	},
    856 	{
    857 		.text = "2.048V",
    858 	},
    859 	{
    860 		.text = "1.024V",
    861 	},
    862 	{
    863 		.text = "OFF",
    864 	},
    865 	{
    866 		.text = "VDD",
    867 	}
    868 };
    869 
    870 int
    871 mcp2221_verify_dac_sysctl(SYSCTLFN_ARGS)
    872 {
    873 	char buf[MCP2221_VREF_NAME];
    874 	char cbuf[MCP2221_VREF_NAME];
    875 	struct umcpmio_softc *sc;
    876 	struct sysctlnode node;
    877 	int error = 0;
    878 	int vrm;
    879 	size_t i;
    880 	struct mcp2221_get_sram_res sram_res;
    881 
    882 	node = *rnode;
    883 	sc = node.sysctl_data;
    884 
    885 	mutex_enter(&sc->sc_action_mutex);
    886 
    887 	error = mcp2221_get_sram(sc, &sram_res);
    888 	if (error)
    889 		goto out;
    890 
    891 	umcpmio_dump_buffer(sc->sc_dumpbuffer,
    892 	    (uint8_t *) & sram_res, MCP2221_RES_BUFFER_SIZE,
    893 	    "umcpmio_verify_dac_sysctl SRAM res buffer");
    894 
    895 	if (sram_res.dac_reference_voltage & MCP2221_SRAM_DAC_IS_VRM) {
    896 		vrm = sram_res.dac_reference_voltage &
    897 		    MCP2221_SRAM_DAC_VRM_MASK;
    898 		switch (vrm) {
    899 		case MCP2221_SRAM_DAC_VRM_4096V:
    900 			strncpy(buf, "4.096V", MCP2221_VREF_NAME);
    901 			break;
    902 		case MCP2221_SRAM_DAC_VRM_2048V:
    903 			strncpy(buf, "2.048V", MCP2221_VREF_NAME);
    904 			break;
    905 		case MCP2221_SRAM_DAC_VRM_1024V:
    906 			strncpy(buf, "1.024V", MCP2221_VREF_NAME);
    907 			break;
    908 		case MCP2221_SRAM_DAC_VRM_OFF:
    909 		default:
    910 			strncpy(buf, "OFF", MCP2221_VREF_NAME);
    911 			break;
    912 		}
    913 	} else {
    914 		strncpy(buf, "VDD", MCP2221_VREF_NAME);
    915 	}
    916 	strncpy(cbuf, buf, MCP2221_VREF_NAME);
    917 	node.sysctl_data = buf;
    918 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    919 	if (error || newp == NULL)
    920 		goto out;
    921 
    922 	for (i = 0; i < __arraycount(mcp2221_vref_names); i++) {
    923 		if (strncmp(node.sysctl_data, mcp2221_vref_names[i].text,
    924 		    MCP2221_VREF_NAME) == 0) {
    925 			break;
    926 		}
    927 	}
    928 	if (i == __arraycount(mcp2221_vref_names)) {
    929 		error = EINVAL;
    930 		goto out;
    931 	}
    932 	if (strncmp(cbuf, buf, MCP2221_VREF_NAME) == 0) {
    933 		error = 0;
    934 		goto out;
    935 	}
    936 	DPRINTF(("umcpmio_verify_dac_sysctl: setting DAC vref: %s\n", buf));
    937 	error = mcp2221_set_dac_vref_one(sc, buf);
    938 
    939 out:
    940 	mutex_exit(&sc->sc_action_mutex);
    941 	return error;
    942 }
    943 
    944 int
    945 mcp2221_verify_adc_sysctl(SYSCTLFN_ARGS)
    946 {
    947 	char buf[MCP2221_VREF_NAME];
    948 	char cbuf[MCP2221_VREF_NAME];
    949 	struct umcpmio_softc *sc;
    950 	struct sysctlnode node;
    951 	int error = 0;
    952 	int vrm;
    953 	size_t i;
    954 	struct mcp2221_get_sram_res sram_res;
    955 
    956 	node = *rnode;
    957 	sc = node.sysctl_data;
    958 
    959 	mutex_enter(&sc->sc_action_mutex);
    960 
    961 	error = mcp2221_get_sram(sc, &sram_res);
    962 	if (error)
    963 		goto out;
    964 
    965 	if (sram_res.irq_adc_reference_voltage & MCP2221_SRAM_ADC_IS_VRM) {
    966 		vrm = sram_res.irq_adc_reference_voltage &
    967 		    MCP2221_SRAM_ADC_VRM_MASK;
    968 		switch (vrm) {
    969 		case MCP2221_SRAM_ADC_VRM_4096V:
    970 			strncpy(buf, "4.096V", MCP2221_VREF_NAME);
    971 			break;
    972 		case MCP2221_SRAM_ADC_VRM_2048V:
    973 			strncpy(buf, "2.048V", MCP2221_VREF_NAME);
    974 			break;
    975 		case MCP2221_SRAM_ADC_VRM_1024V:
    976 			strncpy(buf, "1.024V", MCP2221_VREF_NAME);
    977 			break;
    978 		case MCP2221_SRAM_ADC_VRM_OFF:
    979 		default:
    980 			strncpy(buf, "OFF", MCP2221_VREF_NAME);
    981 			break;
    982 		}
    983 	} else {
    984 		strncpy(buf, "VDD", MCP2221_VREF_NAME);
    985 	}
    986 	strncpy(cbuf, buf, MCP2221_VREF_NAME);
    987 	node.sysctl_data = buf;
    988 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    989 	if (error || newp == NULL)
    990 		goto out;
    991 
    992 	for (i = 0; i < __arraycount(mcp2221_vref_names); i++) {
    993 		if (strncmp(node.sysctl_data, mcp2221_vref_names[i].text,
    994 		    MCP2221_VREF_NAME) == 0) {
    995 			break;
    996 		}
    997 	}
    998 	if (i == __arraycount(mcp2221_vref_names)) {
    999 		error = EINVAL;
   1000 		goto out;
   1001 	}
   1002 	if (strncmp(cbuf, buf, MCP2221_VREF_NAME) == 0) {
   1003 		error = 0;
   1004 		goto out;
   1005 	}
   1006 	DPRINTF(("umcpmio_verify_adc_sysctl: setting ADC vref: %s\n", buf));
   1007 	error = mcp2221_set_adc_vref_one(sc, buf);
   1008 
   1009 out:
   1010 	mutex_exit(&sc->sc_action_mutex);
   1011 	return error;
   1012 }
   1013 
   1014 static struct umcpmio_sysctl_name mcp2221_dc_names[] = {
   1015 	{
   1016 		.text = "75%",
   1017 	},
   1018 	{
   1019 		.text = "50%",
   1020 	},
   1021 	{
   1022 		.text = "25%",
   1023 	},
   1024 	{
   1025 		.text = "0%",
   1026 	}
   1027 };
   1028 
   1029 static int
   1030 mcp2221_verify_gpioclock_dc_sysctl(SYSCTLFN_ARGS)
   1031 {
   1032 	char buf[MCP2221_DC_NAME];
   1033 	char cbuf[MCP2221_DC_NAME];
   1034 	struct umcpmio_softc *sc;
   1035 	struct sysctlnode node;
   1036 	int error = 0;
   1037 	uint8_t duty_cycle;
   1038 	size_t i;
   1039 	struct mcp2221_get_sram_res sram_res;
   1040 
   1041 	node = *rnode;
   1042 	sc = node.sysctl_data;
   1043 
   1044 	mutex_enter(&sc->sc_action_mutex);
   1045 
   1046 	error = mcp2221_get_sram(sc, &sram_res);
   1047 	if (error)
   1048 		goto out;
   1049 
   1050 	duty_cycle = sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_DC_MASK;
   1051 	DPRINTF(("umcpmio_verify_gpioclock_dc_sysctl: current duty cycle:"
   1052 	    " %02x\n", duty_cycle));
   1053 	switch (duty_cycle) {
   1054 	case MCP2221_SRAM_GPIO_CLOCK_DC_75:
   1055 		strncpy(buf, "75%", MCP2221_DC_NAME);
   1056 		break;
   1057 	case MCP2221_SRAM_GPIO_CLOCK_DC_50:
   1058 		strncpy(buf, "50%", MCP2221_DC_NAME);
   1059 		break;
   1060 	case MCP2221_SRAM_GPIO_CLOCK_DC_25:
   1061 		strncpy(buf, "25%", MCP2221_DC_NAME);
   1062 		break;
   1063 	case MCP2221_SRAM_GPIO_CLOCK_DC_0:
   1064 	default:
   1065 		strncpy(buf, "0%", MCP2221_DC_NAME);
   1066 		break;
   1067 	}
   1068 	strncpy(cbuf, buf, MCP2221_DC_NAME);
   1069 	node.sysctl_data = buf;
   1070 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1071 	if (error || newp == NULL)
   1072 		goto out;
   1073 
   1074 	for (i = 0; i < __arraycount(mcp2221_dc_names); i++) {
   1075 		if (strncmp(node.sysctl_data, mcp2221_dc_names[i].text,
   1076 		    MCP2221_DC_NAME) == 0) {
   1077 			break;
   1078 		}
   1079 	}
   1080 	if (i == __arraycount(mcp2221_dc_names)) {
   1081 		error = EINVAL;
   1082 		goto out;
   1083 	}
   1084 	if (strncmp(cbuf, buf, MCP2221_DC_NAME) == 0) {
   1085 		error = 0;
   1086 		goto out;
   1087 	}
   1088 	DPRINTF(("umcpmio_verify_gpioclock_dc_sysctl:"
   1089 	    " setting GPIO clock duty cycle: %s\n", buf));
   1090 	error = mcp2221_set_gpioclock_dc_one(sc, buf);
   1091 
   1092 out:
   1093 	mutex_exit(&sc->sc_action_mutex);
   1094 	return error;
   1095 }
   1096 
   1097 static struct umcpmio_sysctl_name mcp2221_cd_names[] = {
   1098 	{
   1099 		.text = "375kHz",
   1100 	},
   1101 	{
   1102 		.text = "750kHz",
   1103 	},
   1104 	{
   1105 		.text = "1.5MHz",
   1106 	},
   1107 	{
   1108 		.text = "3MHz",
   1109 	},
   1110 	{
   1111 		.text = "6MHz",
   1112 	},
   1113 	{
   1114 		.text = "12MHz",
   1115 	},
   1116 	{
   1117 		.text = "24MHz",
   1118 	}
   1119 };
   1120 
   1121 static int
   1122 mcp2221_verify_gpioclock_cd_sysctl(SYSCTLFN_ARGS)
   1123 {
   1124 	char buf[MCP2221_CD_NAME];
   1125 	char cbuf[MCP2221_CD_NAME];
   1126 	struct umcpmio_softc *sc;
   1127 	struct sysctlnode node;
   1128 	int error = 0;
   1129 	uint8_t clock_divider;
   1130 	size_t i;
   1131 	struct mcp2221_get_sram_res sram_res;
   1132 
   1133 	node = *rnode;
   1134 	sc = node.sysctl_data;
   1135 
   1136 	mutex_enter(&sc->sc_action_mutex);
   1137 
   1138 	error = mcp2221_get_sram(sc, &sram_res);
   1139 	if (error)
   1140 		goto out;
   1141 
   1142 	clock_divider = sram_res.clock_divider &
   1143 	    MCP2221_SRAM_GPIO_CLOCK_CD_MASK;
   1144 	DPRINTF(("umcpmio_verify_gpioclock_cd_sysctl: current clock divider:"
   1145 	    " %02x\n", clock_divider));
   1146 	switch (clock_divider) {
   1147 	case MCP2221_SRAM_GPIO_CLOCK_CD_375KHZ:
   1148 		strncpy(buf, "375kHz", MCP2221_CD_NAME);
   1149 		break;
   1150 	case MCP2221_SRAM_GPIO_CLOCK_CD_750KHZ:
   1151 		strncpy(buf, "750kHz", MCP2221_CD_NAME);
   1152 		break;
   1153 	case MCP2221_SRAM_GPIO_CLOCK_CD_1P5MHZ:
   1154 		strncpy(buf, "1.5MHz", MCP2221_CD_NAME);
   1155 		break;
   1156 	case MCP2221_SRAM_GPIO_CLOCK_CD_3MHZ:
   1157 		strncpy(buf, "3MHz", MCP2221_CD_NAME);
   1158 		break;
   1159 	case MCP2221_SRAM_GPIO_CLOCK_CD_6MHZ:
   1160 		strncpy(buf, "6MHz", MCP2221_CD_NAME);
   1161 		break;
   1162 	case MCP2221_SRAM_GPIO_CLOCK_CD_12MHZ:
   1163 		strncpy(buf, "12MHz", MCP2221_CD_NAME);
   1164 		break;
   1165 	case MCP2221_SRAM_GPIO_CLOCK_CD_24MHZ:
   1166 		strncpy(buf, "24MHz", MCP2221_CD_NAME);
   1167 		break;
   1168 	default:
   1169 		strncpy(buf, "12MHz", MCP2221_CD_NAME);
   1170 		break;
   1171 	}
   1172 	strncpy(cbuf, buf, MCP2221_CD_NAME);
   1173 	node.sysctl_data = buf;
   1174 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1175 	if (error || newp == NULL)
   1176 		goto out;
   1177 
   1178 	for (i = 0; i < __arraycount(mcp2221_cd_names); i++) {
   1179 		if (strncmp(node.sysctl_data, mcp2221_cd_names[i].text,
   1180 		    MCP2221_CD_NAME) == 0) {
   1181 			break;
   1182 		}
   1183 	}
   1184 	if (i == __arraycount(mcp2221_cd_names)) {
   1185 		error = EINVAL;
   1186 		goto out;
   1187 	}
   1188 	if (strncmp(cbuf, buf, MCP2221_CD_NAME) == 0) {
   1189 		error = 0;
   1190 		goto out;
   1191 	}
   1192 	DPRINTF(("umcpmio_verify_gpioclock_cd_sysctl:"
   1193 	    " setting GPIO clock clock divider: %s\n",
   1194 	    buf));
   1195 	error = mcp2221_set_gpioclock_cd_one(sc, buf);
   1196 
   1197 out:
   1198 	mutex_exit(&sc->sc_action_mutex);
   1199 	return error;
   1200 }
   1201 
   1202 static int
   1203 mcp2210_verify_counter_sysctl(SYSCTLFN_ARGS)
   1204 {
   1205 	struct umcpmio_softc *sc;
   1206 	struct sysctlnode node;
   1207 	int error = 0;
   1208 	int counter;
   1209 
   1210 	node = *rnode;
   1211 	sc = node.sysctl_data;
   1212 
   1213 	mutex_enter(&sc->sc_action_mutex);
   1214 
   1215 	error = mcp2210_get_gp6_counter(sc, &counter, MCP2210_COUNTER_RETAIN);
   1216 	if (error)
   1217 		goto out;
   1218 
   1219 	DPRINTF(("mcp2210_verify_counter_sysctl 1: counter=%d\n", counter));
   1220 
   1221 	node.sysctl_data = &counter;
   1222 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1223 	if (error || newp == NULL)
   1224 		goto out;
   1225 
   1226 	DPRINTF(("mcp2210_verify_counter_sysctl 2: counter=%d\n", counter));
   1227 
   1228 	*(int *)rnode->sysctl_data = (int)counter;
   1229 
   1230 out:
   1231 	mutex_exit(&sc->sc_action_mutex);
   1232 	return error;
   1233 }
   1234 
   1235 static int
   1236 mcp2210_reset_counter_sysctl(SYSCTLFN_ARGS)
   1237 {
   1238 	struct umcpmio_softc *sc;
   1239 	struct sysctlnode node;
   1240 	int error = 0;
   1241 	int counter;
   1242 	bool reset = false;
   1243 
   1244 	node = *rnode;
   1245 	sc = node.sysctl_data;
   1246 
   1247 	node.sysctl_data = &reset;
   1248 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1249 	if (error || newp == NULL)
   1250 		return error;
   1251 
   1252 	DPRINTF(("mcp2210_reset_counter_sysctl: reset=%d\n", reset));
   1253 
   1254 	if (reset) {
   1255 		mutex_enter(&sc->sc_action_mutex);
   1256 		error = mcp2210_get_gp6_counter(sc, &counter, MCP2210_COUNTER_RESET);
   1257 		*(int *)rnode->sysctl_data = false;
   1258 		mutex_exit(&sc->sc_action_mutex);
   1259 	}
   1260 	return error;
   1261 }
   1262 
   1263 static int
   1264 umcpmio_sysctl_init(struct umcpmio_softc *sc)
   1265 {
   1266 	int error;
   1267 	const struct sysctlnode *cnode;
   1268 	int sysctlroot_num, i2c_num = 0, spi_num = 0, adc_dac_num = 0, adc_num = 0, dac_num = 0,
   1269 	    gpio_num;
   1270 
   1271 	if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1272 	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
   1273 	    SYSCTL_DESCR("umcpmio controls"),
   1274 	    NULL, 0, NULL, 0,
   1275 	    CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
   1276 		return error;
   1277 
   1278 	sysctlroot_num = cnode->sysctl_num;
   1279 
   1280 #ifdef UMCPMIO_DEBUG
   1281 	if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1282 	    CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
   1283 	    SYSCTL_DESCR("Debug level"),
   1284 	    umcpmio_verify_sysctl, 0, &umcpmiodebug, 0,
   1285 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1286 		return error;
   1287 
   1288 	if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1289 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "dump_buffers",
   1290 	    SYSCTL_DESCR("Dump buffer when debugging"),
   1291 	    NULL, 0, &sc->sc_dumpbuffer, 0,
   1292 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1293 		return error;
   1294 #endif
   1295 
   1296 	if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1297 	    CTLFLAG_READWRITE, CTLTYPE_INT, "response_wait",
   1298 	    SYSCTL_DESCR("How long to wait in ms for a response"
   1299 	    " for a HID report"),
   1300 	    umcpmio_verify_sysctl, 0, &sc->sc_cv_wait, 0,
   1301 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1302 		return error;
   1303 
   1304 	if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1305 	    CTLFLAG_READWRITE, CTLTYPE_INT, "response_errcnt",
   1306 	    SYSCTL_DESCR("How many errors to allow on a response"),
   1307 	    umcpmio_verify_sysctl, 0, &sc->sc_response_errcnt, 0,
   1308 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1309 		return error;
   1310 
   1311 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) {
   1312 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1313 		    0, CTLTYPE_NODE, "spi",
   1314 		    SYSCTL_DESCR("SPI controls"),
   1315 		    NULL, 0, NULL, 0,
   1316 		    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1317 			return error;
   1318 
   1319 		spi_num = cnode->sysctl_num;
   1320 	}
   1321 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
   1322 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1323 		    0, CTLTYPE_NODE, "i2c",
   1324 		    SYSCTL_DESCR("I2C controls"),
   1325 		    NULL, 0, NULL, 0,
   1326 		    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1327 			return error;
   1328 
   1329 		i2c_num = cnode->sysctl_num;
   1330 
   1331 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1332 		    0, CTLTYPE_NODE, "adcdac",
   1333 		    SYSCTL_DESCR("ADC and DAC controls"),
   1334 		    NULL, 0, NULL, 0,
   1335 		    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1336 			return error;
   1337 
   1338 		adc_dac_num = cnode->sysctl_num;
   1339 
   1340 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1341 		    0, CTLTYPE_NODE, "adc",
   1342 		    SYSCTL_DESCR("ADC controls"),
   1343 		    NULL, 0, NULL, 0,
   1344 		    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1345 			return error;
   1346 
   1347 		adc_num = cnode->sysctl_num;
   1348 
   1349 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1350 		    0, CTLTYPE_NODE, "dac",
   1351 		    SYSCTL_DESCR("DAC controls"),
   1352 		    NULL, 0, NULL, 0,
   1353 		    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1354 			return error;
   1355 
   1356 		dac_num = cnode->sysctl_num;
   1357 	}
   1358 	if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1359 	    0, CTLTYPE_NODE, "gpio",
   1360 	    SYSCTL_DESCR("GPIO controls"),
   1361 	    NULL, 0, NULL, 0,
   1362 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1363 		return error;
   1364 
   1365 	gpio_num = cnode->sysctl_num;
   1366 
   1367 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) {
   1368 		/* SPI */
   1369 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1370 		    CTLFLAG_READWRITE, CTLTYPE_BOOL, "verbose",
   1371 		    SYSCTL_DESCR("Verbose SPI messages"),
   1372 		    umcpmio_verify_sysctl, 0, &sc->sc_spi_verbose, 0,
   1373 		    CTL_HW, sysctlroot_num, spi_num, CTL_CREATE, CTL_EOL)) != 0)
   1374 			return error;
   1375 
   1376 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1377 		    CTLFLAG_READWRITE, CTLTYPE_INT, "busy_delay",
   1378 		    SYSCTL_DESCR("How long to wait in ms when the SPI engine is busy"),
   1379 		    umcpmio_verify_sysctl, 0, &sc->sc_busy_delay, 0,
   1380 		    CTL_HW, sysctlroot_num, spi_num, CTL_CREATE, CTL_EOL)) != 0)
   1381 			return error;
   1382 
   1383 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1384 		    CTLFLAG_READWRITE, CTLTYPE_INT, "retry_busy_chipdrain",
   1385 		    SYSCTL_DESCR("How many times to retry the SPI engine to drain the chip"),
   1386 		    umcpmio_verify_sysctl, 0, &sc->sc_retry_busy_read, 0,
   1387 		    CTL_HW, sysctlroot_num, spi_num, CTL_CREATE, CTL_EOL)) != 0)
   1388 			return error;
   1389 
   1390 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1391 		    CTLFLAG_READWRITE, CTLTYPE_INT, "retry_busy_transfer",
   1392 		    SYSCTL_DESCR("How many times to retry the SPI engine in a normal transfer"),
   1393 		    umcpmio_verify_sysctl, 0, &sc->sc_retry_busy_write, 0,
   1394 		    CTL_HW, sysctlroot_num, spi_num, CTL_CREATE, CTL_EOL)) != 0)
   1395 			return error;
   1396 	}
   1397 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
   1398 		/* I2C */
   1399 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1400 		    CTLFLAG_READWRITE, CTLTYPE_BOOL, "reportreadnostop",
   1401 		    SYSCTL_DESCR("Report that a READ without STOP was attempted"
   1402 		    " by a device"),
   1403 		    NULL, 0, &sc->sc_reportreadnostop, 0,
   1404 		    CTL_HW, sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
   1405 			return error;
   1406 
   1407 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1408 		    CTLFLAG_READWRITE, CTLTYPE_INT, "busy_delay",
   1409 		    SYSCTL_DESCR("How long to wait in ms when the I2C engine is busy"),
   1410 		    umcpmio_verify_sysctl, 0, &sc->sc_busy_delay, 0,
   1411 		    CTL_HW, sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
   1412 			return error;
   1413 
   1414 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1415 		    CTLFLAG_READWRITE, CTLTYPE_INT, "retry_busy_read",
   1416 		    SYSCTL_DESCR("How many times to retry a busy I2C read"),
   1417 		    umcpmio_verify_sysctl, 0, &sc->sc_retry_busy_read, 0,
   1418 		    CTL_HW, sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
   1419 			return error;
   1420 
   1421 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1422 		    CTLFLAG_READWRITE, CTLTYPE_INT, "retry_busy_write",
   1423 		    SYSCTL_DESCR("How many times to retry a busy I2C write"),
   1424 		    umcpmio_verify_sysctl, 0, &sc->sc_retry_busy_write, 0,
   1425 		    CTL_HW, sysctlroot_num, i2c_num, CTL_CREATE, CTL_EOL)) != 0)
   1426 			return error;
   1427 	}
   1428 
   1429 	/* GPIO */
   1430 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) {
   1431 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1432 		    CTLFLAG_READONLY, CTLTYPE_INT, "counter",
   1433 		    SYSCTL_DESCR("Interrupt counter on GP6"),
   1434 		    mcp2210_verify_counter_sysctl, 0, (void *)sc, 0,
   1435 		    CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
   1436 			return error;
   1437 
   1438 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1439 		    CTLFLAG_READWRITE, CTLTYPE_BOOL, "reset_counter",
   1440 		    SYSCTL_DESCR("Reset interrupt counter on GP6"),
   1441 		    mcp2210_reset_counter_sysctl, 0, (void *)sc, 0,
   1442 		    CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
   1443 			return error;
   1444 	}
   1445 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
   1446 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1447 		    CTLFLAG_READONLY, CTLTYPE_STRING, "clock_duty_cycles",
   1448 		    SYSCTL_DESCR("Valid duty cycles for GPIO clock on"
   1449 		    " GP1 ALT3 duty cycle"),
   1450 		    0, 0, __UNCONST(umcpmio_valid_dcs), sizeof(umcpmio_valid_dcs) + 1,
   1451 		    CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
   1452 			return error;
   1453 
   1454 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1455 		    CTLFLAG_READWRITE, CTLTYPE_STRING, "clock_duty_cycle",
   1456 		    SYSCTL_DESCR("GPIO clock on GP1 ALT3 duty cycle"),
   1457 		    mcp2221_verify_gpioclock_dc_sysctl, 0, (void *)sc, MCP2221_DC_NAME,
   1458 		    CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
   1459 			return error;
   1460 
   1461 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1462 		    CTLFLAG_READONLY, CTLTYPE_STRING, "clock_dividers",
   1463 		    SYSCTL_DESCR("Valid clock dividers for GPIO clock on GP1"
   1464 		    " with ALT3"),
   1465 		    0, 0, __UNCONST(umcpmio_valid_cds), sizeof(umcpmio_valid_cds) + 1,
   1466 		    CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
   1467 			return error;
   1468 
   1469 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1470 		    CTLFLAG_READWRITE, CTLTYPE_STRING, "clock_divider",
   1471 		    SYSCTL_DESCR("GPIO clock on GP1 ALT3 clock divider"),
   1472 		    mcp2221_verify_gpioclock_cd_sysctl, 0, (void *)sc, MCP2221_CD_NAME,
   1473 		    CTL_HW, sysctlroot_num, gpio_num, CTL_CREATE, CTL_EOL)) != 0)
   1474 			return error;
   1475 
   1476 		/* ADC and DAC */
   1477 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1478 		    CTLFLAG_READONLY, CTLTYPE_STRING, "vrefs",
   1479 		    SYSCTL_DESCR("Valid vref values for ADC and DAC"),
   1480 		    0, 0,
   1481 		    __UNCONST(umcpmio_valid_vrefs), sizeof(umcpmio_valid_vrefs) + 1,
   1482 		    CTL_HW, sysctlroot_num, adc_dac_num, CTL_CREATE, CTL_EOL)) != 0)
   1483 			return error;
   1484 
   1485 		/* ADC */
   1486 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1487 		    CTLFLAG_READWRITE, CTLTYPE_STRING, "vref",
   1488 		    SYSCTL_DESCR("ADC voltage reference"),
   1489 		    mcp2221_verify_adc_sysctl, 0, (void *)sc, MCP2221_VREF_NAME,
   1490 		    CTL_HW, sysctlroot_num, adc_num, CTL_CREATE, CTL_EOL)) != 0)
   1491 			return error;
   1492 
   1493 		/* DAC */
   1494 		if ((error = sysctl_createv(&sc->sc_umcpmiolog, 0, NULL, &cnode,
   1495 		    CTLFLAG_READWRITE, CTLTYPE_STRING, "vref",
   1496 		    SYSCTL_DESCR("DAC voltage reference"),
   1497 		    mcp2221_verify_dac_sysctl, 0, (void *)sc, MCP2221_VREF_NAME,
   1498 		    CTL_HW, sysctlroot_num, dac_num, CTL_CREATE, CTL_EOL)) != 0)
   1499 			return error;
   1500 	}
   1501 	return 0;
   1502 }
   1503 
   1504 static int
   1505 umcpmio_match(device_t parent, cfdata_t match, void *aux)
   1506 {
   1507 	struct uhidev_attach_arg *uha = aux;
   1508 
   1509 	return umcpmio_lookup(uha->uiaa->uiaa_vendor, uha->uiaa->uiaa_product)
   1510 	    != NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
   1511 }
   1512 
   1513 static void
   1514 umcpmio_attach(device_t parent, device_t self, void *aux)
   1515 {
   1516 	struct umcpmio_softc *sc = device_private(self);
   1517 	struct uhidev_attach_arg *uha = aux;
   1518 	struct mcp2221_status_res status_res;
   1519 	int err;
   1520 
   1521 	sc->sc_dev = self;
   1522 	sc->sc_hdev = uha->parent;
   1523 	sc->sc_udev = uha->uiaa->uiaa_device;
   1524 
   1525 	sc->sc_umcpmiolog = NULL;
   1526 	sc->sc_dumpbuffer = false;
   1527 
   1528 	sc->sc_cv_wait = 2500;
   1529 	sc->sc_response_errcnt = 5;
   1530 	sc->sc_dev_open[CONTROL_DEV] = false;
   1531 	sc->sc_dev_open[GP1_DEV] = false;
   1532 	sc->sc_dev_open[GP2_DEV] = false;
   1533 	sc->sc_dev_open[GP3_DEV] = false;
   1534 	sc->sc_dev_open[EEPROM_DEV] = false;
   1535 	sc->sc_adcdac_pin_flags[0] =
   1536 	    sc->sc_adcdac_pin_flags[1] =
   1537 	    sc->sc_adcdac_pin_flags[2] =
   1538 	    sc->sc_adcdac_pin_flags[3] = -1;
   1539 
   1540 	aprint_normal("\n");
   1541 
   1542 	int info_index = -1;
   1543 	for (int c = 0; c < __arraycount(umcpmio_chip_infos); c++){
   1544 		if (uha->uiaa->uiaa_product == umcpmio_chip_infos[c].usb_id) {
   1545 			info_index = c;
   1546 			break;
   1547 		}
   1548 	}
   1549 
   1550 	if (info_index == -1)
   1551 		panic("umcpmio_attach: Unknown info_index\n");
   1552 
   1553 	sc->sc_chipinfo = &umcpmio_chip_infos[info_index];
   1554 
   1555 	if ((err = umcpmio_sysctl_init(sc)) != 0) {
   1556 		aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", err);
   1557 		return;
   1558 	}
   1559 	mutex_init(&sc->sc_action_mutex, MUTEX_DEFAULT, IPL_NONE);
   1560 	cv_init(&sc->sc_res_cv, "mcpres");
   1561 	mutex_init(&sc->sc_res_mutex, MUTEX_DEFAULT, IPL_NONE);
   1562 	sc->sc_res_buffer = NULL;
   1563 	sc->sc_res_ready = false;
   1564 	mutex_init(&sc->sc_spi_mutex, MUTEX_DEFAULT, IPL_NONE);
   1565 
   1566 	err = umcpmio_hid_open(sc);
   1567 	if (err)
   1568 		return;
   1569 
   1570 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) {
   1571 		aprint_normal_dev(sc->sc_dev, "MCP-2210\n");
   1572 	}
   1573 	if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) {
   1574 		mutex_enter(&sc->sc_action_mutex);
   1575 		err = mcp2221_get_status(sc, &status_res);
   1576 		mutex_exit(&sc->sc_action_mutex);
   1577 		if (err) {
   1578 			aprint_error_dev(sc->sc_dev, "umcpmio_attach: "
   1579 			    " mcp2221_get_status: err=%d\n", err);
   1580 			return;
   1581 		}
   1582 		aprint_normal_dev(sc->sc_dev,
   1583 		    "MCP-2221 / MCP-2221A: "
   1584 		    "Hardware revision: %d.%d, Firmware revision: %d.%d\n",
   1585 		    status_res.mcp2221_hardware_rev_major,
   1586 		    status_res.mcp2221_hardware_rev_minor,
   1587 		    status_res.mcp2221_firmware_rev_major,
   1588 		    status_res.mcp2221_firmware_rev_minor);
   1589 
   1590 	}
   1591 
   1592 	/* The IIC or SPI bus should attach, but if they will not, do not
   1593 	 * get too upset about it.
   1594 	 */
   1595 
   1596 	if (sc->sc_chipinfo->num_spi_slaves > 0) {
   1597 		err = umcpmio_spi_attach(sc);
   1598 		if (err)
   1599 			aprint_error_dev(sc->sc_dev, "umcpmio_attach: Unable"
   1600 			    " to attach SPI bus.  Continuing anyway.\n");
   1601 	}
   1602 	if (sc->sc_chipinfo->num_iic_ports > 0) {
   1603 		err = umcpmio_i2c_attach(sc);
   1604 		if (err)
   1605 			aprint_error_dev(sc->sc_dev, "umcpmio_attach: Unable"
   1606 			    " to set I2C speed.  Continuing anyway.\n");
   1607 	}
   1608 	if (sc->sc_chipinfo->num_gpio_pins > 0)
   1609 		umcpmio_gpio_attach(sc);
   1610 }
   1611 
   1612 static int
   1613 umcpmio_detach(device_t self, int flags)
   1614 {
   1615 	struct umcpmio_softc *sc = device_private(self);
   1616 	struct umcpmio_spi_received *r;
   1617 	int err;
   1618 
   1619 	sc->sc_dying = true;
   1620 
   1621 	/* Not sure if this is needed.... */
   1622 
   1623 	flags |= DETACH_FORCE;
   1624 
   1625 	err = config_detach_children(self, flags);
   1626 	if (err)
   1627 		return err;
   1628 
   1629 	mutex_enter(&sc->sc_action_mutex);
   1630 	uhidev_close(sc->sc_hdev);
   1631 	mutex_destroy(&sc->sc_res_mutex);
   1632 	cv_destroy(&sc->sc_res_cv);
   1633 	sysctl_teardown(&sc->sc_umcpmiolog);
   1634 	mutex_exit(&sc->sc_action_mutex);
   1635 	mutex_destroy(&sc->sc_action_mutex);
   1636 
   1637 	if (sc->sc_chipinfo->num_spi_slaves > 0) {
   1638 		mutex_enter(&sc->sc_spi_mutex);
   1639 		for (int slave = 0; slave < sc->sc_chipinfo->num_spi_slaves; slave++){
   1640 			if (!SIMPLEQ_EMPTY(&sc->sc_received[slave])) {
   1641 				while ((r = SIMPLEQ_FIRST(&sc->sc_received[slave])) != NULL) {
   1642 					SIMPLEQ_REMOVE_HEAD(&sc->sc_received[slave], umcpmio_spi_received_q);
   1643 					kmem_free(r, sizeof(struct umcpmio_spi_received));
   1644 				}
   1645 			}
   1646 		}
   1647 		mutex_exit(&sc->sc_spi_mutex);
   1648 	}
   1649 	mutex_destroy(&sc->sc_spi_mutex);
   1650 
   1651 	return 0;
   1652 }
   1653 
   1654 static int
   1655 umcpmio_activate(device_t self, enum devact act)
   1656 {
   1657 	struct umcpmio_softc *sc = device_private(self);
   1658 
   1659 	DPRINTFN(5, ("umcpmio_activate: %d\n", act));
   1660 
   1661 	switch (act) {
   1662 	case DVACT_DEACTIVATE:
   1663 		sc->sc_dying = true;
   1664 		return 0;
   1665 	default:
   1666 		return EOPNOTSUPP;
   1667 	}
   1668 }
   1669