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.2 2003/07/23 02:30:20 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_init_port(port, NULL);
69 port->mp_beginmsg = 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_putport(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 EINPROGRESS).
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 != EINPROGRESS);
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.
179 return (dev->si_devsw);
180 return(cdevsw[major(dev)]);
185 _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)
189 lwkt_initmsg(&msg->msg, cmd);
191 msg->csw = csw = _devsw(dev);
192 if (csw != NULL) { /* YYY too hackish */
193 KKASSERT(csw->d_port); /* YYY too hackish */
194 if (cdevport[major(dev)]) /* YYY too hackish */
195 return(cdevport[major(dev)]);
202 dev_dopen(dev_t dev, int oflags, int devtype, thread_t td)
204 struct cdevmsg_open msg;
207 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
211 msg.devtype = devtype;
213 return(lwkt_domsg(port, &msg.msg.msg));
217 dev_dclose(dev_t dev, int fflag, int devtype, thread_t td)
219 struct cdevmsg_close msg;
222 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
226 msg.devtype = devtype;
228 return(lwkt_domsg(port, &msg.msg.msg));
232 dev_dstrategy(dev_t dev, struct buf *bp)
234 struct cdevmsg_strategy msg;
237 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
238 KKASSERT(port); /* 'nostrategy' function is NULL YYY */
240 lwkt_domsg(port, &msg.msg.msg);
244 dev_dioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
246 struct cdevmsg_ioctl msg;
249 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
256 return(lwkt_domsg(port, &msg.msg.msg));
262 struct cdevmsg_dump msg;
265 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
268 return(lwkt_domsg(port, &msg.msg.msg));
272 dev_dpsize(dev_t dev)
274 struct cdevmsg_psize msg;
278 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
281 error = lwkt_domsg(port, &msg.msg.msg);
288 dev_dread(dev_t dev, struct uio *uio, int ioflag)
290 struct cdevmsg_read msg;
293 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
298 return(lwkt_domsg(port, &msg.msg.msg));
302 dev_dwrite(dev_t dev, struct uio *uio, int ioflag)
304 struct cdevmsg_write msg;
307 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
312 return(lwkt_domsg(port, &msg.msg.msg));
316 dev_dpoll(dev_t dev, int events, thread_t td)
318 struct cdevmsg_poll msg;
322 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
327 error = lwkt_domsg(port, &msg.msg.msg);
330 return(seltrue(dev, msg.events, td));
334 dev_dkqfilter(dev_t dev, struct knote *kn)
336 struct cdevmsg_kqfilter msg;
340 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
344 error = lwkt_domsg(port, &msg.msg.msg);
351 dev_dmmap(dev_t dev, vm_offset_t offset, int nprot)
353 struct cdevmsg_mmap msg;
357 port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
362 error = lwkt_domsg(port, &msg.msg.msg);
369 dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td)
371 struct cdevmsg_open msg;
373 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
377 msg.devtype = devtype;
379 return(lwkt_domsg(port, &msg.msg.msg));
383 dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td)
385 struct cdevmsg_close msg;
387 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
391 msg.devtype = devtype;
393 return(lwkt_domsg(port, &msg.msg.msg));
397 dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp)
399 struct cdevmsg_strategy msg;
401 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
402 KKASSERT(port); /* 'nostrategy' function is NULL YYY */
404 lwkt_domsg(port, &msg.msg.msg);
408 dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
410 struct cdevmsg_ioctl msg;
412 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
419 return(lwkt_domsg(port, &msg.msg.msg));
423 dev_port_ddump(lwkt_port_t port, dev_t dev)
425 struct cdevmsg_dump msg;
427 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
430 return(lwkt_domsg(port, &msg.msg.msg));
434 dev_port_dpsize(lwkt_port_t port, dev_t dev)
436 struct cdevmsg_psize msg;
439 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
442 error = lwkt_domsg(port, &msg.msg.msg);
449 dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
451 struct cdevmsg_read msg;
453 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
458 return(lwkt_domsg(port, &msg.msg.msg));
462 dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
464 struct cdevmsg_write msg;
466 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
471 return(lwkt_domsg(port, &msg.msg.msg));
475 dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td)
477 struct cdevmsg_poll msg;
480 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
485 error = lwkt_domsg(port, &msg.msg.msg);
488 return(seltrue(dev, msg.events, td));
492 dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn)
494 struct cdevmsg_kqfilter msg;
497 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
501 error = lwkt_domsg(port, &msg.msg.msg);
508 dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot)
510 struct cdevmsg_mmap msg;
513 _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
518 error = lwkt_domsg(port, &msg.msg.msg);
529 if ((csw = _devsw(dev)) != NULL)
535 dev_dflags(dev_t dev)
539 if ((csw = _devsw(dev)) != NULL)
540 return(csw->d_flags);
549 if ((csw = _devsw(dev)) != NULL)
559 if ((csw = _devsw(dev)) != NULL) {
560 if (cdevport[major(dev)]) /* YYY too hackish */
561 return(cdevport[major(dev)]);
569 * cdevsw[] array functions, moved from kern/kern_conf.c
579 * Convert a cdevsw template into the real thing, filling in fields the
580 * device left empty with appropriate defaults.
583 compile_devsw(struct cdevsw *devsw)
585 static lwkt_port devsw_compat_port;
587 if (devsw_compat_port.mp_beginmsg == NULL)
588 init_default_cdevsw_port(&devsw_compat_port);
590 if (devsw->old_open == NULL)
591 devsw->old_open = noopen;
592 if (devsw->old_close == NULL)
593 devsw->old_close = noclose;
594 if (devsw->old_read == NULL)
595 devsw->old_read = noread;
596 if (devsw->old_write == NULL)
597 devsw->old_write = nowrite;
598 if (devsw->old_ioctl == NULL)
599 devsw->old_ioctl = noioctl;
600 if (devsw->old_poll == NULL)
601 devsw->old_poll = nopoll;
602 if (devsw->old_mmap == NULL)
603 devsw->old_mmap = nommap;
604 if (devsw->old_strategy == NULL)
605 devsw->old_strategy = nostrategy;
606 if (devsw->old_dump == NULL)
607 devsw->old_dump = nodump;
608 if (devsw->old_psize == NULL)
609 devsw->old_psize = nopsize;
610 if (devsw->old_kqfilter == NULL)
611 devsw->old_kqfilter = nokqfilter;
613 if (devsw->d_port == NULL)
614 devsw->d_port = &devsw_compat_port;
621 cdevsw_add(struct cdevsw *newentry)
623 compile_devsw(newentry);
624 if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
625 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
626 newentry->d_name, newentry->d_maj);
629 if (cdevsw[newentry->d_maj]) {
630 printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
631 newentry->d_name, cdevsw[newentry->d_maj]->d_name);
633 cdevsw[newentry->d_maj] = newentry;
638 * Add a cdevsw entry and override the port.
641 cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port)
645 if ((error = cdevsw_add(newentry)) == 0)
646 cdevport[newentry->d_maj] = port;
647 return(newentry->d_port);
651 cdevsw_dev_override(dev_t dev, lwkt_port_t port)
655 KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW);
656 if ((csw = _devsw(dev)) != NULL) {
657 cdevport[major(dev)] = port;
664 * Remove a cdevsw entry
667 cdevsw_remove(struct cdevsw *oldentry)
669 if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
670 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
671 oldentry->d_name, oldentry->d_maj);
674 cdevsw[oldentry->d_maj] = NULL;
675 cdevport[oldentry->d_maj] = NULL;