1 /* 2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com> All rights reserved. 3 * cdevsw from kern/kern_conf.c Copyright (c) 1995 Terrence R. Lambert 4 * cdevsw from kern/kern_conf.c Copyright (c) 1995 Julian R. Elishcer, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $DragonFly: src/sys/kern/kern_device.c,v 1.7 2003/11/24 20:46:01 dillon Exp $ 29 */ 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/sysctl.h> 33 #include <sys/systm.h> 34 #include <sys/module.h> 35 #include <sys/malloc.h> 36 #include <sys/conf.h> 37 #include <sys/vnode.h> 38 #include <sys/queue.h> 39 #include <sys/msgport.h> 40 #include <sys/device.h> 41 #include <machine/stdarg.h> 42 #include <sys/proc.h> 43 #include <sys/thread2.h> 44 #include <sys/msgport2.h> 45 46 static struct cdevsw *cdevsw[NUMCDEVSW]; 47 static struct lwkt_port *cdevport[NUMCDEVSW]; 48 49 static int cdevsw_putport(lwkt_port_t port, lwkt_msg_t msg); 50 51 /* 52 * Initialize a message port to serve as the default message-handling port 53 * for device operations. This message port provides compatibility with 54 * traditional cdevsw dispatch functions. There are two primary modes: 55 * 56 * mp_td is NULL: The d_autoq mask is ignored and all messages are translated 57 * into directly, synchronous cdevsw calls. 58 * 59 * mp_td not NULL: The d_autoq mask is used to determine which messages should 60 * be queued and which should be handled synchronously. 61 * 62 * Don't worry too much about optimizing this code, the critical devices 63 * will implement their own port messaging functions directly. 64 */ 65 static void 66 init_default_cdevsw_port(lwkt_port_t port) 67 { 68 lwkt_initport(port, NULL); 69 port->mp_putport = cdevsw_putport; 70 } 71 72 static 73 int 74 cdevsw_putport(lwkt_port_t port, lwkt_msg_t lmsg) 75 { 76 cdevallmsg_t msg = (cdevallmsg_t)lmsg; 77 struct cdevsw *csw = msg->am_msg.csw; 78 int error; 79 80 /* 81 * If queueable then officially queue the message 82 */ 83 if (port->mp_td) { 84 int mask = (1 << (msg->am_lmsg.ms_cmd & MSG_SUBCMD_MASK)); 85 if (csw->d_autoq & mask) 86 return(lwkt_beginmsg(port, &msg->am_lmsg)); 87 } 88 89 /* 90 * Run the device switch function synchronously in the context of the 91 * caller and return a synchronous error code (anything not EASYNC). 92 */ 93 switch(msg->am_lmsg.ms_cmd) { 94 case CDEV_CMD_OPEN: 95 error = csw->old_open( 96 msg->am_open.msg.dev, 97 msg->am_open.oflags, 98 msg->am_open.devtype, 99 msg->am_open.td); 100 break; 101 case CDEV_CMD_CLOSE: 102 error = csw->old_close( 103 msg->am_close.msg.dev, 104 msg->am_close.fflag, 105 msg->am_close.devtype, 106 msg->am_close.td); 107 break; 108 case CDEV_CMD_STRATEGY: 109 csw->old_strategy(msg->am_strategy.bp); 110 error = 0; 111 break; 112 case CDEV_CMD_IOCTL: 113 error = csw->old_ioctl( 114 msg->am_ioctl.msg.dev, 115 msg->am_ioctl.cmd, 116 msg->am_ioctl.data, 117 msg->am_ioctl.fflag, 118 msg->am_ioctl.td); 119 break; 120 case CDEV_CMD_DUMP: 121 error = csw->old_dump(msg->am_ioctl.msg.dev); 122 break; 123 case CDEV_CMD_PSIZE: 124 msg->am_psize.result = csw->old_psize(msg->am_psize.msg.dev); 125 error = 0; /* XXX */ 126 break; 127 case CDEV_CMD_READ: 128 error = csw->old_read( 129 msg->am_read.msg.dev, 130 msg->am_read.uio, 131 msg->am_read.ioflag); 132 break; 133 case CDEV_CMD_WRITE: 134 error = csw->old_write( 135 msg->am_read.msg.dev, 136 msg->am_read.uio, 137 msg->am_read.ioflag); 138 break; 139 case CDEV_CMD_POLL: 140 msg->am_poll.events = csw->old_poll( 141 msg->am_poll.msg.dev, 142 msg->am_poll.events, 143 msg->am_poll.td); 144 error = 0; 145 break; 146 case CDEV_CMD_KQFILTER: 147 msg->am_kqfilter.result = csw->old_kqfilter( 148 msg->am_kqfilter.msg.dev, 149 msg->am_kqfilter.kn); 150 error = 0; 151 break; 152 case CDEV_CMD_MMAP: 153 msg->am_mmap.result = csw->old_mmap( 154 msg->am_mmap.msg.dev, 155 msg->am_mmap.offset, 156 msg->am_mmap.nprot); 157 error = 0; /* XXX */ 158 break; 159 default: 160 error = ENOSYS; 161 break; 162 } 163 KKASSERT(error != EASYNC); 164 return(error); 165 } 166 167 /* 168 * These device dispatch functions provide convenient entry points for 169 * any code wishing to make a dev call. 170 * 171 * YYY we ought to be able to optimize the port lookup by caching it in 172 * the dev_t structure itself. 173 */ 174 static __inline 175 struct cdevsw * 176 _devsw(dev_t dev) 177 { 178 if (dev == NULL) 179 return(NULL); 180 if (dev->si_devsw) 181 return (dev->si_devsw); 182 return(cdevsw[major(dev)]); 183 } 184 185 static __inline 186 lwkt_port_t 187 _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd) 188 { 189 struct cdevsw *csw; 190 191 lwkt_initmsg(&msg->msg, &curthread->td_msgport, cmd); 192 msg->dev = dev; 193 msg->csw = csw = _devsw(dev); 194 if (csw != NULL) { /* YYY too hackish */ 195 KKASSERT(csw->d_port); /* YYY too hackish */ 196 if (cdevport[major(dev)]) /* YYY too hackish */ 197 return(cdevport[major(dev)]); 198 return(csw->d_port); 199 } 200 return(NULL); 201 } 202 203 int 204 dev_dopen(dev_t dev, int oflags, int devtype, thread_t td) 205 { 206 struct cdevmsg_open msg; 207 lwkt_port_t port; 208 209 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN); 210 if (port == NULL) 211 return(ENXIO); 212 msg.oflags = oflags; 213 msg.devtype = devtype; 214 msg.td = td; 215 return(lwkt_domsg(port, &msg.msg.msg)); 216 } 217 218 int 219 dev_dclose(dev_t dev, int fflag, int devtype, thread_t td) 220 { 221 struct cdevmsg_close msg; 222 lwkt_port_t port; 223 224 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE); 225 if (port == NULL) 226 return(ENXIO); 227 msg.fflag = fflag; 228 msg.devtype = devtype; 229 msg.td = td; 230 return(lwkt_domsg(port, &msg.msg.msg)); 231 } 232 233 void 234 dev_dstrategy(dev_t dev, struct buf *bp) 235 { 236 struct cdevmsg_strategy msg; 237 lwkt_port_t port; 238 239 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY); 240 KKASSERT(port); /* 'nostrategy' function is NULL YYY */ 241 msg.bp = bp; 242 lwkt_domsg(port, &msg.msg.msg); 243 } 244 245 int 246 dev_dioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td) 247 { 248 struct cdevmsg_ioctl msg; 249 lwkt_port_t port; 250 251 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL); 252 if (port == NULL) 253 return(ENXIO); 254 msg.cmd = cmd; 255 msg.data = data; 256 msg.fflag = fflag; 257 msg.td = td; 258 return(lwkt_domsg(port, &msg.msg.msg)); 259 } 260 261 int 262 dev_ddump(dev_t dev) 263 { 264 struct cdevmsg_dump msg; 265 lwkt_port_t port; 266 267 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP); 268 if (port == NULL) 269 return(ENXIO); 270 return(lwkt_domsg(port, &msg.msg.msg)); 271 } 272 273 int 274 dev_dpsize(dev_t dev) 275 { 276 struct cdevmsg_psize msg; 277 lwkt_port_t port; 278 int error; 279 280 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE); 281 if (port == NULL) 282 return(-1); 283 error = lwkt_domsg(port, &msg.msg.msg); 284 if (error == 0) 285 return(msg.result); 286 return(-1); 287 } 288 289 int 290 dev_dread(dev_t dev, struct uio *uio, int ioflag) 291 { 292 struct cdevmsg_read msg; 293 lwkt_port_t port; 294 295 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ); 296 if (port == NULL) 297 return(ENXIO); 298 msg.uio = uio; 299 msg.ioflag = ioflag; 300 return(lwkt_domsg(port, &msg.msg.msg)); 301 } 302 303 int 304 dev_dwrite(dev_t dev, struct uio *uio, int ioflag) 305 { 306 struct cdevmsg_write msg; 307 lwkt_port_t port; 308 309 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE); 310 if (port == NULL) 311 return(ENXIO); 312 msg.uio = uio; 313 msg.ioflag = ioflag; 314 return(lwkt_domsg(port, &msg.msg.msg)); 315 } 316 317 int 318 dev_dpoll(dev_t dev, int events, thread_t td) 319 { 320 struct cdevmsg_poll msg; 321 lwkt_port_t port; 322 int error; 323 324 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL); 325 if (port == NULL) 326 return(ENXIO); 327 msg.events = events; 328 msg.td = td; 329 error = lwkt_domsg(port, &msg.msg.msg); 330 if (error == 0) 331 return(msg.events); 332 return(seltrue(dev, msg.events, td)); 333 } 334 335 int 336 dev_dkqfilter(dev_t dev, struct knote *kn) 337 { 338 struct cdevmsg_kqfilter msg; 339 lwkt_port_t port; 340 int error; 341 342 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER); 343 if (port == NULL) 344 return(ENXIO); 345 msg.kn = kn; 346 error = lwkt_domsg(port, &msg.msg.msg); 347 if (error == 0) 348 return(msg.result); 349 return(ENODEV); 350 } 351 352 int 353 dev_dmmap(dev_t dev, vm_offset_t offset, int nprot) 354 { 355 struct cdevmsg_mmap msg; 356 lwkt_port_t port; 357 int error; 358 359 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP); 360 if (port == NULL) 361 return(-1); 362 msg.offset = offset; 363 msg.nprot = nprot; 364 error = lwkt_domsg(port, &msg.msg.msg); 365 if (error == 0) 366 return(msg.result); 367 return(-1); 368 } 369 370 int 371 dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td) 372 { 373 struct cdevmsg_open msg; 374 375 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN); 376 if (port == NULL) 377 return(ENXIO); 378 msg.oflags = oflags; 379 msg.devtype = devtype; 380 msg.td = td; 381 return(lwkt_domsg(port, &msg.msg.msg)); 382 } 383 384 int 385 dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td) 386 { 387 struct cdevmsg_close msg; 388 389 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE); 390 if (port == NULL) 391 return(ENXIO); 392 msg.fflag = fflag; 393 msg.devtype = devtype; 394 msg.td = td; 395 return(lwkt_domsg(port, &msg.msg.msg)); 396 } 397 398 void 399 dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp) 400 { 401 struct cdevmsg_strategy msg; 402 403 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY); 404 KKASSERT(port); /* 'nostrategy' function is NULL YYY */ 405 msg.bp = bp; 406 lwkt_domsg(port, &msg.msg.msg); 407 } 408 409 int 410 dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td) 411 { 412 struct cdevmsg_ioctl msg; 413 414 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL); 415 if (port == NULL) 416 return(ENXIO); 417 msg.cmd = cmd; 418 msg.data = data; 419 msg.fflag = fflag; 420 msg.td = td; 421 return(lwkt_domsg(port, &msg.msg.msg)); 422 } 423 424 int 425 dev_port_ddump(lwkt_port_t port, dev_t dev) 426 { 427 struct cdevmsg_dump msg; 428 429 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP); 430 if (port == NULL) 431 return(ENXIO); 432 return(lwkt_domsg(port, &msg.msg.msg)); 433 } 434 435 int 436 dev_port_dpsize(lwkt_port_t port, dev_t dev) 437 { 438 struct cdevmsg_psize msg; 439 int error; 440 441 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE); 442 if (port == NULL) 443 return(-1); 444 error = lwkt_domsg(port, &msg.msg.msg); 445 if (error == 0) 446 return(msg.result); 447 return(-1); 448 } 449 450 int 451 dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag) 452 { 453 struct cdevmsg_read msg; 454 455 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ); 456 if (port == NULL) 457 return(ENXIO); 458 msg.uio = uio; 459 msg.ioflag = ioflag; 460 return(lwkt_domsg(port, &msg.msg.msg)); 461 } 462 463 int 464 dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag) 465 { 466 struct cdevmsg_write msg; 467 468 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE); 469 if (port == NULL) 470 return(ENXIO); 471 msg.uio = uio; 472 msg.ioflag = ioflag; 473 return(lwkt_domsg(port, &msg.msg.msg)); 474 } 475 476 int 477 dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td) 478 { 479 struct cdevmsg_poll msg; 480 int error; 481 482 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL); 483 if (port == NULL) 484 return(ENXIO); 485 msg.events = events; 486 msg.td = td; 487 error = lwkt_domsg(port, &msg.msg.msg); 488 if (error == 0) 489 return(msg.events); 490 return(seltrue(dev, msg.events, td)); 491 } 492 493 int 494 dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn) 495 { 496 struct cdevmsg_kqfilter msg; 497 int error; 498 499 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER); 500 if (port == NULL) 501 return(ENXIO); 502 msg.kn = kn; 503 error = lwkt_domsg(port, &msg.msg.msg); 504 if (error == 0) 505 return(msg.result); 506 return(ENODEV); 507 } 508 509 int 510 dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot) 511 { 512 struct cdevmsg_mmap msg; 513 int error; 514 515 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP); 516 if (port == NULL) 517 return(-1); 518 msg.offset = offset; 519 msg.nprot = nprot; 520 error = lwkt_domsg(port, &msg.msg.msg); 521 if (error == 0) 522 return(msg.result); 523 return(-1); 524 } 525 526 const char * 527 dev_dname(dev_t dev) 528 { 529 struct cdevsw *csw; 530 531 if ((csw = _devsw(dev)) != NULL) 532 return(csw->d_name); 533 return(NULL); 534 } 535 536 int 537 dev_dflags(dev_t dev) 538 { 539 struct cdevsw *csw; 540 541 if ((csw = _devsw(dev)) != NULL) 542 return(csw->d_flags); 543 return(0); 544 } 545 546 int 547 dev_dmaj(dev_t dev) 548 { 549 struct cdevsw *csw; 550 551 if ((csw = _devsw(dev)) != NULL) 552 return(csw->d_maj); 553 return(0); 554 } 555 556 lwkt_port_t 557 dev_dport(dev_t dev) 558 { 559 struct cdevsw *csw; 560 561 if ((csw = _devsw(dev)) != NULL) { 562 if (cdevport[major(dev)]) /* YYY too hackish */ 563 return(cdevport[major(dev)]); 564 return(csw->d_port); 565 } 566 return(NULL); 567 } 568 569 #if 0 570 /* 571 * cdevsw[] array functions, moved from kern/kern_conf.c 572 */ 573 struct cdevsw * 574 devsw(dev_t dev) 575 { 576 return(_devsw(dev)); 577 } 578 #endif 579 580 /* 581 * Convert a cdevsw template into the real thing, filling in fields the 582 * device left empty with appropriate defaults. 583 */ 584 void 585 compile_devsw(struct cdevsw *devsw) 586 { 587 static lwkt_port devsw_compat_port; 588 589 if (devsw_compat_port.mp_putport == NULL) 590 init_default_cdevsw_port(&devsw_compat_port); 591 592 if (devsw->old_open == NULL) 593 devsw->old_open = noopen; 594 if (devsw->old_close == NULL) 595 devsw->old_close = noclose; 596 if (devsw->old_read == NULL) 597 devsw->old_read = noread; 598 if (devsw->old_write == NULL) 599 devsw->old_write = nowrite; 600 if (devsw->old_ioctl == NULL) 601 devsw->old_ioctl = noioctl; 602 if (devsw->old_poll == NULL) 603 devsw->old_poll = nopoll; 604 if (devsw->old_mmap == NULL) 605 devsw->old_mmap = nommap; 606 if (devsw->old_strategy == NULL) 607 devsw->old_strategy = nostrategy; 608 if (devsw->old_dump == NULL) 609 devsw->old_dump = nodump; 610 if (devsw->old_psize == NULL) 611 devsw->old_psize = nopsize; 612 if (devsw->old_kqfilter == NULL) 613 devsw->old_kqfilter = nokqfilter; 614 615 if (devsw->d_port == NULL) 616 devsw->d_port = &devsw_compat_port; 617 } 618 619 /* 620 * Add a cdevsw entry 621 */ 622 int 623 cdevsw_add(struct cdevsw *newentry) 624 { 625 compile_devsw(newentry); 626 if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 627 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 628 newentry->d_name, newentry->d_maj); 629 return (EINVAL); 630 } 631 if (cdevsw[newentry->d_maj]) { 632 printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 633 newentry->d_name, cdevsw[newentry->d_maj]->d_name); 634 } 635 cdevsw[newentry->d_maj] = newentry; 636 return (0); 637 } 638 639 /* 640 * Add a cdevsw entry and override the port. 641 */ 642 lwkt_port_t 643 cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port) 644 { 645 int error; 646 647 if ((error = cdevsw_add(newentry)) == 0) 648 cdevport[newentry->d_maj] = port; 649 return(newentry->d_port); 650 } 651 652 lwkt_port_t 653 cdevsw_dev_override(dev_t dev, lwkt_port_t port) 654 { 655 struct cdevsw *csw; 656 657 KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW); 658 if ((csw = _devsw(dev)) != NULL) { 659 cdevport[major(dev)] = port; 660 return(csw->d_port); 661 } 662 return(NULL); 663 } 664 665 /* 666 * Remove a cdevsw entry 667 */ 668 int 669 cdevsw_remove(struct cdevsw *oldentry) 670 { 671 if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 672 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 673 oldentry->d_name, oldentry->d_maj); 674 return EINVAL; 675 } 676 cdevsw[oldentry->d_maj] = NULL; 677 cdevport[oldentry->d_maj] = NULL; 678 return 0; 679 } 680 681