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