1 /* $OpenBSD: vldcp.c,v 1.25 2022/08/17 15:26:56 visa Exp $ */ 2 /* 3 * Copyright (c) 2009, 2012 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/conf.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 #include <sys/proc.h> 23 #include <sys/systm.h> 24 25 #include <machine/autoconf.h> 26 #include <machine/hypervisor.h> 27 #include <machine/mdesc.h> 28 29 #include <uvm/uvm_extern.h> 30 31 #include <sparc64/dev/cbusvar.h> 32 #include <sparc64/dev/ldcvar.h> 33 34 #ifdef VLDCP_DEBUG 35 #define DPRINTF(x) printf x 36 #else 37 #define DPRINTF(x) 38 #endif 39 40 #include <sys/ioccom.h> 41 42 struct hv_io { 43 uint64_t hi_cookie; 44 void *hi_addr; 45 size_t hi_len; 46 }; 47 48 #define HVIOCREAD _IOW('h', 0, struct hv_io) 49 #define HVIOCWRITE _IOW('h', 1, struct hv_io) 50 51 #define VLDCP_TX_ENTRIES 128 52 #define VLDCP_RX_ENTRIES 128 53 54 struct vldcp_softc { 55 struct device sc_dv; 56 bus_space_tag_t sc_bustag; 57 bus_dma_tag_t sc_dmatag; 58 59 uint64_t sc_tx_ino; 60 uint64_t sc_rx_ino; 61 void *sc_tx_ih; 62 void *sc_rx_ih; 63 64 struct ldc_conn sc_lc; 65 66 struct selinfo sc_rsel; 67 struct selinfo sc_wsel; 68 }; 69 70 int vldcp_match(struct device *, void *, void *); 71 void vldcp_attach(struct device *, struct device *, void *); 72 void filt_vldcprdetach(struct knote *); 73 void filt_vldcpwdetach(struct knote *); 74 int filt_vldcpread(struct knote *, long); 75 int filt_vldcpwrite(struct knote *, long); 76 int vldcpkqfilter(dev_t, struct knote *); 77 78 const struct cfattach vldcp_ca = { 79 sizeof(struct vldcp_softc), vldcp_match, vldcp_attach 80 }; 81 82 struct cfdriver vldcp_cd = { 83 NULL, "vldcp", DV_DULL 84 }; 85 86 int vldcp_tx_intr(void *); 87 int vldcp_rx_intr(void *); 88 89 /* 90 * We attach to certain well-known channels. These are assigned fixed 91 * device minor device numbers through their index in the table below. 92 * So "hvctl" gets minor 0, "spds" gets minor 1, etc. etc. 93 * 94 * We also attach to the domain services channels. These are named 95 * "ldom-<guestname>" and get assigned a device minor starting at 96 * VLDC_LDOM_OFFSET. 97 */ 98 #define VLDC_NUM_SERVICES 64 99 #define VLDC_LDOM_OFFSET 32 100 int vldc_num_ldoms; 101 102 struct vldc_svc { 103 const char *vs_name; 104 struct vldcp_softc *vs_sc; 105 }; 106 107 struct vldc_svc vldc_svc[VLDC_NUM_SERVICES] = { 108 { "hvctl" }, 109 { "spds" }, 110 { NULL } 111 }; 112 113 int 114 vldcp_match(struct device *parent, void *match, void *aux) 115 { 116 struct cbus_attach_args *ca = aux; 117 struct vldc_svc *svc; 118 119 for (svc = vldc_svc; svc->vs_name != NULL; svc++) 120 if (strcmp(ca->ca_name, svc->vs_name) == 0) 121 return (1); 122 123 if (strncmp(ca->ca_name, "ldom-", 5) == 0 && 124 strcmp(ca->ca_name, "ldom-primary") != 0) 125 return (1); 126 127 return (0); 128 } 129 130 void 131 vldcp_attach(struct device *parent, struct device *self, void *aux) 132 { 133 struct vldcp_softc *sc = (struct vldcp_softc *)self; 134 struct cbus_attach_args *ca = aux; 135 struct vldc_svc *svc; 136 struct ldc_conn *lc; 137 138 sc->sc_bustag = ca->ca_bustag; 139 sc->sc_dmatag = ca->ca_dmatag; 140 sc->sc_tx_ino = ca->ca_tx_ino; 141 sc->sc_rx_ino = ca->ca_rx_ino; 142 143 printf(": ivec 0x%llx, 0x%llx", sc->sc_tx_ino, sc->sc_rx_ino); 144 145 /* 146 * Un-configure queues before registering interrupt handlers, 147 * such that we dont get any stale LDC packets or events. 148 */ 149 hv_ldc_tx_qconf(ca->ca_id, 0, 0); 150 hv_ldc_rx_qconf(ca->ca_id, 0, 0); 151 152 sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino, 153 IPL_TTY, 0, vldcp_tx_intr, sc, sc->sc_dv.dv_xname); 154 sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino, 155 IPL_TTY, 0, vldcp_rx_intr, sc, sc->sc_dv.dv_xname); 156 if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) { 157 printf(", can't establish interrupt\n"); 158 return; 159 } 160 161 lc = &sc->sc_lc; 162 lc->lc_id = ca->ca_id; 163 lc->lc_sc = sc; 164 165 lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_TX_ENTRIES); 166 if (lc->lc_txq == NULL) { 167 printf(", can't allocate tx queue\n"); 168 return; 169 } 170 171 lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_RX_ENTRIES); 172 if (lc->lc_rxq == NULL) { 173 printf(", can't allocate rx queue\n"); 174 goto free_txqueue; 175 } 176 lc->lc_rx_state = LDC_CHANNEL_INIT; 177 178 for (svc = vldc_svc; svc->vs_name != NULL; svc++) { 179 if (strcmp(ca->ca_name, svc->vs_name) == 0) { 180 svc->vs_sc = sc; 181 break; 182 } 183 } 184 185 if (strncmp(ca->ca_name, "ldom-", 5) == 0 && 186 strcmp(ca->ca_name, "ldom-primary") != 0) { 187 int minor = VLDC_LDOM_OFFSET + vldc_num_ldoms++; 188 if (minor < nitems(vldc_svc)) 189 vldc_svc[minor].vs_sc = sc; 190 } 191 192 printf(" channel \"%s\"\n", ca->ca_name); 193 return; 194 195 #if 0 196 free_rxqueue: 197 ldc_queue_free(sc->sc_dmatag, lc->lc_rxq); 198 #endif 199 free_txqueue: 200 ldc_queue_free(sc->sc_dmatag, lc->lc_txq); 201 } 202 203 int 204 vldcp_tx_intr(void *arg) 205 { 206 struct vldcp_softc *sc = arg; 207 struct ldc_conn *lc = &sc->sc_lc; 208 uint64_t tx_head, tx_tail, tx_state; 209 int err; 210 211 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 212 if (err != H_EOK) { 213 printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); 214 return (0); 215 } 216 217 if (tx_state != lc->lc_tx_state) { 218 switch (tx_state) { 219 case LDC_CHANNEL_DOWN: 220 DPRINTF(("%s: Tx link down\n", __func__)); 221 break; 222 case LDC_CHANNEL_UP: 223 DPRINTF(("%s: Tx link up\n", __func__)); 224 break; 225 case LDC_CHANNEL_RESET: 226 DPRINTF(("%s: Tx link reset\n", __func__)); 227 break; 228 } 229 lc->lc_tx_state = tx_state; 230 } 231 232 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); 233 selwakeup(&sc->sc_wsel); 234 wakeup(lc->lc_txq); 235 return (1); 236 } 237 238 int 239 vldcp_rx_intr(void *arg) 240 { 241 struct vldcp_softc *sc = arg; 242 struct ldc_conn *lc = &sc->sc_lc; 243 uint64_t rx_head, rx_tail, rx_state; 244 int err; 245 246 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 247 if (err != H_EOK) { 248 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 249 return (0); 250 } 251 252 if (rx_state != lc->lc_rx_state) { 253 switch (rx_state) { 254 case LDC_CHANNEL_DOWN: 255 DPRINTF(("%s: Rx link down\n", __func__)); 256 if (rx_head == rx_tail) 257 break; 258 /* Discard and ack pending I/O. */ 259 DPRINTF(("setting rx qhead to %llx\n", rx_tail)); 260 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail); 261 if (err == H_EOK) 262 break; 263 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 264 break; 265 case LDC_CHANNEL_UP: 266 DPRINTF(("%s: Rx link up\n", __func__)); 267 break; 268 case LDC_CHANNEL_RESET: 269 DPRINTF(("%s: Rx link reset\n", __func__)); 270 if (rx_head == rx_tail) 271 break; 272 /* Discard and ack pending I/O. */ 273 DPRINTF(("setting rx qhead to %llx\n", rx_tail)); 274 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail); 275 if (err == H_EOK) 276 break; 277 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 278 break; 279 } 280 lc->lc_rx_state = rx_state; 281 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 282 INTR_DISABLED); 283 selwakeup(&sc->sc_rsel); 284 wakeup(lc->lc_rxq); 285 return (1); 286 } 287 288 if (rx_head == rx_tail) 289 return (0); 290 291 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); 292 selwakeup(&sc->sc_rsel); 293 wakeup(lc->lc_rxq); 294 return (1); 295 } 296 297 cdev_decl(vldcp); 298 struct vldcp_softc *vldcp_lookup(dev_t); 299 300 struct vldcp_softc * 301 vldcp_lookup(dev_t dev) 302 { 303 struct vldcp_softc *sc = NULL; 304 305 if (minor(dev) < nitems(vldc_svc)) 306 sc = vldc_svc[minor(dev)].vs_sc; 307 308 if (sc) 309 device_ref(&sc->sc_dv); 310 311 return (sc); 312 } 313 314 int 315 vldcpopen(dev_t dev, int flag, int mode, struct proc *p) 316 { 317 struct vldcp_softc *sc; 318 struct ldc_conn *lc; 319 uint64_t rx_head, rx_tail, rx_state; 320 int err; 321 322 sc = vldcp_lookup(dev); 323 if (sc == NULL) 324 return (ENXIO); 325 lc = &sc->sc_lc; 326 327 err = hv_ldc_tx_qconf(lc->lc_id, 328 lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries); 329 if (err != H_EOK) 330 printf("%s: hv_ldc_tx_qconf %d\n", __func__, err); 331 332 err = hv_ldc_rx_qconf(lc->lc_id, 333 lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries); 334 if (err != H_EOK) 335 printf("%s: hv_ldc_rx_qconf %d\n", __func__, err); 336 337 /* Clear a pending channel reset. */ 338 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 339 if (err != H_EOK) 340 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 341 342 device_unref(&sc->sc_dv); 343 return (0); 344 } 345 346 int 347 vldcpclose(dev_t dev, int flag, int mode, struct proc *p) 348 { 349 struct vldcp_softc *sc; 350 351 sc = vldcp_lookup(dev); 352 if (sc == NULL) 353 return (ENXIO); 354 355 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); 356 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); 357 358 hv_ldc_tx_qconf(sc->sc_lc.lc_id, 0, 0); 359 hv_ldc_rx_qconf(sc->sc_lc.lc_id, 0, 0); 360 361 device_unref(&sc->sc_dv); 362 return (0); 363 } 364 365 int 366 vldcpread(dev_t dev, struct uio *uio, int ioflag) 367 { 368 struct vldcp_softc *sc; 369 struct ldc_conn *lc; 370 uint64_t rx_head, rx_tail, rx_state; 371 int err, ret; 372 int s; 373 374 sc = vldcp_lookup(dev); 375 if (sc == NULL) 376 return (ENXIO); 377 lc = &sc->sc_lc; 378 379 if (uio->uio_resid != 64) { 380 device_unref(&sc->sc_dv); 381 return (EINVAL); 382 } 383 384 s = spltty(); 385 retry: 386 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 387 if (err != H_EOK) { 388 splx(s); 389 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 390 device_unref(&sc->sc_dv); 391 return (EIO); 392 } 393 394 DPRINTF(("rx head %llx, rx tail %llx, state %lld\n", rx_head, rx_tail, rx_state)); 395 396 if (rx_state != LDC_CHANNEL_UP) { 397 splx(s); 398 device_unref(&sc->sc_dv); 399 return (EIO); 400 } 401 402 if (rx_head == rx_tail) { 403 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 404 INTR_ENABLED); 405 ret = tsleep_nsec(lc->lc_rxq, PWAIT | PCATCH, "hvrd", INFSLP); 406 if (ret) { 407 splx(s); 408 device_unref(&sc->sc_dv); 409 return (ret); 410 } 411 goto retry; 412 } 413 414 ret = uiomove(lc->lc_rxq->lq_va + rx_head, 64, uio); 415 416 rx_head += 64; 417 rx_head &= ((lc->lc_rxq->lq_nentries * 64) - 1); 418 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head); 419 if (err != H_EOK) 420 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 421 422 splx(s); 423 device_unref(&sc->sc_dv); 424 return (ret); 425 } 426 427 int 428 vldcpwrite(dev_t dev, struct uio *uio, int ioflag) 429 { 430 struct vldcp_softc *sc; 431 struct ldc_conn *lc; 432 uint64_t tx_head, tx_tail, tx_state; 433 uint64_t next_tx_tail; 434 int err, ret; 435 int s; 436 437 sc = vldcp_lookup(dev); 438 if (sc == NULL) 439 return (ENXIO); 440 lc = &sc->sc_lc; 441 442 if (uio->uio_resid != 64) { 443 device_unref(&sc->sc_dv); 444 return (EINVAL); 445 } 446 447 s = spltty(); 448 retry: 449 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 450 if (err != H_EOK) { 451 splx(s); 452 printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); 453 device_unref(&sc->sc_dv); 454 return (EIO); 455 } 456 457 if (tx_state != LDC_CHANNEL_UP) { 458 splx(s); 459 device_unref(&sc->sc_dv); 460 return (EIO); 461 } 462 463 DPRINTF(("tx head %llx, tx tail %llx\n", tx_head, tx_tail)); 464 465 next_tx_tail = tx_tail + 64; 466 next_tx_tail &= ((lc->lc_txq->lq_nentries * 64) - 1); 467 468 if (tx_head == next_tx_tail) { 469 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 470 INTR_ENABLED); 471 ret = tsleep_nsec(lc->lc_txq, PWAIT | PCATCH, "hvwr", INFSLP); 472 if (ret) { 473 splx(s); 474 device_unref(&sc->sc_dv); 475 return (ret); 476 } 477 goto retry; 478 } 479 splx(s); 480 481 ret = uiomove(lc->lc_txq->lq_va + tx_tail, 64, uio); 482 483 err = hv_ldc_tx_set_qtail(lc->lc_id, next_tx_tail); 484 if (err != H_EOK) { 485 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); 486 device_unref(&sc->sc_dv); 487 return (EIO); 488 } 489 490 device_unref(&sc->sc_dv); 491 return (ret); 492 } 493 494 int 495 vldcpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 496 { 497 struct vldcp_softc *sc; 498 struct ldc_conn *lc; 499 struct hv_io *hi = (struct hv_io *)data; 500 paddr_t pa, offset; 501 psize_t nbytes; 502 caddr_t buf; 503 size_t size; 504 int err; 505 506 sc = vldcp_lookup(dev); 507 if (sc == NULL) 508 return (ENXIO); 509 lc = &sc->sc_lc; 510 511 switch (cmd) { 512 case HVIOCREAD: 513 case HVIOCWRITE: 514 break; 515 default: 516 device_unref(&sc->sc_dv); 517 return (ENOTTY); 518 } 519 520 buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 521 522 switch(cmd) { 523 case HVIOCREAD: 524 size = hi->hi_len; 525 offset = 0; 526 while (size > 0) { 527 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa); 528 nbytes = min(PAGE_SIZE, size); 529 err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN, 530 hi->hi_cookie + offset, pa, nbytes, &nbytes); 531 if (err != H_EOK) { 532 printf("hv_ldc_copy %d\n", err); 533 free(buf, M_DEVBUF, 0); 534 device_unref(&sc->sc_dv); 535 return (EINVAL); 536 } 537 err = copyout(buf, (caddr_t)hi->hi_addr + offset, nbytes); 538 if (err) { 539 free(buf, M_DEVBUF, 0); 540 device_unref(&sc->sc_dv); 541 return (err); 542 } 543 size -= nbytes; 544 offset += nbytes; 545 } 546 break; 547 case HVIOCWRITE: 548 size = hi->hi_len; 549 offset = 0; 550 while (size > 0) { 551 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa); 552 nbytes = min(PAGE_SIZE, size); 553 err = copyin((caddr_t)hi->hi_addr + offset, buf, nbytes); 554 if (err) { 555 free(buf, M_DEVBUF, 0); 556 device_unref(&sc->sc_dv); 557 return (err); 558 } 559 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 560 hi->hi_cookie + offset, pa, nbytes, &nbytes); 561 if (err != H_EOK) { 562 printf("hv_ldc_copy %d\n", err); 563 free(buf, M_DEVBUF, 0); 564 device_unref(&sc->sc_dv); 565 return (EINVAL); 566 } 567 size -= nbytes; 568 offset += nbytes; 569 } 570 break; 571 572 } 573 574 free(buf, M_DEVBUF, 0); 575 576 device_unref(&sc->sc_dv); 577 return (0); 578 } 579 580 void 581 filt_vldcprdetach(struct knote *kn) 582 { 583 struct vldcp_softc *sc = (void *)kn->kn_hook; 584 int s; 585 586 s = spltty(); 587 klist_remove_locked(&sc->sc_rsel.si_note, kn); 588 splx(s); 589 } 590 591 void 592 filt_vldcpwdetach(struct knote *kn) 593 { 594 struct vldcp_softc *sc = (void *)kn->kn_hook; 595 int s; 596 597 s = spltty(); 598 klist_remove_locked(&sc->sc_wsel.si_note, kn); 599 splx(s); 600 } 601 602 int 603 filt_vldcpread(struct knote *kn, long hint) 604 { 605 struct vldcp_softc *sc = (void *)kn->kn_hook; 606 struct ldc_conn *lc = &sc->sc_lc; 607 uint64_t head, tail, avail, state; 608 int s, err; 609 610 s = spltty(); 611 err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state); 612 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) { 613 avail = (tail - head) / sizeof(struct ldc_pkt) + 614 lc->lc_rxq->lq_nentries; 615 avail %= lc->lc_rxq->lq_nentries; 616 kn->kn_data = avail; 617 } else { 618 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 619 INTR_ENABLED); 620 kn->kn_data = 0; 621 } 622 splx(s); 623 624 return (kn->kn_data > 0); 625 } 626 627 int 628 filt_vldcwrite(struct knote *kn, long hint) 629 { 630 struct vldcp_softc *sc = (void *)kn->kn_hook; 631 struct ldc_conn *lc = &sc->sc_lc; 632 uint64_t head, tail, avail, state; 633 int s, err; 634 635 s = spltty(); 636 err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state); 637 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) { 638 avail = (head - tail) / sizeof(struct ldc_pkt) + 639 lc->lc_txq->lq_nentries - 1; 640 avail %= lc->lc_txq->lq_nentries; 641 kn->kn_data = avail; 642 } else { 643 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 644 INTR_ENABLED); 645 kn->kn_data = 0; 646 } 647 splx(s); 648 649 return (kn->kn_data > 0); 650 } 651 652 const struct filterops vldcpread_filtops = { 653 .f_flags = FILTEROP_ISFD, 654 .f_attach = NULL, 655 .f_detach = filt_vldcprdetach, 656 .f_event = filt_vldcpread, 657 }; 658 659 const struct filterops vldcpwrite_filtops = { 660 .f_flags = FILTEROP_ISFD, 661 .f_attach = NULL, 662 .f_detach = filt_vldcpwdetach, 663 .f_event = filt_vldcwrite, 664 }; 665 666 int 667 vldcpkqfilter(dev_t dev, struct knote *kn) 668 { 669 struct vldcp_softc *sc; 670 struct klist *klist; 671 int s; 672 673 sc = vldcp_lookup(dev); 674 if (sc == NULL) 675 return (ENXIO); 676 677 switch (kn->kn_filter) { 678 case EVFILT_READ: 679 klist = &sc->sc_rsel.si_note; 680 kn->kn_fop = &vldcpread_filtops; 681 break; 682 case EVFILT_WRITE: 683 klist = &sc->sc_wsel.si_note; 684 kn->kn_fop = &vldcpwrite_filtops; 685 break; 686 687 default: 688 device_unref(&sc->sc_dv); 689 return (EINVAL); 690 } 691 692 kn->kn_hook = sc; 693 694 s = spltty(); 695 klist_insert_locked(klist, kn); 696 splx(s); 697 698 device_unref(&sc->sc_dv); 699 return (0); 700 } 701