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,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
28 * $DragonFly: src/sys/kern/kern_device.c,v 1.7 2003/11/24 20:46:01 dillon Exp $
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>
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>
43 #include <sys/thread2.h>
44 #include <sys/msgport2.h>
46 static struct cdevsw *cdevsw[NUMCDEVSW];
47 static struct lwkt_port *cdevport[NUMCDEVSW];
49 static int cdevsw_putport(lwkt_port_t port, lwkt_msg_t msg);
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:
56 * mp_td is NULL: The d_autoq mask is ignored and all messages are translated
57 * into directly, synchronous cdevsw calls.
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.
62 * Don't worry too much about optimizing this code, the critical devices
63 * will implement their own port messaging functions directly.
66 init_default_cdevsw_port(lwkt_port_t port)
68 lwkt_initport(port, NULL);
69 port->mp_putport = cdevsw_putport;
74 cdevsw_putport(lwkt_port_t port, lwkt_msg_t lmsg)
76 cdevallmsg_t msg = (cdevallmsg_t)lmsg;
77 struct cdevsw *csw = msg->am_msg.csw;
81 * If queueable then officially queue the message
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));
90 * Run the device switch function synchronously in the context of the
91 * caller and return a synchronous error code (anything not EASYNC).
93 switch(msg->am_lmsg.ms_cmd) {
95 error = csw->old_open(
102 error = csw->old_close(
103 msg->am_close.msg.dev,
105 msg->am_close.devtype,
108 case CDEV_CMD_STRATEGY:
109 csw->old_strategy(msg->am_strategy.bp);
113 error = csw->old_ioctl(
114 msg->am_ioctl.msg.dev,
121 error = csw->old_dump(msg->am_ioctl.msg.dev);
124 msg->am_psize.result = csw->old_psize(msg->am_psize.msg.dev);
128 error = csw->old_read(
129 msg->am_read.msg.dev,
131 msg->am_read.ioflag);
134 error = csw->old_write(
135 msg->am_read.msg.dev,
137 msg->am_read.ioflag);
140 msg->am_poll.events = csw->old_poll(
141 msg->am_poll.msg.dev,
146 case CDEV_CMD_KQFILTER:
147 msg->am_kqfilter.result = csw->old_kqfilter(
148 msg->am_kqfilter.msg.dev,
149 msg->am_kqfilter.kn);
153 msg->am_mmap.result = csw->old_mmap(
154 msg->am_mmap.msg.dev,
163 KKASSERT(error != EASYNC);
168 * These device dispatch functions provide convenient entry points for
169 * any code wishing to make a dev call.
171 * YYY we ought to be able to optimize the port lookup by caching it in
172 * the dev_t structure itself.
181 return (dev->si_devsw);
182 return(cdevsw[major(dev)]);
187 _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)
191 lwkt_initmsg(&msg->msg, &curthread->td_msgport, cmd);
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)]);
204 dev_dopen(dev_t dev, int oflags, int devtype, thread_t td)
206 struct cdevmsg_open msg;
209 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
213 msg.devtype = devtype;
215 return(lwkt_domsg(port, &msg.msg.msg));
219 dev_dclose(dev_t dev, int fflag, int devtype, thread_t td)
221 struct cdevmsg_close msg;
224 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
228 msg.devtype = devtype;
230 return(lwkt_domsg(port, &msg.msg.msg));
234 dev_dstrategy(dev_t dev, struct buf *bp)
236 struct cdevmsg_strategy msg;
239 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
240 KKASSERT(port); /* 'nostrategy' function is NULL YYY */
242 lwkt_domsg(port, &msg.msg.msg);
246 dev_dioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
248 struct cdevmsg_ioctl msg;
251 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
258 return(lwkt_domsg(port, &msg.msg.msg));
264 struct cdevmsg_dump msg;
267 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
270 return(lwkt_domsg(port, &msg.msg.msg));
274 dev_dpsize(dev_t dev)
276 struct cdevmsg_psize msg;
280 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
283 error = lwkt_domsg(port, &msg.msg.msg);
290 dev_dread(dev_t dev, struct uio *uio, int ioflag)
292 struct cdevmsg_read msg;
295 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
300 return(lwkt_domsg(port, &msg.msg.msg));
304 dev_dwrite(dev_t dev, struct uio *uio, int ioflag)
306 struct cdevmsg_write msg;
309 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
314 return(lwkt_domsg(port, &msg.msg.msg));
318 dev_dpoll(dev_t dev, int events, thread_t td)
320 struct cdevmsg_poll msg;
324 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
329 error = lwkt_domsg(port, &msg.msg.msg);
332 return(seltrue(dev, msg.events, td));
336 dev_dkqfilter(dev_t dev, struct knote *kn)
338 struct cdevmsg_kqfilter msg;
342 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
346 error = lwkt_domsg(port, &msg.msg.msg);
353 dev_dmmap(dev_t dev, vm_offset_t offset, int nprot)
355 struct cdevmsg_mmap msg;
359 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
364 error = lwkt_domsg(port, &msg.msg.msg);
371 dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td)
373 struct cdevmsg_open msg;
375 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
379 msg.devtype = devtype;
381 return(lwkt_domsg(port, &msg.msg.msg));
385 dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td)
387 struct cdevmsg_close msg;
389 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
393 msg.devtype = devtype;
395 return(lwkt_domsg(port, &msg.msg.msg));
399 dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp)
401 struct cdevmsg_strategy msg;
403 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
404 KKASSERT(port); /* 'nostrategy' function is NULL YYY */
406 lwkt_domsg(port, &msg.msg.msg);
410 dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
412 struct cdevmsg_ioctl msg;
414 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
421 return(lwkt_domsg(port, &msg.msg.msg));
425 dev_port_ddump(lwkt_port_t port, dev_t dev)
427 struct cdevmsg_dump msg;
429 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
432 return(lwkt_domsg(port, &msg.msg.msg));
436 dev_port_dpsize(lwkt_port_t port, dev_t dev)
438 struct cdevmsg_psize msg;
441 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
444 error = lwkt_domsg(port, &msg.msg.msg);
451 dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
453 struct cdevmsg_read msg;
455 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
460 return(lwkt_domsg(port, &msg.msg.msg));
464 dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
466 struct cdevmsg_write msg;
468 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
473 return(lwkt_domsg(port, &msg.msg.msg));
477 dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td)
479 struct cdevmsg_poll msg;
482 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
487 error = lwkt_domsg(port, &msg.msg.msg);
490 return(seltrue(dev, msg.events, td));
494 dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn)
496 struct cdevmsg_kqfilter msg;
499 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
503 error = lwkt_domsg(port, &msg.msg.msg);
510 dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot)
512 struct cdevmsg_mmap msg;
515 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
520 error = lwkt_domsg(port, &msg.msg.msg);
531 if ((csw = _devsw(dev)) != NULL)
537 dev_dflags(dev_t dev)
541 if ((csw = _devsw(dev)) != NULL)
542 return(csw->d_flags);
551 if ((csw = _devsw(dev)) != NULL)
561 if ((csw = _devsw(dev)) != NULL) {
562 if (cdevport[major(dev)]) /* YYY too hackish */
563 return(cdevport[major(dev)]);
571 * cdevsw[] array functions, moved from kern/kern_conf.c
581 * Convert a cdevsw template into the real thing, filling in fields the
582 * device left empty with appropriate defaults.
585 compile_devsw(struct cdevsw *devsw)
587 static lwkt_port devsw_compat_port;
589 if (devsw_compat_port.mp_putport == NULL)
590 init_default_cdevsw_port(&devsw_compat_port);
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;
615 if (devsw->d_port == NULL)
616 devsw->d_port = &devsw_compat_port;
623 cdevsw_add(struct cdevsw *newentry)
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);
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);
635 cdevsw[newentry->d_maj] = newentry;
640 * Add a cdevsw entry and override the port.
643 cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port)
647 if ((error = cdevsw_add(newentry)) == 0)
648 cdevport[newentry->d_maj] = port;
649 return(newentry->d_port);
653 cdevsw_dev_override(dev_t dev, lwkt_port_t port)
657 KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW);
658 if ((csw = _devsw(dev)) != NULL) {
659 cdevport[major(dev)] = port;
666 * Remove a cdevsw entry
669 cdevsw_remove(struct cdevsw *oldentry)
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);
676 cdevsw[oldentry->d_maj] = NULL;
677 cdevport[oldentry->d_maj] = NULL;